diff options
Diffstat (limited to 'services/java/com/android/server/wm')
6 files changed, 682 insertions, 400 deletions
diff --git a/services/java/com/android/server/wm/DisplayContent.java b/services/java/com/android/server/wm/DisplayContent.java index 68cdbfc..59e4b0e 100644 --- a/services/java/com/android/server/wm/DisplayContent.java +++ b/services/java/com/android/server/wm/DisplayContent.java @@ -16,10 +16,8 @@ package com.android.server.wm; -import android.os.RemoteCallbackList; import android.view.Display; import android.view.DisplayInfo; -import android.view.IDisplayContentChangeListener; import java.io.PrintWriter; import java.util.ArrayList; @@ -43,12 +41,6 @@ class DisplayContent { * from mDisplayWindows; */ private WindowList mWindows = new WindowList(); - // Specification for magnifying the display content. - MagnificationSpec mMagnificationSpec; - - // Callback for observing content changes on a display. - RemoteCallbackList<IDisplayContentChangeListener> mDisplayContentChangeListeners; - // This protects the following display size properties, so that // getDisplaySize() doesn't need to acquire the global lock. This is // needed because the window manager sometimes needs to use ActivityThread @@ -128,9 +120,6 @@ class DisplayContent { pw.print("-"); pw.print(mDisplayInfo.largestNominalAppWidth); pw.print("x"); pw.println(mDisplayInfo.largestNominalAppHeight); pw.print(subPrefix); pw.print("layoutNeeded="); pw.print(layoutNeeded); - if (mMagnificationSpec != null) { - pw.print(" mMagnificationSpec="); pw.print(mMagnificationSpec); - } pw.println(); } } diff --git a/services/java/com/android/server/wm/DisplayMagnificationMediator.java b/services/java/com/android/server/wm/DisplayMagnificationMediator.java new file mode 100644 index 0000000..8621c5c --- /dev/null +++ b/services/java/com/android/server/wm/DisplayMagnificationMediator.java @@ -0,0 +1,616 @@ +package com.android.server.wm; + +import android.Manifest; +import android.content.Context; +import android.content.pm.PackageManager; +import android.graphics.Rect; +import android.graphics.Region; +import android.hardware.display.DisplayManager; +import android.hardware.display.DisplayManager.DisplayListener; +import android.os.Binder; +import android.os.Handler; +import android.os.IBinder; +import android.os.Message; +import android.os.Process; +import android.os.RemoteException; +import android.util.Slog; +import android.util.SparseArray; +import android.util.Pools.SynchronizedPool; +import android.view.DisplayInfo; +import android.view.IDisplayMagnificationController; +import android.view.IDisplayMagnificationMediator; +import android.view.MagnificationSpec; +import android.view.Surface; +import android.view.WindowManager; +import android.view.WindowManagerPolicy; + +import com.android.internal.os.SomeArgs; +import com.android.internal.policy.impl.PhoneWindowManager; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; + +final class DisplayMagnificationMediator extends IDisplayMagnificationMediator.Stub + implements DisplayListener { + private static final String LOG_TAG = DisplayMagnificationMediator.class.getSimpleName(); + + private static final boolean DEBUG_WINDOW_TRANSITIONS = false; + private static final boolean DEBUG_ROTATION = false; + private static final boolean DEBUG_LAYERS = false; + private static final boolean DEBUG_RECTANGLE_REQUESTED = false; + + private static final int MESSAGE_NOTIFY_MAGNIFIED_FRAME_CHANGED = 1; + private static final int MESSAGE_NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED = 2; + private static final int MESSAGE_NOTIFY_USER_CONTEXT_CHANGED = 3; + private static final int MESSAGE_NOTIFY_ROTATION_CHANGED = 4; + + private static final String METHOD_SIGNATURE_ADD_CONTROLLER = + "addController(int, IDisplayMagnificationController)"; + private static final String METHOD_SIGNATURE_REMOVE_CONTROLLER = + "removeController(IDisplayMagnificationController, int)"; + private static final String METHOD_SIGNATURE_SET_MAGNIFICATION_SPEC = + "setMagnificationSpec(IDisplayMagnificationController, MagnificationSpec)"; + + private final Rect mTempRect = new Rect(); + private final Rect mTempRect1 = new Rect(); + private final Region mTempRegion = new Region(); + + private final SparseArray<DisplayState> mDisplayStates = + new SparseArray<DisplayMagnificationMediator.DisplayState>(); + + private final Context mContext; + private final WindowManagerService mWindowManagerService; + + private final Handler mHandler = new Handler() { + @Override + public void handleMessage(Message message) { + switch (message.what) { + case MESSAGE_NOTIFY_MAGNIFIED_FRAME_CHANGED: { + SomeArgs args = (SomeArgs) message.obj; + IDisplayMagnificationController client = + (IDisplayMagnificationController) args.arg1; + final int left = args.argi1; + final int top = args.argi2; + final int right = args.argi3; + final int bottom = args.argi4; + try { + client.onMagnifedFrameChanged(left, top, right, bottom); + } catch (RemoteException re) { + /* ignore */ + } finally { + args.recycle(); + } + } break; + case MESSAGE_NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED: { + SomeArgs args = (SomeArgs) message.obj; + IDisplayMagnificationController client = + (IDisplayMagnificationController) args.arg1; + final int left = args.argi1; + final int top = args.argi2; + final int right = args.argi3; + final int bottom = args.argi4; + try { + client.onRectangleOnScreenRequested(left, top, right, bottom); + } catch (RemoteException re) { + /* ignore */ + } finally { + args.recycle(); + } + } break; + case MESSAGE_NOTIFY_USER_CONTEXT_CHANGED: { + IDisplayMagnificationController client = + (IDisplayMagnificationController) message.obj; + try { + client.onUserContextChanged(); + } catch (RemoteException re) { + /* ignore */ + } + } break; + case MESSAGE_NOTIFY_ROTATION_CHANGED: { + IDisplayMagnificationController client = + (IDisplayMagnificationController) message.obj; + final int rotation = message.arg1; + try { + client.onRotationChanged(rotation); + } catch (RemoteException re) { + /* ignore */ + } + } break; + } + } + }; + + public DisplayMagnificationMediator(WindowManagerService windowManagerService) { + mContext = windowManagerService.mContext; + mWindowManagerService = windowManagerService; + DisplayManager displayManager = (DisplayManager) + mContext.getSystemService(Context.DISPLAY_SERVICE); + displayManager.registerDisplayListener(this, mHandler); + } + + @Override + public void addController(int displayId, IDisplayMagnificationController controller) { + enforceCallingPermission(Manifest.permission.MAGNIFY_DISPLAY, + METHOD_SIGNATURE_ADD_CONTROLLER); + synchronized (mWindowManagerService.mWindowMap) { + DisplayState displayState = mDisplayStates.get(displayId); + if (displayState != null) { + displayState.clearLw(); + } + mDisplayStates.remove(displayId); + mDisplayStates.put(displayId, new DisplayState(displayId, controller)); + } + } + + @Override + public void removeController(IDisplayMagnificationController controller) { + enforceCallingPermission(Manifest.permission.MAGNIFY_DISPLAY, + METHOD_SIGNATURE_REMOVE_CONTROLLER); + synchronized (mWindowManagerService.mWindowMap) { + final int displayStateCount = mDisplayStates.size(); + for (int i = 0; i < displayStateCount; i++) { + DisplayState displayState = mDisplayStates.valueAt(i); + if (displayState.mClient.asBinder() == controller.asBinder()) { + displayState.clearLw(); + mDisplayStates.removeAt(i); + return; + } + } + } + } + + @Override + public void setMagnificationSpec(IDisplayMagnificationController controller, + MagnificationSpec spec) { + enforceCallingPermission(Manifest.permission.MAGNIFY_DISPLAY, + METHOD_SIGNATURE_SET_MAGNIFICATION_SPEC); + synchronized (mWindowManagerService.mWindowMap) { + DisplayState displayState = null; + final int displayStateCount = mDisplayStates.size(); + for (int i = 0; i < displayStateCount; i++) { + DisplayState candidate = mDisplayStates.valueAt(i); + if (candidate.mClient.asBinder() == controller.asBinder()) { + displayState = candidate; + break; + } + } + if (displayState == null) { + Slog.e(LOG_TAG, "Setting magnification spec for unregistered controller " + + controller); + return; + } + displayState.mMagnificationSpec.initialize(spec.scale, spec.offsetX, + spec.offsetY); + spec.recycle(); + } + synchronized (mWindowManagerService.mLayoutToAnim) { + mWindowManagerService.scheduleAnimationLocked(); + } + } + + @Override + public MagnificationSpec getCompatibleMagnificationSpec(IBinder windowToken) { + synchronized (mWindowManagerService.mWindowMap) { + WindowState windowState = mWindowManagerService.mWindowMap.get(windowToken); + if (windowState == null) { + return null; + } + MagnificationSpec spec = getMagnificationSpecLw(windowState); + if ((spec == null || spec.isNop()) && windowState.mGlobalScale == 1.0f) { + return null; + } + if (spec == null) { + spec = MagnificationSpec.obtain(); + } else { + spec = MagnificationSpec.obtain(spec); + } + spec.scale *= windowState.mGlobalScale; + return spec; + } + } + + @Override + public void onDisplayAdded(int displayId) { + /* do nothing */ + } + + @Override + public void onDisplayRemoved(int displayId) { + synchronized (mWindowManagerService.mWindowMap) { + DisplayState displayState = mDisplayStates.get(displayId); + if (displayState != null) { + displayState.clearLw(); + mDisplayStates.remove(displayId); + } + } + } + + @Override + public void onDisplayChanged(int displayId) { + /* do nothing */ + } + + public void onRectangleOnScreenRequestedLw(WindowState windowState, Rect rectangle, + boolean immediate) { + DisplayState displayState = mDisplayStates.get(windowState.getDisplayId()); + if (displayState == null) { + return; + } + if (DEBUG_RECTANGLE_REQUESTED) { + Slog.i(LOG_TAG, "Rectangle on screen requested: " + rectangle + + " displayId: " + windowState.getDisplayId()); + } + if (!displayState.isMagnifyingLw()) { + return; + } + Rect magnifiedRegionBounds = mTempRect1; + displayState.getMagnifiedFrameInContentCoordsLw(magnifiedRegionBounds); + if (magnifiedRegionBounds.contains(rectangle)) { + return; + } + SomeArgs args = SomeArgs.obtain(); + args.arg1 = displayState.mClient; + args.argi1 = rectangle.left; + args.argi2 = rectangle.top; + args.argi3 = rectangle.right; + args.argi4 = rectangle.bottom; + mHandler.obtainMessage(MESSAGE_NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED, + args).sendToTarget(); + } + + public void onWindowLayersChangedLw(int displayId) { + DisplayState displayState = mDisplayStates.get(displayId); + if (displayState == null) { + return; + } + if (DEBUG_LAYERS) { + Slog.i(LOG_TAG, "Layers changed displayId: " + displayId); + } + displayState.mViewport.recomputeBoundsLw(); + } + + public void onRotationChangedLw(int displayId, int rotation) { + DisplayState displayState = mDisplayStates.get(displayId); + if (displayState == null) { + return; + } + if (DEBUG_ROTATION) { + Slog.i(LOG_TAG, "Rotaton: " + Surface.rotationToString(rotation) + + " displayId: " + displayId); + } + displayState.mViewport.recomputeBoundsLw(); + mHandler.obtainMessage(MESSAGE_NOTIFY_ROTATION_CHANGED, rotation, 0, + displayState.mClient).sendToTarget(); + } + + public void onWindowTransitionLw(WindowState windowState, int transition) { + DisplayState displayState = mDisplayStates.get(windowState.getDisplayId()); + if (displayState == null) { + return; + } + if (DEBUG_WINDOW_TRANSITIONS) { + Slog.i(LOG_TAG, "Window transition: " + + PhoneWindowManager.windowTransitionToString(transition) + + " displayId: " + windowState.getDisplayId()); + } + final boolean magnifying = displayState.isMagnifyingLw(); + if (magnifying) { + switch (transition) { + case WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN: + case WindowManagerPolicy.TRANSIT_TASK_OPEN: + case WindowManagerPolicy.TRANSIT_TASK_TO_FRONT: + case WindowManagerPolicy.TRANSIT_WALLPAPER_OPEN: + case WindowManagerPolicy.TRANSIT_WALLPAPER_CLOSE: + case WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_OPEN: { + mHandler.obtainMessage(MESSAGE_NOTIFY_USER_CONTEXT_CHANGED, + displayState.mClient).sendToTarget(); + } + } + } + final int type = windowState.mAttrs.type; + if (type == WindowManager.LayoutParams.TYPE_NAVIGATION_BAR + || type == WindowManager.LayoutParams.TYPE_INPUT_METHOD + || type == WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG + || type == WindowManager.LayoutParams.TYPE_KEYGUARD + || type == WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG) { + switch (transition) { + case WindowManagerPolicy.TRANSIT_ENTER: + case WindowManagerPolicy.TRANSIT_SHOW: + case WindowManagerPolicy.TRANSIT_EXIT: + case WindowManagerPolicy.TRANSIT_HIDE: { + displayState.mViewport.recomputeBoundsLw(); + } break; + } + } + switch (transition) { + case WindowManagerPolicy.TRANSIT_ENTER: + case WindowManagerPolicy.TRANSIT_SHOW: { + if (!magnifying) { + break; + } + switch (type) { + case WindowManager.LayoutParams.TYPE_APPLICATION: + case WindowManager.LayoutParams.TYPE_APPLICATION_PANEL: + case WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA: + case WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL: + case WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG: + case WindowManager.LayoutParams.TYPE_SEARCH_BAR: + case WindowManager.LayoutParams.TYPE_PHONE: + case WindowManager.LayoutParams.TYPE_SYSTEM_ALERT: + case WindowManager.LayoutParams.TYPE_TOAST: + case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY: + case WindowManager.LayoutParams.TYPE_PRIORITY_PHONE: + case WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG: + case WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG: + case WindowManager.LayoutParams.TYPE_SYSTEM_ERROR: + case WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY: + case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL: + case WindowManager.LayoutParams.TYPE_RECENTS_OVERLAY: { + Rect magnifiedRegionBounds = mTempRect1; + displayState.getMagnifiedFrameInContentCoordsLw(magnifiedRegionBounds); + Rect touchableRegionBounds = mTempRect; + windowState.getTouchableRegion(mTempRegion); + mTempRegion.getBounds(touchableRegionBounds); + if (!magnifiedRegionBounds.intersect(touchableRegionBounds)) { + SomeArgs args = SomeArgs.obtain(); + args.arg1 = displayState.mClient; + args.argi1 = touchableRegionBounds.left; + args.argi2 = touchableRegionBounds.top; + args.argi3 = touchableRegionBounds.right; + args.argi4 = touchableRegionBounds.bottom; + mHandler.obtainMessage(MESSAGE_NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED, + args).sendToTarget(); + } + } break; + } break; + } + } + } + + public MagnificationSpec getMagnificationSpecLw(WindowState windowState) { + DisplayState displayState = mDisplayStates.get(windowState.getDisplayId()); + if (displayState == null) { + return null; + } + MagnificationSpec spec = displayState.mMagnificationSpec; + if (spec != null && !spec.isNop()) { + if (windowState.mAttachedWindow != null) { + if (!canMagnifyWindow(windowState.mAttachedWindow.mAttrs.type)) { + return null; + } + } + if (!canMagnifyWindow(windowState.mAttrs.type)) { + return null; + } + } + return spec; + } + + private void enforceCallingPermission(String permission, String function) { + if (Process.myPid() == Binder.getCallingPid()) { + return; + } + if (mContext.checkCallingPermission(permission) != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("The caller does not have " + permission + + " required to call " + function); + } + } + + private static boolean canMagnifyWindow(int type) { + switch (type) { + case WindowManager.LayoutParams.TYPE_INPUT_METHOD: + case WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG: + case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR: + case WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY: { + return false; + } + } + return true; + } + + private static final class Viewport { + + private final ArrayList<WindowStateInfo> mTempWindowStateInfoList = + new ArrayList<WindowStateInfo>(); + + private final Rect mTempRect1 = new Rect(); + private final Rect mTempRect2 = new Rect(); + private final Rect mTempRect3 = new Rect(); + + private final Rect mBounds = new Rect(); + private final Handler mHandler; + private final IDisplayMagnificationController mClient; + private final WindowManagerService mWindowManagerService; + private final DisplayInfo mDisplayInfo; + + private final int mDisplayId; + + public Viewport(Context context, int displayId, Handler handler, + IDisplayMagnificationController client, WindowManagerService windowManagerService) { + mDisplayId = displayId; + mHandler = handler; + mWindowManagerService = windowManagerService; + mDisplayInfo = mWindowManagerService.getDisplayContentLocked(displayId) + .getDisplayInfo(); + mClient = client; + recomputeBoundsLw(); + } + + private final Comparator<WindowStateInfo> mWindowInfoInverseComparator = + new Comparator<WindowStateInfo>() { + @Override + public int compare(WindowStateInfo lhs, WindowStateInfo rhs) { + if (lhs.mWindowState.mLayer != rhs.mWindowState.mLayer) { + return rhs.mWindowState.mLayer - lhs.mWindowState.mLayer; + } + if (lhs.mTouchableRegion.top != rhs.mTouchableRegion.top) { + return rhs.mTouchableRegion.top - lhs.mTouchableRegion.top; + } + if (lhs.mTouchableRegion.left != rhs.mTouchableRegion.left) { + return rhs.mTouchableRegion.left - lhs.mTouchableRegion.left; + } + if (lhs.mTouchableRegion.right != rhs.mTouchableRegion.right) { + return rhs.mTouchableRegion.right - lhs.mTouchableRegion.right; + } + if (lhs.mTouchableRegion.bottom != rhs.mTouchableRegion.bottom) { + return rhs.mTouchableRegion.bottom - lhs.mTouchableRegion.bottom; + } + return 0; + } + }; + + public void recomputeBoundsLw() { + Rect magnifiedFrame = mBounds; + magnifiedFrame.set(0, 0, 0, 0); + + Rect oldmagnifiedFrame = mTempRect3; + oldmagnifiedFrame.set(magnifiedFrame); + + Rect availableFrame = mTempRect1; + availableFrame.set(0, 0, mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight); + + ArrayList<WindowStateInfo> visibleWindows = mTempWindowStateInfoList; + visibleWindows.clear(); + getVisibleWindowsLw(visibleWindows); + + Collections.sort(visibleWindows, mWindowInfoInverseComparator); + + final int visibleWindowCount = visibleWindows.size(); + for (int i = 0; i < visibleWindowCount; i++) { + WindowStateInfo info = visibleWindows.get(i); + if (info.mWindowState.mAttrs.type == WindowManager + .LayoutParams.TYPE_MAGNIFICATION_OVERLAY) { + continue; + } + Rect windowFrame = mTempRect2; + windowFrame.set(info.mTouchableRegion); + if (canMagnifyWindow(info.mWindowState.mAttrs.type)) { + magnifiedFrame.union(windowFrame); + magnifiedFrame.intersect(availableFrame); + } else { + subtract(windowFrame, magnifiedFrame); + subtract(availableFrame, windowFrame); + } + if (availableFrame.equals(magnifiedFrame)) { + break; + } + } + for (int i = visibleWindowCount - 1; i >= 0; i--) { + visibleWindows.remove(i).recycle(); + } + + final int displayWidth = mDisplayInfo.logicalWidth; + final int displayHeight = mDisplayInfo.logicalHeight; + magnifiedFrame.intersect(0, 0, displayWidth, displayHeight); + + if (!oldmagnifiedFrame.equals(magnifiedFrame)) { + SomeArgs args = SomeArgs.obtain(); + args.arg1 = mClient; + args.argi1 = magnifiedFrame.left; + args.argi2 = magnifiedFrame.top; + args.argi3 = magnifiedFrame.right; + args.argi4 = magnifiedFrame.bottom; + mHandler.obtainMessage(MESSAGE_NOTIFY_MAGNIFIED_FRAME_CHANGED, args) + .sendToTarget(); + } + } + + private void getVisibleWindowsLw(ArrayList<WindowStateInfo> outWindowStates) { + DisplayContent displayContent = mWindowManagerService.getDisplayContentLocked( + mDisplayId); + WindowList windowList = displayContent.getWindowList(); + final int windowCount = windowList.size(); + for (int i = 0; i < windowCount; i++) { + WindowState windowState = windowList.get(i); + if (windowState.isVisibleLw() || windowState.mAttrs.type == WindowManager + .LayoutParams.TYPE_UNIVERSE_BACKGROUND) { + outWindowStates.add(WindowStateInfo.obtain(windowState)); + } + } + } + + public Rect getBoundsLw() { + return mBounds; + } + + private static boolean subtract(Rect lhs, Rect rhs) { + if (lhs.right < rhs.left || lhs.left > rhs.right + || lhs.bottom < rhs.top || lhs.top > rhs.bottom) { + return false; + } + if (lhs.left < rhs.left) { + lhs.right = rhs.left; + } + if (lhs.top < rhs.top) { + lhs.bottom = rhs.top; + } + if (lhs.right > rhs.right) { + lhs.left = rhs.right; + } + if (lhs.bottom > rhs.bottom) { + lhs.top = rhs.bottom; + } + return true; + } + + private static final class WindowStateInfo { + private static final int MAX_POOL_SIZE = 30; + + private static final SynchronizedPool<WindowStateInfo> sPool = + new SynchronizedPool<WindowStateInfo>(MAX_POOL_SIZE); + + private static final Region mTempRegion = new Region(); + + public WindowState mWindowState; + public final Rect mTouchableRegion = new Rect(); + + public static WindowStateInfo obtain(WindowState windowState) { + WindowStateInfo info = sPool.acquire(); + if (info == null) { + info = new WindowStateInfo(); + } + info.mWindowState = windowState; + windowState.getTouchableRegion(mTempRegion); + mTempRegion.getBounds(info.mTouchableRegion); + return info; + } + + public void recycle() { + mWindowState = null; + mTouchableRegion.setEmpty(); + sPool.release(this); + } + } + } + + private final class DisplayState { + final int mDisplayId; + final MagnificationSpec mMagnificationSpec; + final Viewport mViewport; + final IDisplayMagnificationController mClient; + + DisplayState(int displayId, IDisplayMagnificationController client) { + mDisplayId = displayId; + mClient = client; + mMagnificationSpec = MagnificationSpec.obtain(); + mViewport = new Viewport(mContext, mDisplayId, mHandler, + mClient, mWindowManagerService); + } + + public boolean isMagnifyingLw() { + return mMagnificationSpec.scale > 1.0f; + } + + private void getMagnifiedFrameInContentCoordsLw(Rect rect) { + MagnificationSpec spec = mMagnificationSpec; + rect.set(mViewport.getBoundsLw()); + rect.offset((int) -spec.offsetX, (int) -spec.offsetY); + rect.scale(1.0f / spec.scale); + } + + public void clearLw() { + mMagnificationSpec.recycle(); + } + } +} diff --git a/services/java/com/android/server/wm/MagnificationSpec.java b/services/java/com/android/server/wm/MagnificationSpec.java deleted file mode 100644 index 31aae66..0000000 --- a/services/java/com/android/server/wm/MagnificationSpec.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.wm; - -public class MagnificationSpec { - public float mScale = 1.0f; - public float mOffsetX; - public float mOffsetY; - - public void initialize(float scale, float offsetX, float offsetY) { - mScale = scale; - mOffsetX = offsetX; - mOffsetY = offsetY; - } - - public boolean isNop() { - return mScale == 1.0f && mOffsetX == 0 && mOffsetY == 0; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("<scale:"); - builder.append(mScale); - builder.append(",offsetX:"); - builder.append(mOffsetX); - builder.append(",offsetY:"); - builder.append(mOffsetY); - builder.append(">"); - return builder.toString(); - } -} diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index 69964e4..dc1121b 100644 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -91,7 +91,6 @@ import android.os.Parcel; import android.os.ParcelFileDescriptor; import android.os.PowerManager; import android.os.Process; -import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.ServiceManager; import android.os.StrictMode; @@ -114,7 +113,7 @@ import android.view.Display; import android.view.DisplayInfo; import android.view.Gravity; import android.view.IApplicationToken; -import android.view.IDisplayContentChangeListener; +import android.view.IDisplayMagnificationMediator; import android.view.IInputFilter; import android.view.IOnKeyguardExitResult; import android.view.IRotationWatcher; @@ -126,12 +125,12 @@ import android.view.InputDevice; import android.view.InputEvent; import android.view.InputEventReceiver; import android.view.KeyEvent; +import android.view.MagnificationSpec; import android.view.MotionEvent; import android.view.Surface; import android.view.SurfaceSession; import android.view.View; import android.view.ViewTreeObserver; -import android.view.WindowInfo; import android.view.WindowManager; import android.view.WindowManagerGlobal; import android.view.WindowManagerPolicy; @@ -424,6 +423,8 @@ public class WindowManagerService extends IWindowManager.Stub IInputMethodManager mInputMethodManager; + DisplayMagnificationMediator mMagnificationMediator; + final SurfaceSession mFxSession; Watermark mWatermark; StrictModeFlash mStrictModeFlash; @@ -2374,7 +2375,9 @@ public class WindowManagerService extends IWindowManager.Stub if (win.mWinAnimator.applyAnimationLocked(transit, false)) { win.mExiting = true; } - scheduleNotifyWindowTranstionIfNeededLocked(win, transit); + if (mMagnificationMediator != null) { + mMagnificationMediator.onWindowTransitionLw(win, transit); + } } if (win.mExiting || win.mWinAnimator.isAnimating()) { // The exit animation is running... wait for it! @@ -2666,49 +2669,13 @@ public class WindowManagerService extends IWindowManager.Stub public void onRectangleOnScreenRequested(IBinder token, Rect rectangle, boolean immediate) { synchronized (mWindowMap) { - WindowState window = mWindowMap.get(token); - if (window != null) { - scheduleNotifyRectangleOnScreenRequestedIfNeededLocked(window, rectangle, - immediate); - } - } - } - - private void scheduleNotifyRectangleOnScreenRequestedIfNeededLocked(WindowState window, - Rect rectangle, boolean immediate) { - DisplayContent displayContent = window.mDisplayContent; - if (displayContent.mDisplayContentChangeListeners != null - && displayContent.mDisplayContentChangeListeners.getRegisteredCallbackCount() > 0) { - mH.obtainMessage(H.NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED, displayContent.getDisplayId(), - immediate? 1 : 0, new Rect(rectangle)).sendToTarget(); - } - } - - private void handleNotifyRectangleOnScreenRequested(int displayId, Rect rectangle, - boolean immediate) { - RemoteCallbackList<IDisplayContentChangeListener> callbacks = null; - synchronized (mWindowMap) { - DisplayContent displayContent = getDisplayContentLocked(displayId); - if (displayContent == null) { - return; - } - callbacks = displayContent.mDisplayContentChangeListeners; - if (callbacks == null) { - return; - } - } - final int callbackCount = callbacks.beginBroadcast(); - try { - for (int i = 0; i < callbackCount; i++) { - try { - callbacks.getBroadcastItem(i).onRectangleOnScreenRequested(displayId, - rectangle, immediate); - } catch (RemoteException re) { - /* ignore */ + if (mMagnificationMediator != null) { + WindowState window = mWindowMap.get(token); + if (window != null) { + mMagnificationMediator.onRectangleOnScreenRequestedLw(window, rectangle, + immediate); } } - } finally { - callbacks.finishBroadcast(); } } @@ -2933,7 +2900,9 @@ public class WindowManagerService extends IWindowManager.Stub } winAnimator.destroySurfaceLocked(false); } - scheduleNotifyWindowTranstionIfNeededLocked(win, transit); + if (mMagnificationMediator != null) { + mMagnificationMediator.onWindowTransitionLw(win, transit); + } } } @@ -3072,106 +3041,31 @@ public class WindowManagerService extends IWindowManager.Stub } @Override - public float getWindowCompatibilityScale(IBinder windowToken) { - if (!checkCallingPermission(android.Manifest.permission.RETRIEVE_WINDOW_INFO, - "getWindowCompatibilityScale()")) { - throw new SecurityException("Requires RETRIEVE_WINDOW_INFO permission."); - } - synchronized (mWindowMap) { - WindowState windowState = mWindowMap.get(windowToken); - return (windowState != null) ? windowState.mGlobalScale : 1.0f; - } - } - - @Override - public WindowInfo getWindowInfo(IBinder token) { + public void getWindowFrame(IBinder token, Rect outBounds) { if (!checkCallingPermission(android.Manifest.permission.RETRIEVE_WINDOW_INFO, "getWindowInfo()")) { throw new SecurityException("Requires RETRIEVE_WINDOW_INFO permission."); } synchronized (mWindowMap) { - WindowState window = mWindowMap.get(token); - if (window != null) { - return getWindowInfoForWindowStateLocked(window); + WindowState windowState = mWindowMap.get(token); + if (windowState != null) { + outBounds.set(windowState.mFrame); + } else { + outBounds.setEmpty(); } - return null; } } @Override - public void getVisibleWindowsForDisplay(int displayId, List<WindowInfo> outInfos) { - if (!checkCallingPermission(android.Manifest.permission.RETRIEVE_WINDOW_INFO, - "getWindowInfos()")) { + public IDisplayMagnificationMediator getDisplayMagnificationMediator() { + if (!checkCallingPermission(android.Manifest.permission.MAGNIFY_DISPLAY, + "getDisplayMagnificationMediator()")) { throw new SecurityException("Requires RETRIEVE_WINDOW_INFO permission."); } - synchronized (mWindowMap) { - DisplayContent displayContent = getDisplayContentLocked(displayId); - if (displayContent == null) { - return; - } - WindowList windows = displayContent.getWindowList(); - final int windowCount = windows.size(); - for (int i = 0; i < windowCount; i++) { - WindowState window = windows.get(i); - if (window.isVisibleLw() || window.mAttrs.type == TYPE_UNIVERSE_BACKGROUND) { - WindowInfo info = getWindowInfoForWindowStateLocked(window); - outInfos.add(info); - } - } - } - } - - @Override - public void magnifyDisplay(int displayId, float scale, float offsetX, float offsetY) { - if (!checkCallingPermission( - android.Manifest.permission.MAGNIFY_DISPLAY, "magnifyDisplay()")) { - throw new SecurityException("Requires MAGNIFY_DISPLAY permission"); + if (mMagnificationMediator == null) { + mMagnificationMediator = new DisplayMagnificationMediator(this); } - synchronized (mWindowMap) { - MagnificationSpec spec = getDisplayMagnificationSpecLocked(displayId); - if (spec != null) { - final boolean scaleChanged = spec.mScale != scale; - final boolean offsetChanged = spec.mOffsetX != offsetX || spec.mOffsetY != offsetY; - if (!scaleChanged && !offsetChanged) { - return; - } - spec.initialize(scale, offsetX, offsetY); - // If the offset has changed we need to re-add the input windows - // since the offsets have to be propagated to the input system. - if (offsetChanged) { - // TODO(multidisplay): Input only occurs on the default display. - if (displayId == Display.DEFAULT_DISPLAY) { - mInputMonitor.updateInputWindowsLw(true); - } - } - scheduleAnimationLocked(); - } - } - } - - MagnificationSpec getDisplayMagnificationSpecLocked(int displayId) { - DisplayContent displayContent = getDisplayContentLocked(displayId); - if (displayContent != null) { - if (displayContent.mMagnificationSpec == null) { - displayContent.mMagnificationSpec = new MagnificationSpec(); - } - return displayContent.mMagnificationSpec; - } - return null; - } - - private WindowInfo getWindowInfoForWindowStateLocked(WindowState window) { - WindowInfo info = WindowInfo.obtain(); - info.token = window.mToken.token; - info.frame.set(window.mFrame); - info.type = window.mAttrs.type; - info.displayId = window.getDisplayId(); - info.compatibilityScale = window.mGlobalScale; - info.visible = window.isVisibleLw() || info.type == TYPE_UNIVERSE_BACKGROUND; - info.layer = window.mLayer; - window.getTouchableRegion(mTempRegion); - mTempRegion.getBounds(info.touchableRegion); - return info; + return mMagnificationMediator; } private boolean applyAnimationLocked(AppWindowToken atoken, @@ -3315,8 +3209,10 @@ public class WindowManagerService extends IWindowManager.Stub if (win.isVisibleNow()) { win.mWinAnimator.applyAnimationLocked(WindowManagerPolicy.TRANSIT_EXIT, false); - scheduleNotifyWindowTranstionIfNeededLocked(win, - WindowManagerPolicy.TRANSIT_EXIT); + if (mMagnificationMediator != null) { + mMagnificationMediator.onWindowTransitionLw(win, + WindowManagerPolicy.TRANSIT_EXIT); + } changed = true; win.mDisplayContent.layoutNeeded = true; } @@ -4071,8 +3967,8 @@ public class WindowManagerService extends IWindowManager.Stub delayed = runningAppAnimation = true; } WindowState window = wtoken.findMainWindow(); - if (window != null) { - scheduleNotifyWindowTranstionIfNeededLocked(window, transit); + if (window != null && mMagnificationMediator != null) { + mMagnificationMediator.onWindowTransitionLw(window, transit); } changed = true; } @@ -4091,8 +3987,10 @@ public class WindowManagerService extends IWindowManager.Stub if (!runningAppAnimation) { win.mWinAnimator.applyAnimationLocked( WindowManagerPolicy.TRANSIT_ENTER, true); - scheduleNotifyWindowTranstionIfNeededLocked(win, - WindowManagerPolicy.TRANSIT_ENTER); + if (mMagnificationMediator != null) { + mMagnificationMediator.onWindowTransitionLw(win, + WindowManagerPolicy.TRANSIT_ENTER); + } } changed = true; win.mDisplayContent.layoutNeeded = true; @@ -4101,8 +3999,10 @@ public class WindowManagerService extends IWindowManager.Stub if (!runningAppAnimation) { win.mWinAnimator.applyAnimationLocked( WindowManagerPolicy.TRANSIT_EXIT, false); - scheduleNotifyWindowTranstionIfNeededLocked(win, - WindowManagerPolicy.TRANSIT_EXIT); + if (mMagnificationMediator != null) { + mMagnificationMediator.onWindowTransitionLw(win, + WindowManagerPolicy.TRANSIT_EXIT); + } } changed = true; win.mDisplayContent.layoutNeeded = true; @@ -5727,7 +5627,9 @@ public class WindowManagerService extends IWindowManager.Stub } } - scheduleNotifyRotationChangedIfNeededLocked(displayContent, rotation); + if (mMagnificationMediator != null) { + mMagnificationMediator.onRotationChangedLw(Display.DEFAULT_DISPLAY, rotation); + } return true; } @@ -6109,146 +6011,6 @@ public class WindowManagerService extends IWindowManager.Stub return success; } - @Override - public void addDisplayContentChangeListener(int displayId, - IDisplayContentChangeListener listener) { - if (!checkCallingPermission(android.Manifest.permission.RETRIEVE_WINDOW_INFO, - "addDisplayContentChangeListener()")) { - throw new SecurityException("Requires RETRIEVE_WINDOW_INFO permission"); - } - synchronized(mWindowMap) { - DisplayContent displayContent = getDisplayContentLocked(displayId); - if (displayContent != null) { - if (displayContent.mDisplayContentChangeListeners == null) { - displayContent.mDisplayContentChangeListeners = - new RemoteCallbackList<IDisplayContentChangeListener>(); - displayContent.mDisplayContentChangeListeners.register(listener); - } - } - } - } - - @Override - public void removeDisplayContentChangeListener(int displayId, - IDisplayContentChangeListener listener) { - if (!checkCallingPermission(android.Manifest.permission.RETRIEVE_WINDOW_INFO, - "removeDisplayContentChangeListener()")) { - throw new SecurityException("Requires RETRIEVE_WINDOW_INFO permission"); - } - synchronized(mWindowMap) { - DisplayContent displayContent = getDisplayContentLocked(displayId); - if (displayContent != null) { - if (displayContent.mDisplayContentChangeListeners != null) { - displayContent.mDisplayContentChangeListeners.unregister(listener); - if (displayContent.mDisplayContentChangeListeners - .getRegisteredCallbackCount() == 0) { - displayContent.mDisplayContentChangeListeners = null; - } - } - } - } - } - - void scheduleNotifyWindowTranstionIfNeededLocked(WindowState window, int transition) { - DisplayContent displayContent = window.mDisplayContent; - if (displayContent.mDisplayContentChangeListeners != null) { - WindowInfo info = getWindowInfoForWindowStateLocked(window); - mH.obtainMessage(H.NOTIFY_WINDOW_TRANSITION, transition, 0, info).sendToTarget(); - } - } - - private void handleNotifyWindowTranstion(int transition, WindowInfo info) { - RemoteCallbackList<IDisplayContentChangeListener> callbacks = null; - synchronized (mWindowMap) { - DisplayContent displayContent = getDisplayContentLocked(info.displayId); - if (displayContent == null) { - return; - } - callbacks = displayContent.mDisplayContentChangeListeners; - if (callbacks == null) { - return; - } - } - final int callbackCount = callbacks.beginBroadcast(); - try { - for (int i = 0; i < callbackCount; i++) { - try { - callbacks.getBroadcastItem(i).onWindowTransition(info.displayId, - transition, info); - } catch (RemoteException re) { - /* ignore */ - } - } - } finally { - callbacks.finishBroadcast(); - } - } - - private void scheduleNotifyRotationChangedIfNeededLocked(DisplayContent displayContent, - int rotation) { - if (displayContent.mDisplayContentChangeListeners != null - && displayContent.mDisplayContentChangeListeners.getRegisteredCallbackCount() > 0) { - mH.obtainMessage(H.NOTIFY_ROTATION_CHANGED, displayContent.getDisplayId(), - rotation).sendToTarget(); - } - } - - private void handleNotifyRotationChanged(int displayId, int rotation) { - RemoteCallbackList<IDisplayContentChangeListener> callbacks = null; - synchronized (mWindowMap) { - DisplayContent displayContent = getDisplayContentLocked(displayId); - if (displayContent == null) { - return; - } - callbacks = displayContent.mDisplayContentChangeListeners; - if (callbacks == null) { - return; - } - } - try { - final int watcherCount = callbacks.beginBroadcast(); - for (int i = 0; i < watcherCount; i++) { - try { - callbacks.getBroadcastItem(i).onRotationChanged(rotation); - } catch (RemoteException re) { - /* ignore */ - } - } - } finally { - callbacks.finishBroadcast(); - } - } - - private void scheduleNotifyWindowLayersChangedIfNeededLocked(DisplayContent displayContent) { - if (displayContent.mDisplayContentChangeListeners != null - && displayContent.mDisplayContentChangeListeners.getRegisteredCallbackCount() > 0) { - mH.obtainMessage(H.NOTIFY_WINDOW_LAYERS_CHANGED, displayContent) .sendToTarget(); - } - } - - private void handleNotifyWindowLayersChanged(DisplayContent displayContent) { - RemoteCallbackList<IDisplayContentChangeListener> callbacks = null; - synchronized (mWindowMap) { - callbacks = displayContent.mDisplayContentChangeListeners; - if (callbacks == null) { - return; - } - } - try { - final int watcherCount = callbacks.beginBroadcast(); - for (int i = 0; i < watcherCount; i++) { - try { - callbacks.getBroadcastItem(i).onWindowLayersChanged( - displayContent.getDisplayId()); - } catch (RemoteException re) { - /* ignore */ - } - } - } finally { - callbacks.finishBroadcast(); - } - } - public void addWindowChangeListener(WindowChangeListener listener) { synchronized(mWindowMap) { mWindowChangeListeners.add(listener); @@ -6892,16 +6654,12 @@ public class WindowManagerService extends IWindowManager.Stub public static final int UPDATE_ANIM_PARAMETERS = 25; public static final int SHOW_STRICT_MODE_VIOLATION = 26; public static final int DO_ANIMATION_CALLBACK = 27; - public static final int NOTIFY_ROTATION_CHANGED = 28; - public static final int NOTIFY_WINDOW_TRANSITION = 29; - public static final int NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED = 30; - public static final int NOTIFY_WINDOW_LAYERS_CHANGED = 31; - public static final int DO_DISPLAY_ADDED = 32; - public static final int DO_DISPLAY_REMOVED = 33; - public static final int DO_DISPLAY_CHANGED = 34; + public static final int DO_DISPLAY_ADDED = 28; + public static final int DO_DISPLAY_REMOVED = 29; + public static final int DO_DISPLAY_CHANGED = 30; - public static final int CLIENT_FREEZE_TIMEOUT = 35; + public static final int CLIENT_FREEZE_TIMEOUT = 31; public static final int ANIMATOR_WHAT_OFFSET = 100000; public static final int SET_TRANSPARENT_REGION = ANIMATOR_WHAT_OFFSET + 1; @@ -7351,34 +7109,6 @@ public class WindowManagerService extends IWindowManager.Stub break; } - case NOTIFY_ROTATION_CHANGED: { - final int displayId = msg.arg1; - final int rotation = msg.arg2; - handleNotifyRotationChanged(displayId, rotation); - break; - } - - case NOTIFY_WINDOW_TRANSITION: { - final int transition = msg.arg1; - WindowInfo info = (WindowInfo) msg.obj; - handleNotifyWindowTranstion(transition, info); - break; - } - - case NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED: { - final int displayId = msg.arg1; - final boolean immediate = (msg.arg2 == 1); - Rect rectangle = (Rect) msg.obj; - handleNotifyRectangleOnScreenRequested(displayId, rectangle, immediate); - break; - } - - case NOTIFY_WINDOW_LAYERS_CHANGED: { - DisplayContent displayContent = (DisplayContent) msg.obj; - handleNotifyWindowLayersChanged(displayContent); - break; - } - case DO_DISPLAY_ADDED: synchronized (mWindowMap) { handleDisplayAddedLocked(msg.arg1); @@ -7823,8 +7553,9 @@ public class WindowManagerService extends IWindowManager.Stub // "Assigned layer " + curLayer + " to " + w.mClient.asBinder()); } - if (anyLayerChanged) { - scheduleNotifyWindowLayersChangedIfNeededLocked(getDefaultDisplayContentLocked()); + if (mMagnificationMediator != null && anyLayerChanged) { + mMagnificationMediator.onWindowLayersChangedLw( + windows.get(windows.size() - 1).getDisplayId()); } } diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java index 3b5b1eb..541e859 100644 --- a/services/java/com/android/server/wm/WindowState.java +++ b/services/java/com/android/server/wm/WindowState.java @@ -517,21 +517,6 @@ final class WindowState implements WindowManagerPolicy.WindowState { } } - MagnificationSpec getWindowMagnificationSpecLocked() { - MagnificationSpec spec = mDisplayContent.mMagnificationSpec; - if (spec != null && !spec.isNop()) { - if (mAttachedWindow != null) { - if (!mPolicy.canMagnifyWindowLw(mAttachedWindow.mAttrs)) { - return null; - } - } - if (!mPolicy.canMagnifyWindowLw(mAttrs)) { - return null; - } - } - return spec; - } - @Override public Rect getFrameLw() { return mFrame; diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/java/com/android/server/wm/WindowStateAnimator.java index 945c5e3..3c9424a 100644 --- a/services/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/java/com/android/server/wm/WindowStateAnimator.java @@ -16,6 +16,7 @@ import android.graphics.Region; import android.os.Debug; import android.util.Slog; import android.view.DisplayInfo; +import android.view.MagnificationSpec; import android.view.Surface; import android.view.SurfaceSession; import android.view.WindowManager; @@ -918,10 +919,13 @@ class WindowStateAnimator { if (screenAnimation) { tmpMatrix.postConcat(screenRotationAnimation.getEnterTransformation().getMatrix()); } - MagnificationSpec spec = mWin.getWindowMagnificationSpecLocked(); - if (spec != null && !spec.isNop()) { - tmpMatrix.postScale(spec.mScale, spec.mScale); - tmpMatrix.postTranslate(spec.mOffsetX, spec.mOffsetY); + if (mService.mMagnificationMediator != null) { + MagnificationSpec spec = mService.mMagnificationMediator + .getMagnificationSpecLw(mWin); + if (spec != null && !spec.isNop()) { + tmpMatrix.postScale(spec.scale, spec.scale); + tmpMatrix.postTranslate(spec.offsetX, spec.offsetY); + } } // "convert" it into SurfaceFlinger's format @@ -994,7 +998,8 @@ class WindowStateAnimator { final boolean applyUniverseTransformation = (mAnimator.mUniverseBackground != null && mWin.mAttrs.type != WindowManager.LayoutParams.TYPE_UNIVERSE_BACKGROUND && mWin.mBaseLayer < mAnimator.mAboveUniverseLayer); - MagnificationSpec spec = mWin.getWindowMagnificationSpecLocked(); + MagnificationSpec spec = (mService.mMagnificationMediator != null) + ? mService.mMagnificationMediator.getMagnificationSpecLw(mWin) : null; if (applyUniverseTransformation || spec != null) { final Rect frame = mWin.mFrame; final float tmpFloats[] = mService.mTmpFloats; @@ -1008,8 +1013,8 @@ class WindowStateAnimator { } if (spec != null && !spec.isNop()) { - tmpMatrix.postScale(spec.mScale, spec.mScale); - tmpMatrix.postTranslate(spec.mOffsetX, spec.mOffsetY); + tmpMatrix.postScale(spec.scale, spec.scale); + tmpMatrix.postTranslate(spec.offsetX, spec.offsetY); } tmpMatrix.getValues(tmpFloats); @@ -1494,7 +1499,9 @@ class WindowStateAnimator { transit = WindowManagerPolicy.TRANSIT_SHOW; } applyAnimationLocked(transit, true); - mService.scheduleNotifyWindowTranstionIfNeededLocked(mWin, transit); + if (mService.mMagnificationMediator != null) { + mService.mMagnificationMediator.onWindowTransitionLw(mWin, transit); + } } // TODO(cmautner): Move back to WindowState? |