diff options
Diffstat (limited to 'services/java')
9 files changed, 1250 insertions, 1320 deletions
diff --git a/services/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/java/com/android/server/accessibility/AccessibilityInputFilter.java index eb414fa..45da1e1 100644 --- a/services/java/com/android/server/accessibility/AccessibilityInputFilter.java +++ b/services/java/com/android/server/accessibility/AccessibilityInputFilter.java @@ -19,6 +19,7 @@ package com.android.server.accessibility; import android.content.Context; import android.os.PowerManager; import android.util.Slog; +import android.view.Display; import android.view.InputDevice; import android.view.InputEvent; import android.view.InputFilter; @@ -169,7 +170,8 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo private void enableFeatures() { if ((mEnabledFeatures & FLAG_FEATURE_SCREEN_MAGNIFIER) != 0) { - mEventHandler = mScreenMagnifier = new ScreenMagnifier(mContext); + mEventHandler = mScreenMagnifier = new ScreenMagnifier(mContext, + Display.DEFAULT_DISPLAY, mAms); mEventHandler.setNext(this); } if ((mEnabledFeatures & FLAG_FEATURE_TOUCH_EXPLORATION) != 0) { diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java index 65bfa7e..3e2540d 100644 --- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -65,12 +65,13 @@ import android.text.TextUtils.SimpleStringSplitter; import android.util.Slog; import android.util.SparseArray; import android.view.Display; +import android.view.IDisplayMagnificationMediator; import android.view.IWindow; import android.view.IWindowManager; import android.view.InputDevice; import android.view.KeyCharacterMap; import android.view.KeyEvent; -import android.view.WindowInfo; +import android.view.MagnificationSpec; import android.view.WindowManager; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityInteractionClient; @@ -158,6 +159,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { private final MainHandler mMainHandler; + private IDisplayMagnificationMediator mMagnificationMediator; + private Service mUiAutomationService; private Service mQueryBridge; @@ -621,6 +624,13 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { return false; } focus.getBoundsInScreen(outBounds); + + MagnificationSpec spec = service.getCompatibleMagnificationSpec(focus.getWindowId()); + if (spec != null && !spec.isNop()) { + outBounds.offset((int) -spec.offsetX, (int) -spec.offsetY); + outBounds.scale(1 / spec.scale); + } + // Clip to the window rectangle. Rect windowBounds = mTempRect; getActiveWindowBounds(windowBounds); @@ -628,6 +638,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { // Clip to the screen rectangle. mDefaultDisplay.getRealSize(mTempPoint); outBounds.intersect(0, 0, mTempPoint.x, mTempPoint.y); + return true; } finally { client.removeConnection(connectionId); @@ -648,19 +659,13 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { token = getCurrentUserStateLocked().mWindowTokens.get(windowId); } } - WindowInfo info = null; try { - info = mWindowManagerService.getWindowInfo(token); - if (info != null) { - outBounds.set(info.frame); + mWindowManagerService.getWindowFrame(token, outBounds); + if (!outBounds.isEmpty()) { return true; } } catch (RemoteException re) { /* ignore */ - } finally { - if (info != null) { - info.recycle(); - } } return false; } @@ -677,6 +682,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { mSecurityPolicy.onTouchInteractionEnd(); } + void onMagnificationStateChanged() { + notifyClearAccessibilityNodeInfoCacheLocked(); + } + private void switchUser(int userId) { synchronized (mLock) { // The user switched so we do not need to restore the current user @@ -762,6 +771,14 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { return false; } + private void notifyClearAccessibilityNodeInfoCacheLocked() { + UserState state = getCurrentUserStateLocked(); + for (int i = state.mServices.size() - 1; i >= 0; i--) { + Service service = state.mServices.get(i); + service.notifyClearAccessibilityNodeInfoCache(); + } + } + /** * Removes an AccessibilityInteractionConnection. * @@ -1438,9 +1455,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { class Service extends IAccessibilityServiceConnection.Stub implements ServiceConnection, DeathRecipient { - // We pick the MSB to avoid collision since accessibility event types are + // We pick the MSBs to avoid collision since accessibility event types are // used as message types allowing us to remove messages per event type. private static final int MSG_ON_GESTURE = 0x80000000; + private static final int MSG_CLEAR_ACCESSIBILITY_NODE_INFO_CACHE = 0x40000000; final int mUserId; @@ -1494,6 +1512,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { final int gestureId = message.arg1; notifyGestureInternal(gestureId); } break; + case MSG_CLEAR_ACCESSIBILITY_NODE_INFO_CACHE: { + notifyClearAccessibilityNodeInfoCacheInternal(); + } break; default: { final int eventType = type; notifyAccessibilityEventInternal(eventType); @@ -1636,7 +1657,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } @Override - public float findAccessibilityNodeInfoByViewId(int accessibilityWindowId, + public boolean findAccessibilityNodeInfoByViewId(int accessibilityWindowId, long accessibilityNodeId, int viewId, int interactionId, IAccessibilityInteractionConnectionCallback callback, long interrogatingTid) throws RemoteException { @@ -1647,17 +1668,17 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { .resolveCallingUserIdEnforcingPermissionsLocked( UserHandle.getCallingUserId()); if (resolvedUserId != mCurrentUserId) { - return -1; + return false; } mSecurityPolicy.enforceCanRetrieveWindowContent(this); final boolean permissionGranted = mSecurityPolicy.canRetrieveWindowContent(this); if (!permissionGranted) { - return 0; + return false; } else { resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId); connection = getConnectionLocked(resolvedWindowId); if (connection == null) { - return 0; + return false; } } } @@ -1665,10 +1686,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { AccessibilityNodeInfo.INCLUDE_NOT_IMPORTANT_VIEWS : 0; final int interrogatingPid = Binder.getCallingPid(); final long identityToken = Binder.clearCallingIdentity(); + MagnificationSpec spec = getCompatibleMagnificationSpec(resolvedWindowId); try { connection.findAccessibilityNodeInfoByViewId(accessibilityNodeId, viewId, - interactionId, callback, flags, interrogatingPid, interrogatingTid); - return getCompatibilityScale(resolvedWindowId); + interactionId, callback, flags, interrogatingPid, interrogatingTid, spec); + return true; } catch (RemoteException re) { if (DEBUG) { Slog.e(LOG_TAG, "Error findAccessibilityNodeInfoByViewId()."); @@ -1676,11 +1698,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } finally { Binder.restoreCallingIdentity(identityToken); } - return 0; + return false; } @Override - public float findAccessibilityNodeInfosByText(int accessibilityWindowId, + public boolean findAccessibilityNodeInfosByText(int accessibilityWindowId, long accessibilityNodeId, String text, int interactionId, IAccessibilityInteractionConnectionCallback callback, long interrogatingTid) throws RemoteException { @@ -1691,18 +1713,18 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { .resolveCallingUserIdEnforcingPermissionsLocked( UserHandle.getCallingUserId()); if (resolvedUserId != mCurrentUserId) { - return -1; + return false; } mSecurityPolicy.enforceCanRetrieveWindowContent(this); resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId); final boolean permissionGranted = mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId); if (!permissionGranted) { - return 0; + return false; } else { connection = getConnectionLocked(resolvedWindowId); if (connection == null) { - return 0; + return false; } } } @@ -1710,11 +1732,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { AccessibilityNodeInfo.INCLUDE_NOT_IMPORTANT_VIEWS : 0; final int interrogatingPid = Binder.getCallingPid(); final long identityToken = Binder.clearCallingIdentity(); + MagnificationSpec spec = getCompatibleMagnificationSpec(resolvedWindowId); try { connection.findAccessibilityNodeInfosByText(accessibilityNodeId, text, - interactionId, callback, flags, interrogatingPid, - interrogatingTid); - return getCompatibilityScale(resolvedWindowId); + interactionId, callback, flags, interrogatingPid, interrogatingTid, spec); + return true; } catch (RemoteException re) { if (DEBUG) { Slog.e(LOG_TAG, "Error calling findAccessibilityNodeInfosByText()"); @@ -1722,12 +1744,12 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } finally { Binder.restoreCallingIdentity(identityToken); } - return 0; + return false; } @Override - public float findAccessibilityNodeInfoByAccessibilityId(int accessibilityWindowId, - long accessibilityNodeId, int interactionId, + public boolean findAccessibilityNodeInfoByAccessibilityId( + int accessibilityWindowId, long accessibilityNodeId, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, long interrogatingTid) throws RemoteException { final int resolvedWindowId; @@ -1737,18 +1759,18 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { .resolveCallingUserIdEnforcingPermissionsLocked( UserHandle.getCallingUserId()); if (resolvedUserId != mCurrentUserId) { - return -1; + return false; } mSecurityPolicy.enforceCanRetrieveWindowContent(this); resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId); final boolean permissionGranted = mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId); if (!permissionGranted) { - return 0; + return false; } else { connection = getConnectionLocked(resolvedWindowId); if (connection == null) { - return 0; + return false; } } } @@ -1756,10 +1778,12 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { AccessibilityNodeInfo.INCLUDE_NOT_IMPORTANT_VIEWS : 0); final int interrogatingPid = Binder.getCallingPid(); final long identityToken = Binder.clearCallingIdentity(); + MagnificationSpec spec = getCompatibleMagnificationSpec(resolvedWindowId); try { connection.findAccessibilityNodeInfoByAccessibilityId(accessibilityNodeId, - interactionId, callback, allFlags, interrogatingPid, interrogatingTid); - return getCompatibilityScale(resolvedWindowId); + interactionId, callback, allFlags, interrogatingPid, interrogatingTid, + spec); + return true; } catch (RemoteException re) { if (DEBUG) { Slog.e(LOG_TAG, "Error calling findAccessibilityNodeInfoByAccessibilityId()"); @@ -1767,11 +1791,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } finally { Binder.restoreCallingIdentity(identityToken); } - return 0; + return false; } @Override - public float findFocus(int accessibilityWindowId, long accessibilityNodeId, + public boolean findFocus(int accessibilityWindowId, long accessibilityNodeId, int focusType, int interactionId, IAccessibilityInteractionConnectionCallback callback, long interrogatingTid) throws RemoteException { @@ -1782,18 +1806,18 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { .resolveCallingUserIdEnforcingPermissionsLocked( UserHandle.getCallingUserId()); if (resolvedUserId != mCurrentUserId) { - return -1; + return false; } mSecurityPolicy.enforceCanRetrieveWindowContent(this); resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId); final boolean permissionGranted = mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId); if (!permissionGranted) { - return 0; + return false; } else { connection = getConnectionLocked(resolvedWindowId); if (connection == null) { - return 0; + return false; } } } @@ -1801,10 +1825,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { AccessibilityNodeInfo.INCLUDE_NOT_IMPORTANT_VIEWS : 0; final int interrogatingPid = Binder.getCallingPid(); final long identityToken = Binder.clearCallingIdentity(); + MagnificationSpec spec = getCompatibleMagnificationSpec(resolvedWindowId); try { connection.findFocus(accessibilityNodeId, focusType, interactionId, callback, - flags, interrogatingPid, interrogatingTid); - return getCompatibilityScale(resolvedWindowId); + flags, interrogatingPid, interrogatingTid, spec); + return true; } catch (RemoteException re) { if (DEBUG) { Slog.e(LOG_TAG, "Error calling findAccessibilityFocus()"); @@ -1812,11 +1837,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } finally { Binder.restoreCallingIdentity(identityToken); } - return 0; + return false; } @Override - public float focusSearch(int accessibilityWindowId, long accessibilityNodeId, + public boolean focusSearch(int accessibilityWindowId, long accessibilityNodeId, int direction, int interactionId, IAccessibilityInteractionConnectionCallback callback, long interrogatingTid) throws RemoteException { @@ -1827,18 +1852,18 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { .resolveCallingUserIdEnforcingPermissionsLocked( UserHandle.getCallingUserId()); if (resolvedUserId != mCurrentUserId) { - return -1; + return false; } mSecurityPolicy.enforceCanRetrieveWindowContent(this); resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId); final boolean permissionGranted = mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId); if (!permissionGranted) { - return 0; + return false; } else { connection = getConnectionLocked(resolvedWindowId); if (connection == null) { - return 0; + return false; } } } @@ -1846,10 +1871,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { AccessibilityNodeInfo.INCLUDE_NOT_IMPORTANT_VIEWS : 0; final int interrogatingPid = Binder.getCallingPid(); final long identityToken = Binder.clearCallingIdentity(); + MagnificationSpec spec = getCompatibleMagnificationSpec(resolvedWindowId); try { connection.focusSearch(accessibilityNodeId, direction, interactionId, callback, - flags, interrogatingPid, interrogatingTid); - return getCompatibilityScale(resolvedWindowId); + flags, interrogatingPid, interrogatingTid, spec); + return true; } catch (RemoteException re) { if (DEBUG) { Slog.e(LOG_TAG, "Error calling accessibilityFocusSearch()"); @@ -1857,7 +1883,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } finally { Binder.restoreCallingIdentity(identityToken); } - return 0; + return false; } @Override @@ -2082,6 +2108,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { mHandler.obtainMessage(MSG_ON_GESTURE, gestureId, 0).sendToTarget(); } + public void notifyClearAccessibilityNodeInfoCache() { + mHandler.sendEmptyMessage(MSG_CLEAR_ACCESSIBILITY_NODE_INFO_CACHE); + } + private void notifyGestureInternal(int gestureId) { IAccessibilityServiceClient listener = mServiceInterface; if (listener != null) { @@ -2094,6 +2124,18 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } } + private void notifyClearAccessibilityNodeInfoCacheInternal() { + IAccessibilityServiceClient listener = mServiceInterface; + if (listener != null) { + try { + listener.clearAccessibilityNodeInfoCache(); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error during requesting accessibility info cache" + + " to be cleared.", re); + } + } + } + private void sendDownAndUpKeyEvents(int keyCode) { final long token = Binder.clearCallingIdentity(); @@ -2176,20 +2218,23 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { return accessibilityWindowId; } - private float getCompatibilityScale(int windowId) { + private MagnificationSpec getCompatibleMagnificationSpec(int windowId) { try { - IBinder windowToken = mGlobalWindowTokens.get(windowId); - if (windowToken != null) { - return mWindowManagerService.getWindowCompatibilityScale(windowToken); + if (mMagnificationMediator == null) { + mMagnificationMediator = mWindowManagerService + .getDisplayMagnificationMediator(); } - windowToken = getCurrentUserStateLocked().mWindowTokens.get(windowId); + IBinder windowToken = mGlobalWindowTokens.get(windowId); + if (windowToken == null) { + windowToken = getCurrentUserStateLocked().mWindowTokens.get(windowId); + } if (windowToken != null) { - return mWindowManagerService.getWindowCompatibilityScale(windowToken); + return mMagnificationMediator.getCompatibleMagnificationSpec(windowToken); } } catch (RemoteException re) { /* ignore */ } - return 1.0f; + return null; } } diff --git a/services/java/com/android/server/accessibility/ScreenMagnifier.java b/services/java/com/android/server/accessibility/ScreenMagnifier.java index 482bff5..e5f0924 100644 --- a/services/java/com/android/server/accessibility/ScreenMagnifier.java +++ b/services/java/com/android/server/accessibility/ScreenMagnifier.java @@ -21,6 +21,7 @@ import android.animation.Animator.AnimatorListener; import android.animation.ObjectAnimator; import android.animation.TypeEvaluator; import android.animation.ValueAnimator; +import android.app.Service; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -48,20 +49,19 @@ import android.view.DisplayInfo; import android.view.GestureDetector; import android.view.GestureDetector.SimpleOnGestureListener; import android.view.Gravity; -import android.view.IDisplayContentChangeListener; +import android.view.IDisplayMagnificationController; +import android.view.IDisplayMagnificationMediator; import android.view.IWindowManager; +import android.view.MagnificationSpec; import android.view.MotionEvent; import android.view.MotionEvent.PointerCoords; import android.view.MotionEvent.PointerProperties; import android.view.ScaleGestureDetector; import android.view.ScaleGestureDetector.OnScaleGestureListener; -import android.view.Surface; import android.view.View; import android.view.ViewConfiguration; import android.view.ViewGroup; -import android.view.WindowInfo; import android.view.WindowManager; -import android.view.WindowManagerPolicy; import android.view.accessibility.AccessibilityEvent; import android.view.animation.DecelerateInterpolator; import android.view.animation.Interpolator; @@ -69,9 +69,6 @@ import android.view.animation.Interpolator; import com.android.internal.R; import com.android.internal.os.SomeArgs; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; import java.util.Locale; /** @@ -91,7 +88,7 @@ import java.util.Locale; * moving finger will be magnified to fit the screen. For example, if the * screen was not magnified and the user triple taps and holds the screen * would magnify and the viewport will follow the user's finger. When the - * finger goes up the screen will clear zoom out. If the same user interaction + * finger goes up the screen will zoom out. If the same user interaction * is performed when the screen is magnified, the viewport movement will * be the same but when the finger goes up the screen will stay magnified. * In other words, the initial magnified state is sticky. @@ -106,26 +103,25 @@ import java.util.Locale; * to pan the viewport. Note that in this mode the content is panned as * opposed to the viewport dragging mode in which the viewport is moved. * - * 5. When in a permanent magnified state the user can use three or more + * 5. When in a permanent magnified state the user can use two or more * fingers to change the magnification scale which will become the current * default magnification scale. The next time the user magnifies the same * magnification scale would be used. * * 6. The magnification scale will be persisted in settings and in the cloud. */ -public final class ScreenMagnifier implements EventStreamTransformation { +public final class ScreenMagnifier extends IDisplayMagnificationController.Stub + implements EventStreamTransformation { + + private static final String LOG_TAG = ScreenMagnifier.class.getSimpleName(); private static final boolean DEBUG_STATE_TRANSITIONS = false; private static final boolean DEBUG_DETECTING = false; - private static final boolean DEBUG_TRANSFORMATION = false; + private static final boolean DEBUG_SET_MAGNIFICATION_SPEC = false; private static final boolean DEBUG_PANNING = false; private static final boolean DEBUG_SCALING = false; - private static final boolean DEBUG_VIEWPORT_WINDOW = false; - private static final boolean DEBUG_WINDOW_TRANSITIONS = false; - private static final boolean DEBUG_ROTATION = false; private static final boolean DEBUG_MAGNIFICATION_CONTROLLER = false; - - private static final String LOG_TAG = ScreenMagnifier.class.getSimpleName(); + private static final boolean DEBUG_VIEWPORT_WINDOW = false; private static final int STATE_DELEGATING = 1; private static final int STATE_DETECTING = 2; @@ -133,27 +129,30 @@ public final class ScreenMagnifier implements EventStreamTransformation { private static final int STATE_MAGNIFIED_INTERACTION = 4; private static final float DEFAULT_MAGNIFICATION_SCALE = 2.0f; - private static final int DEFAULT_SCREEN_MAGNIFICATION_AUTO_UPDATE = 1; - private static final float DEFAULT_WINDOW_ANIMATION_SCALE = 1.0f; - private static final int MULTI_TAP_TIME_SLOP_ADJUSTMENT = 50; - private final IWindowManager mWindowManagerService = IWindowManager.Stub.asInterface( - ServiceManager.getService("window")); - private final WindowManager mWindowManager; - private final DisplayProvider mDisplayProvider; + private static final int MESSAGE_ON_MAGNIFIED_FRAME_CHANGED = 1; + private static final int MESSAGE_ON_RECTANGLE_ON_SCREEN_REQUESTED = 2; + private static final int MESSAGE_ON_USER_CONTEXT_CHANGED = 3; + private static final int MESSAGE_ON_ROTATION_CHANGED = 4; + private static final int MESSAGE_SHOW_VIEWPORT_FRAME = 5; - private final DetectingStateHandler mDetectingStateHandler = new DetectingStateHandler(); - private final MagnifiedContentInteractonStateHandler mMagnifiedContentInteractonStateHandler; - private final StateViewportDraggingHandler mStateViewportDraggingHandler = - new StateViewportDraggingHandler(); + private static final int DEFAULT_SCREEN_MAGNIFICATION_AUTO_UPDATE = 1; + private static final float DEFAULT_WINDOW_ANIMATION_SCALE = 1.0f; - private final Interpolator mInterpolator = new DecelerateInterpolator(2.5f); + private final Rect mTempRect = new Rect(); + private final Rect mTempRect1 = new Rect(); + private final Context mContext; private final MagnificationController mMagnificationController; - private final DisplayContentObserver mDisplayContentObserver; private final ScreenStateObserver mScreenStateObserver; - private final Viewport mViewport; + private final ViewportWindow mViewportWindow; + + private final DetectingStateHandler mDetectingStateHandler; + private final MagnifiedContentInteractonStateHandler mMagnifiedContentInteractonStateHandler; + private final StateViewportDraggingHandler mStateViewportDraggingHandler; + + private final AccessibilityManagerService mAms; private final int mTapTimeSlop = ViewConfiguration.getTapTimeout(); private final int mMultiTapTimeSlop = @@ -161,11 +160,12 @@ public final class ScreenMagnifier implements EventStreamTransformation { private final int mTapDistanceSlop; private final int mMultiTapDistanceSlop; - private final int mShortAnimationDuration; - private final int mLongAnimationDuration; + private final long mLongAnimationDuration; private final float mWindowAnimationScale; - private final Context mContext; + private final Rect mMagnifiedFrame = new Rect(); + + private IDisplayMagnificationMediator mDisplayMagnifier; private EventStreamTransformation mNext; @@ -178,12 +178,46 @@ public final class ScreenMagnifier implements EventStreamTransformation { private long mDelegatingStateDownTime; - public ScreenMagnifier(Context context) { + private final Handler mHandler = new Handler() { + @Override + public void handleMessage(Message message) { + switch (message.what) { + case MESSAGE_ON_MAGNIFIED_FRAME_CHANGED: { + SomeArgs args = (SomeArgs) message.obj; + final int left = args.argi1; + final int top = args.argi2; + final int right = args.argi3; + final int bottom = args.argi4; + handleOnMagnifiedFrameChanged(left, top, right, bottom); + args.recycle(); + } break; + case MESSAGE_ON_RECTANGLE_ON_SCREEN_REQUESTED: { + SomeArgs args = (SomeArgs) message.obj; + final int left = args.argi1; + final int top = args.argi2; + final int right = args.argi3; + final int bottom = args.argi4; + handleOnRectangleOnScreenRequested(left, top, right, bottom); + args.recycle(); + } break; + case MESSAGE_ON_USER_CONTEXT_CHANGED: { + handleOnUserContextChanged(); + } break; + case MESSAGE_ON_ROTATION_CHANGED: { + final int rotation = message.arg1; + handleOnRotationChanged(rotation); + } break; + case MESSAGE_SHOW_VIEWPORT_FRAME: { + mViewportWindow.setShown(true, true); + } break; + } + } + }; + + public ScreenMagnifier(Context context, int displayId, AccessibilityManagerService service) { mContext = context; - mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + mAms = service; - mShortAnimationDuration = context.getResources().getInteger( - com.android.internal.R.integer.config_shortAnimTime); mLongAnimationDuration = context.getResources().getInteger( com.android.internal.R.integer.config_longAnimTime); mTapDistanceSlop = ViewConfiguration.get(context).getScaledTouchSlop(); @@ -191,23 +225,132 @@ public final class ScreenMagnifier implements EventStreamTransformation { mWindowAnimationScale = Settings.Global.getFloat(context.getContentResolver(), Settings.Global.WINDOW_ANIMATION_SCALE, DEFAULT_WINDOW_ANIMATION_SCALE); - mMagnificationController = new MagnificationController(mShortAnimationDuration); - mDisplayProvider = new DisplayProvider(context, mWindowManager); - mViewport = new Viewport(mContext, mWindowManager, mWindowManagerService, - mDisplayProvider, mInterpolator, mShortAnimationDuration); - mDisplayContentObserver = new DisplayContentObserver(mContext, mViewport, - mMagnificationController, mWindowManagerService, mDisplayProvider, - mLongAnimationDuration, mWindowAnimationScale); - mScreenStateObserver = new ScreenStateObserver(mContext, mViewport, - mMagnificationController); - + mDetectingStateHandler = new DetectingStateHandler(); + mStateViewportDraggingHandler = new StateViewportDraggingHandler(); mMagnifiedContentInteractonStateHandler = new MagnifiedContentInteractonStateHandler( context); + mMagnificationController = new MagnificationController(mLongAnimationDuration); + mViewportWindow = new ViewportWindow(context, displayId); + mScreenStateObserver = new ScreenStateObserver(context, mMagnificationController, + mViewportWindow); + + try { + IWindowManager windowManagerService = IWindowManager.Stub.asInterface( + ServiceManager.getService("window")); + mDisplayMagnifier = windowManagerService.getDisplayMagnificationMediator(); + mDisplayMagnifier.addController(Display.DEFAULT_DISPLAY, this); + } catch (RemoteException re) { + /* ignore */ + } + transitionToState(STATE_DETECTING); } @Override + public void onMagnifedFrameChanged(int left, int top, int right, int bottom) { + SomeArgs args = SomeArgs.obtain(); + args.argi1 = left; + args.argi2 = top; + args.argi3 = right; + args.argi4 = bottom; + mHandler.obtainMessage(MESSAGE_ON_MAGNIFIED_FRAME_CHANGED, args).sendToTarget(); + } + + private void handleOnMagnifiedFrameChanged(int left, int top, int right, int bottom) { + mMagnifiedFrame.set(left, top, right, bottom); + mViewportWindow.setBounds(mMagnifiedFrame, mMagnificationController.isMagnifying()); + mAms.onMagnificationStateChanged(); + } + + @Override + public void onRectangleOnScreenRequested(int left, int top, int right, int bottom) { + SomeArgs args = SomeArgs.obtain(); + args.argi1 = left; + args.argi2 = top; + args.argi3 = right; + args.argi4 = bottom; + mHandler.obtainMessage(MESSAGE_ON_RECTANGLE_ON_SCREEN_REQUESTED, args).sendToTarget(); + } + + private void handleOnRectangleOnScreenRequested(int left, int top, int right, int bottom) { + Rect rectangle = mTempRect; + rectangle.set(left, top, right, bottom); + if (!Rect.intersects(rectangle, mMagnifiedFrame)) { + return; + } + Rect magnifFrameInScreenCoords = mTempRect1; + getMagnifiedFrameInContentCoords(magnifFrameInScreenCoords); + final float scrollX; + final float scrollY; + if (rectangle.width() > magnifFrameInScreenCoords.width()) { + final int direction = TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()); + if (direction == View.LAYOUT_DIRECTION_LTR) { + scrollX = rectangle.left - magnifFrameInScreenCoords.left; + } else { + scrollX = rectangle.right - magnifFrameInScreenCoords.right; + } + } else if (rectangle.left < magnifFrameInScreenCoords.left) { + scrollX = rectangle.left - magnifFrameInScreenCoords.left; + } else if (rectangle.right > magnifFrameInScreenCoords.right) { + scrollX = rectangle.right - magnifFrameInScreenCoords.right; + } else { + scrollX = 0; + } + if (rectangle.height() > magnifFrameInScreenCoords.height()) { + scrollY = rectangle.top - magnifFrameInScreenCoords.top; + } else if (rectangle.top < magnifFrameInScreenCoords.top) { + scrollY = rectangle.top - magnifFrameInScreenCoords.top; + } else if (rectangle.bottom > magnifFrameInScreenCoords.bottom) { + scrollY = rectangle.bottom - magnifFrameInScreenCoords.bottom; + } else { + scrollY = 0; + } + final float scale = mMagnificationController.getScale(); + mMagnificationController.offsetMagnifiedRegionCenter(scrollX * scale, scrollY * scale); + } + + private void getMagnifiedFrameInContentCoords(Rect rect) { + MagnificationSpec spec = mMagnificationController.getMagnificationSpec(); + rect.set(mMagnifiedFrame); + rect.offset((int) -spec.offsetX, (int) -spec.offsetY); + rect.scale(1.0f / spec.scale); + } + + @Override + public void onRotationChanged(int rotation) { + mHandler.obtainMessage(MESSAGE_ON_ROTATION_CHANGED, rotation, 0).sendToTarget(); + } + + private void handleOnRotationChanged(int rotation) { + resetMagnificationIfNeeded(); + mViewportWindow.setShown(false, false); + mViewportWindow.rotationChanged(); + if (mMagnificationController.isMagnifying()) { + final long delay = (long) (2 * mLongAnimationDuration * mWindowAnimationScale); + Message message = mHandler.obtainMessage(MESSAGE_SHOW_VIEWPORT_FRAME); + mHandler.sendMessageDelayed(message, delay); + } + } + + @Override + public void onUserContextChanged() { + mHandler.sendEmptyMessage(MESSAGE_ON_USER_CONTEXT_CHANGED); + } + + private void handleOnUserContextChanged() { + resetMagnificationIfNeeded(); + } + + private void resetMagnificationIfNeeded() { + if (mMagnificationController.isMagnifying() + && isScreenMagnificationAutoUpdateEnabled(mContext)) { + mMagnificationController.reset(true); + mViewportWindow.setShown(false, true); + } + } + + @Override public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) { mMagnifiedContentInteractonStateHandler.onMotionEvent(event); @@ -257,12 +400,8 @@ public final class ScreenMagnifier implements EventStreamTransformation { @Override public void onDestroy() { - mMagnificationController.setScaleAndMagnifiedRegionCenter(1.0f, - 0, 0, true); - mViewport.setFrameShown(false, true); - mDisplayProvider.destroy(); - mDisplayContentObserver.destroy(); mScreenStateObserver.destroy(); + mViewportWindow.destroy(); } private void handleMotionEventStateDelegating(MotionEvent event, @@ -284,10 +423,10 @@ public final class ScreenMagnifier implements EventStreamTransformation { final float eventX = event.getX(); final float eventY = event.getY(); if (mMagnificationController.isMagnifying() - && mViewport.getBounds().contains((int) eventX, (int) eventY)) { + && mMagnifiedFrame.contains((int) eventX, (int) eventY)) { final float scale = mMagnificationController.getScale(); - final float scaledOffsetX = mMagnificationController.getScaledOffsetX(); - final float scaledOffsetY = mMagnificationController.getScaledOffsetY(); + final float scaledOffsetX = mMagnificationController.getOffsetX(); + final float scaledOffsetY = mMagnificationController.getOffsetY(); final int pointerCount = event.getPointerCount(); PointerCoords[] coords = getTempPointerCoordsWithMinSize(pointerCount); PointerProperties[] properties = getTempPointerPropertiesWithMinSize(pointerCount); @@ -412,16 +551,11 @@ public final class ScreenMagnifier implements EventStreamTransformation { if (mCurrentState != STATE_MAGNIFIED_INTERACTION) { return true; } - final float scale = mMagnificationController.getScale(); - final float scrollX = distanceX / scale; - final float scrollY = distanceY / scale; - final float centerX = mMagnificationController.getMagnifiedRegionCenterX() + scrollX; - final float centerY = mMagnificationController.getMagnifiedRegionCenterY() + scrollY; if (DEBUG_PANNING) { - Slog.i(LOG_TAG, "Panned content by scrollX: " + scrollX - + " scrollY: " + scrollY); + Slog.i(LOG_TAG, "Panned content by scrollX: " + distanceX + + " scrollY: " + distanceY); } - mMagnificationController.setMagnifiedRegionCenter(centerX, centerY, false); + mMagnificationController.offsetMagnifiedRegionCenter(distanceX, distanceY); return true; } @@ -485,7 +619,7 @@ public final class ScreenMagnifier implements EventStreamTransformation { } final float eventX = event.getX(); final float eventY = event.getY(); - if (mViewport.getBounds().contains((int) eventX, (int) eventY)) { + if (mMagnifiedFrame.contains((int) eventX, (int) eventY)) { if (mLastMoveOutsideMagnifiedRegion) { mLastMoveOutsideMagnifiedRegion = false; mMagnificationController.setMagnifiedRegionCenter(eventX, @@ -501,7 +635,7 @@ public final class ScreenMagnifier implements EventStreamTransformation { case MotionEvent.ACTION_UP: { if (!mTranslationEnabledBeforePan) { mMagnificationController.reset(true); - mViewport.setFrameShown(false, true); + mViewportWindow.setShown(false, true); } clear(); transitionToState(STATE_DETECTING); @@ -559,7 +693,7 @@ public final class ScreenMagnifier implements EventStreamTransformation { switch (action) { case MotionEvent.ACTION_DOWN: { mHandler.removeMessages(MESSAGE_TRANSITION_TO_DELEGATING_STATE); - if (!mViewport.getBounds().contains((int) event.getX(), + if (!mMagnifiedFrame.contains((int) event.getX(), (int) event.getY())) { transitionToDelegatingStateAndClear(); return; @@ -601,7 +735,7 @@ public final class ScreenMagnifier implements EventStreamTransformation { return; } mHandler.removeMessages(MESSAGE_ON_ACTION_TAP_AND_HOLD); - if (!mViewport.getBounds().contains((int) event.getX(), (int) event.getY())) { + if (!mMagnifiedFrame.contains((int) event.getX(), (int) event.getY())) { transitionToDelegatingStateAndClear(); return; } @@ -727,10 +861,10 @@ public final class ScreenMagnifier implements EventStreamTransformation { if (!mMagnificationController.isMagnifying()) { mMagnificationController.setScaleAndMagnifiedRegionCenter(getPersistedScale(), up.getX(), up.getY(), true); - mViewport.setFrameShown(true, true); + mViewportWindow.setShown(true, true); } else { mMagnificationController.reset(true); - mViewport.setFrameShown(false, true); + mViewportWindow.setShown(false, true); } } @@ -742,7 +876,7 @@ public final class ScreenMagnifier implements EventStreamTransformation { mTranslationEnabledBeforePan = mMagnificationController.isMagnifying(); mMagnificationController.setScaleAndMagnifiedRegionCenter(getPersistedScale(), down.getX(), down.getY(), true); - mViewport.setFrameShown(true, true); + mViewportWindow.setShown(true, true); transitionToState(STATE_VIEWPORT_DRAGGING); } } @@ -837,443 +971,35 @@ public final class ScreenMagnifier implements EventStreamTransformation { } } - private static final class ScreenStateObserver extends BroadcastReceiver { - - private static final int MESSAGE_ON_SCREEN_STATE_CHANGE = 1; - - private final Handler mHandler = new Handler() { - @Override - public void handleMessage(Message message) { - switch (message.what) { - case MESSAGE_ON_SCREEN_STATE_CHANGE: { - String action = (String) message.obj; - handleOnScreenStateChange(action); - } break; - } - } - }; - - private final Context mContext; - private final Viewport mViewport; - private final MagnificationController mMagnificationController; - - public ScreenStateObserver(Context context, Viewport viewport, - MagnificationController magnificationController) { - mContext = context; - mViewport = viewport; - mMagnificationController = magnificationController; - mContext.registerReceiver(this, new IntentFilter(Intent.ACTION_SCREEN_OFF)); - } - - public void destroy() { - mContext.unregisterReceiver(this); - } - - @Override - public void onReceive(Context context, Intent intent) { - mHandler.obtainMessage(MESSAGE_ON_SCREEN_STATE_CHANGE, - intent.getAction()).sendToTarget(); - } - - private void handleOnScreenStateChange(String action) { - if (action.equals(Intent.ACTION_SCREEN_OFF) - && mMagnificationController.isMagnifying() - && isScreenMagnificationAutoUpdateEnabled(mContext)) { - mMagnificationController.reset(false); - mViewport.setFrameShown(false, false); - } - } - } - - private static final class DisplayContentObserver { - - private static final int MESSAGE_SHOW_VIEWPORT_FRAME = 1; - private static final int MESSAGE_ON_RECTANGLE_ON_SCREEN_REQUESTED = 3; - private static final int MESSAGE_ON_WINDOW_TRANSITION = 4; - private static final int MESSAGE_ON_ROTATION_CHANGED = 5; - private static final int MESSAGE_ON_WINDOW_LAYERS_CHANGED = 6; - - private final Handler mHandler = new MyHandler(); - - private final Rect mTempRect = new Rect(); - - private final IDisplayContentChangeListener mDisplayContentChangeListener; - - private final Context mContext; - private final Viewport mViewport; - private final MagnificationController mMagnificationController; - private final IWindowManager mWindowManagerService; - private final DisplayProvider mDisplayProvider; - private final long mLongAnimationDuration; - private final float mWindowAnimationScale; - - public DisplayContentObserver(Context context, Viewport viewport, - MagnificationController magnificationController, - IWindowManager windowManagerService, DisplayProvider displayProvider, - long longAnimationDuration, float windowAnimationScale) { - mContext = context; - mViewport = viewport; - mMagnificationController = magnificationController; - mWindowManagerService = windowManagerService; - mDisplayProvider = displayProvider; - mLongAnimationDuration = longAnimationDuration; - mWindowAnimationScale = windowAnimationScale; - - mDisplayContentChangeListener = new IDisplayContentChangeListener.Stub() { - @Override - public void onWindowTransition(int displayId, int transition, WindowInfo info) { - mHandler.obtainMessage(MESSAGE_ON_WINDOW_TRANSITION, - transition, 0, WindowInfo.obtain(info)).sendToTarget(); - } - - @Override - public void onRectangleOnScreenRequested(int dsiplayId, Rect rectangle, - boolean immediate) { - SomeArgs args = SomeArgs.obtain(); - args.argi1 = rectangle.left; - args.argi2 = rectangle.top; - args.argi3 = rectangle.right; - args.argi4 = rectangle.bottom; - mHandler.obtainMessage(MESSAGE_ON_RECTANGLE_ON_SCREEN_REQUESTED, 0, - immediate ? 1 : 0, args).sendToTarget(); - } - - @Override - public void onRotationChanged(int rotation) throws RemoteException { - mHandler.obtainMessage(MESSAGE_ON_ROTATION_CHANGED, rotation, 0) - .sendToTarget(); - } - - @Override - public void onWindowLayersChanged(int displayId) throws RemoteException { - mHandler.sendEmptyMessage(MESSAGE_ON_WINDOW_LAYERS_CHANGED); - } - }; - - try { - mWindowManagerService.addDisplayContentChangeListener( - mDisplayProvider.getDisplay().getDisplayId(), - mDisplayContentChangeListener); - } catch (RemoteException re) { - /* ignore */ - } - } - - public void destroy() { - try { - mWindowManagerService.removeDisplayContentChangeListener( - mDisplayProvider.getDisplay().getDisplayId(), - mDisplayContentChangeListener); - } catch (RemoteException re) { - /* ignore*/ - } - } - - private void handleOnRotationChanged(int rotation) { - if (DEBUG_ROTATION) { - Slog.i(LOG_TAG, "Rotation: " + rotationToString(rotation)); - } - resetMagnificationIfNeeded(); - mViewport.setFrameShown(false, false); - mViewport.rotationChanged(); - mViewport.recomputeBounds(false); - if (mMagnificationController.isMagnifying()) { - final long delay = (long) (2 * mLongAnimationDuration * mWindowAnimationScale); - Message message = mHandler.obtainMessage(MESSAGE_SHOW_VIEWPORT_FRAME); - mHandler.sendMessageDelayed(message, delay); - } - } - - private void handleOnWindowTransition(int transition, WindowInfo info) { - if (DEBUG_WINDOW_TRANSITIONS) { - Slog.i(LOG_TAG, "Window transitioning: " - + windowTransitionToString(transition)); - } - try { - final boolean magnifying = mMagnificationController.isMagnifying(); - 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: { - resetMagnificationIfNeeded(); - } - } - } - if (info.type == WindowManager.LayoutParams.TYPE_NAVIGATION_BAR - || info.type == WindowManager.LayoutParams.TYPE_INPUT_METHOD - || info.type == WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG - || info.type == WindowManager.LayoutParams.TYPE_KEYGUARD - || info.type == WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG) { - switch (transition) { - case WindowManagerPolicy.TRANSIT_ENTER: - case WindowManagerPolicy.TRANSIT_SHOW: - case WindowManagerPolicy.TRANSIT_EXIT: - case WindowManagerPolicy.TRANSIT_HIDE: { - mViewport.recomputeBounds(mMagnificationController.isMagnifying()); - } break; - } - } - switch (transition) { - case WindowManagerPolicy.TRANSIT_ENTER: - case WindowManagerPolicy.TRANSIT_SHOW: { - if (!magnifying || !isScreenMagnificationAutoUpdateEnabled(mContext)) { - break; - } - final int type = info.type; - switch (type) { - // TODO: Are these all the windows we want to make - // visible when they appear on the screen? - // Do we need to take some of them out? - 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 = mMagnificationController - .getMagnifiedRegionBounds(); - Rect touchableRegion = info.touchableRegion; - if (!magnifiedRegionBounds.intersect(touchableRegion)) { - ensureRectangleInMagnifiedRegionBounds( - magnifiedRegionBounds, touchableRegion); - } - } break; - } break; - } - } - } finally { - if (info != null) { - info.recycle(); - } - } - } - - private void handleOnRectangleOnScreenRequested(Rect rectangle, boolean immediate) { - if (!mMagnificationController.isMagnifying()) { - return; - } - Rect magnifiedRegionBounds = mMagnificationController.getMagnifiedRegionBounds(); - if (magnifiedRegionBounds.contains(rectangle)) { - return; - } - ensureRectangleInMagnifiedRegionBounds(magnifiedRegionBounds, rectangle); - } - - private void ensureRectangleInMagnifiedRegionBounds(Rect magnifiedRegionBounds, - Rect rectangle) { - if (!Rect.intersects(rectangle, mViewport.getBounds())) { - return; - } - final float scrollX; - final float scrollY; - if (rectangle.width() > magnifiedRegionBounds.width()) { - final int direction = TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()); - if (direction == View.LAYOUT_DIRECTION_LTR) { - scrollX = rectangle.left - magnifiedRegionBounds.left; - } else { - scrollX = rectangle.right - magnifiedRegionBounds.right; - } - } else if (rectangle.left < magnifiedRegionBounds.left) { - scrollX = rectangle.left - magnifiedRegionBounds.left; - } else if (rectangle.right > magnifiedRegionBounds.right) { - scrollX = rectangle.right - magnifiedRegionBounds.right; - } else { - scrollX = 0; - } - if (rectangle.height() > magnifiedRegionBounds.height()) { - scrollY = rectangle.top - magnifiedRegionBounds.top; - } else if (rectangle.top < magnifiedRegionBounds.top) { - scrollY = rectangle.top - magnifiedRegionBounds.top; - } else if (rectangle.bottom > magnifiedRegionBounds.bottom) { - scrollY = rectangle.bottom - magnifiedRegionBounds.bottom; - } else { - scrollY = 0; - } - final float viewportCenterX = mMagnificationController.getMagnifiedRegionCenterX() - + scrollX; - final float viewportCenterY = mMagnificationController.getMagnifiedRegionCenterY() - + scrollY; - mMagnificationController.setMagnifiedRegionCenter(viewportCenterX, viewportCenterY, - true); - } - - private void resetMagnificationIfNeeded() { - if (mMagnificationController.isMagnifying() - && isScreenMagnificationAutoUpdateEnabled(mContext)) { - mMagnificationController.reset(true); - mViewport.setFrameShown(false, true); - } - } - - private String windowTransitionToString(int transition) { - switch (transition) { - case WindowManagerPolicy.TRANSIT_UNSET: { - return "TRANSIT_UNSET"; - } - case WindowManagerPolicy.TRANSIT_NONE: { - return "TRANSIT_NONE"; - } - case WindowManagerPolicy.TRANSIT_ENTER: { - return "TRANSIT_ENTER"; - } - case WindowManagerPolicy.TRANSIT_EXIT: { - return "TRANSIT_EXIT"; - } - case WindowManagerPolicy.TRANSIT_SHOW: { - return "TRANSIT_SHOW"; - } - case WindowManagerPolicy.TRANSIT_EXIT_MASK: { - return "TRANSIT_EXIT_MASK"; - } - case WindowManagerPolicy.TRANSIT_PREVIEW_DONE: { - return "TRANSIT_PREVIEW_DONE"; - } - case WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN: { - return "TRANSIT_ACTIVITY_OPEN"; - } - case WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE: { - return "TRANSIT_ACTIVITY_CLOSE"; - } - case WindowManagerPolicy.TRANSIT_TASK_OPEN: { - return "TRANSIT_TASK_OPEN"; - } - case WindowManagerPolicy.TRANSIT_TASK_CLOSE: { - return "TRANSIT_TASK_CLOSE"; - } - case WindowManagerPolicy.TRANSIT_TASK_TO_FRONT: { - return "TRANSIT_TASK_TO_FRONT"; - } - case WindowManagerPolicy.TRANSIT_TASK_TO_BACK: { - return "TRANSIT_TASK_TO_BACK"; - } - case WindowManagerPolicy.TRANSIT_WALLPAPER_CLOSE: { - return "TRANSIT_WALLPAPER_CLOSE"; - } - case WindowManagerPolicy.TRANSIT_WALLPAPER_OPEN: { - return "TRANSIT_WALLPAPER_OPEN"; - } - case WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_OPEN: { - return "TRANSIT_WALLPAPER_INTRA_OPEN"; - } - case WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_CLOSE: { - return "TRANSIT_WALLPAPER_INTRA_CLOSE"; - } - default: { - return "<UNKNOWN>"; - } - } - } - - private String rotationToString(int rotation) { - switch (rotation) { - case Surface.ROTATION_0: { - return "ROTATION_0"; - } - case Surface.ROTATION_90: { - return "ROATATION_90"; - } - case Surface.ROTATION_180: { - return "ROATATION_180"; - } - case Surface.ROTATION_270: { - return "ROATATION_270"; - } - default: { - throw new IllegalArgumentException("Invalid rotation: " - + rotation); - } - } - } - - private final class MyHandler extends Handler { - @Override - public void handleMessage(Message message) { - final int action = message.what; - switch (action) { - case MESSAGE_SHOW_VIEWPORT_FRAME: { - mViewport.setFrameShown(true, true); - } break; - case MESSAGE_ON_RECTANGLE_ON_SCREEN_REQUESTED: { - SomeArgs args = (SomeArgs) message.obj; - try { - mTempRect.set(args.argi1, args.argi2, args.argi3, args.argi4); - final boolean immediate = (message.arg1 == 1); - handleOnRectangleOnScreenRequested(mTempRect, immediate); - } finally { - args.recycle(); - } - } break; - case MESSAGE_ON_WINDOW_TRANSITION: { - final int transition = message.arg1; - WindowInfo info = (WindowInfo) message.obj; - handleOnWindowTransition(transition, info); - } break; - case MESSAGE_ON_ROTATION_CHANGED: { - final int rotation = message.arg1; - handleOnRotationChanged(rotation); - } break; - case MESSAGE_ON_WINDOW_LAYERS_CHANGED: { - mViewport.recomputeBounds(mMagnificationController.isMagnifying()); - } break; - default: { - throw new IllegalArgumentException("Unknown message: " + action); - } - } - } - } - } - private final class MagnificationController { - private static final String PROPERTY_NAME_ACCESSIBILITY_TRANSFORMATION = - "accessibilityTransformation"; + private static final String PROPERTY_NAME_MAGNIFICATION_SPEC = + "magnificationSpec"; - private final MagnificationSpec mSentMagnificationSpec = new MagnificationSpec(); + private final MagnificationSpec mSentMagnificationSpec = MagnificationSpec.obtain(); - private final MagnificationSpec mCurrentMagnificationSpec = new MagnificationSpec(); + private final MagnificationSpec mCurrentMagnificationSpec = MagnificationSpec.obtain(); private final Rect mTempRect = new Rect(); private final ValueAnimator mTransformationAnimator; - public MagnificationController(int animationDuration) { + public MagnificationController(long animationDuration) { Property<MagnificationController, MagnificationSpec> property = Property.of(MagnificationController.class, MagnificationSpec.class, - PROPERTY_NAME_ACCESSIBILITY_TRANSFORMATION); + PROPERTY_NAME_MAGNIFICATION_SPEC); TypeEvaluator<MagnificationSpec> evaluator = new TypeEvaluator<MagnificationSpec>() { - private final MagnificationSpec mTempTransformationSpec = new MagnificationSpec(); + private final MagnificationSpec mTempTransformationSpec = + MagnificationSpec.obtain(); @Override public MagnificationSpec evaluate(float fraction, MagnificationSpec fromSpec, MagnificationSpec toSpec) { MagnificationSpec result = mTempTransformationSpec; - result.mScale = fromSpec.mScale - + (toSpec.mScale - fromSpec.mScale) * fraction; - result.mMagnifiedRegionCenterX = fromSpec.mMagnifiedRegionCenterX - + (toSpec.mMagnifiedRegionCenterX - fromSpec.mMagnifiedRegionCenterX) - * fraction; - result.mMagnifiedRegionCenterY = fromSpec.mMagnifiedRegionCenterY - + (toSpec.mMagnifiedRegionCenterY - fromSpec.mMagnifiedRegionCenterY) - * fraction; - result.mScaledOffsetX = fromSpec.mScaledOffsetX - + (toSpec.mScaledOffsetX - fromSpec.mScaledOffsetX) + result.scale = fromSpec.scale + + (toSpec.scale - fromSpec.scale) * fraction; + result.offsetX = fromSpec.offsetX + (toSpec.offsetX - fromSpec.offsetX) * fraction; - result.mScaledOffsetY = fromSpec.mScaledOffsetY - + (toSpec.mScaledOffsetY - fromSpec.mScaledOffsetY) + result.offsetY = fromSpec.offsetY + (toSpec.offsetY - fromSpec.offsetY) * fraction; return result; } @@ -1281,61 +1007,48 @@ public final class ScreenMagnifier implements EventStreamTransformation { mTransformationAnimator = ObjectAnimator.ofObject(this, property, evaluator, mSentMagnificationSpec, mCurrentMagnificationSpec); mTransformationAnimator.setDuration((long) (animationDuration)); - mTransformationAnimator.setInterpolator(mInterpolator); + mTransformationAnimator.setInterpolator(new DecelerateInterpolator(2.5f)); } public boolean isMagnifying() { - return mCurrentMagnificationSpec.mScale > 1.0f; + return mCurrentMagnificationSpec.scale > 1.0f; } public void reset(boolean animate) { if (mTransformationAnimator.isRunning()) { mTransformationAnimator.cancel(); } - mCurrentMagnificationSpec.reset(); + mCurrentMagnificationSpec.clear(); if (animate) { - animateAccessibilityTranformation(mSentMagnificationSpec, + animateMangificationSpec(mSentMagnificationSpec, mCurrentMagnificationSpec); } else { - setAccessibilityTransformation(mCurrentMagnificationSpec); + setMagnificationSpec(mCurrentMagnificationSpec); } - } - - public Rect getMagnifiedRegionBounds() { - mTempRect.set(mViewport.getBounds()); - mTempRect.offset((int) -mCurrentMagnificationSpec.mScaledOffsetX, - (int) -mCurrentMagnificationSpec.mScaledOffsetY); - mTempRect.scale(1.0f / mCurrentMagnificationSpec.mScale); - return mTempRect; + Rect bounds = mTempRect; + bounds.setEmpty(); + mAms.onMagnificationStateChanged(); } public float getScale() { - return mCurrentMagnificationSpec.mScale; - } - - public float getMagnifiedRegionCenterX() { - return mCurrentMagnificationSpec.mMagnifiedRegionCenterX; - } - - public float getMagnifiedRegionCenterY() { - return mCurrentMagnificationSpec.mMagnifiedRegionCenterY; + return mCurrentMagnificationSpec.scale; } - public float getScaledOffsetX() { - return mCurrentMagnificationSpec.mScaledOffsetX; + public float getOffsetX() { + return mCurrentMagnificationSpec.offsetX; } - public float getScaledOffsetY() { - return mCurrentMagnificationSpec.mScaledOffsetY; + public float getOffsetY() { + return mCurrentMagnificationSpec.offsetY; } public void setScale(float scale, float pivotX, float pivotY, boolean animate) { MagnificationSpec spec = mCurrentMagnificationSpec; - final float oldScale = spec.mScale; - final float oldCenterX = spec.mMagnifiedRegionCenterX; - final float oldCenterY = spec.mMagnifiedRegionCenterY; - final float normPivotX = (-spec.mScaledOffsetX + pivotX) / oldScale; - final float normPivotY = (-spec.mScaledOffsetY + pivotY) / oldScale; + final float oldScale = spec.scale; + final float oldCenterX = (-spec.offsetX + mMagnifiedFrame.width() / 2) / oldScale; + final float oldCenterY = (-spec.offsetY + mMagnifiedFrame.height() / 2) / oldScale; + final float normPivotX = (-spec.offsetX + pivotX) / oldScale; + final float normPivotY = (-spec.offsetY + pivotY) / oldScale; final float offsetX = (oldCenterX - normPivotX) * (oldScale / scale); final float offsetY = (oldCenterY - normPivotY) * (oldScale / scale); final float centerX = normPivotX + offsetX; @@ -1344,16 +1057,26 @@ public final class ScreenMagnifier implements EventStreamTransformation { } public void setMagnifiedRegionCenter(float centerX, float centerY, boolean animate) { - setScaleAndMagnifiedRegionCenter(mCurrentMagnificationSpec.mScale, centerX, centerY, + setScaleAndMagnifiedRegionCenter(mCurrentMagnificationSpec.scale, centerX, centerY, animate); } + public void offsetMagnifiedRegionCenter(float offsetX, float offsetY) { + final float nonNormOffsetX = mCurrentMagnificationSpec.offsetX - offsetX; + mCurrentMagnificationSpec.offsetX = Math.min(Math.max(nonNormOffsetX, + getMinOffsetX()), 0); + final float nonNormOffsetY = mCurrentMagnificationSpec.offsetY - offsetY; + mCurrentMagnificationSpec.offsetY = Math.min(Math.max(nonNormOffsetY, + getMinOffsetY()), 0); + setMagnificationSpec(mCurrentMagnificationSpec); + } + public void setScaleAndMagnifiedRegionCenter(float scale, float centerX, float centerY, boolean animate) { - if (Float.compare(mCurrentMagnificationSpec.mScale, scale) == 0 - && Float.compare(mCurrentMagnificationSpec.mMagnifiedRegionCenterX, + if (Float.compare(mCurrentMagnificationSpec.scale, scale) == 0 + && Float.compare(mCurrentMagnificationSpec.offsetX, centerX) == 0 - && Float.compare(mCurrentMagnificationSpec.mMagnifiedRegionCenterY, + && Float.compare(mCurrentMagnificationSpec.offsetY, centerY) == 0) { return; } @@ -1361,149 +1084,192 @@ public final class ScreenMagnifier implements EventStreamTransformation { mTransformationAnimator.cancel(); } if (DEBUG_MAGNIFICATION_CONTROLLER) { - Slog.i(LOG_TAG, "scale: " + scale + " centerX: " + centerX - + " centerY: " + centerY); + Slog.i(LOG_TAG, "scale: " + scale + " offsetX: " + centerX + + " offsetY: " + centerY); } - mCurrentMagnificationSpec.initialize(scale, centerX, centerY); + updateMagnificationSpec(scale, centerX, centerY); if (animate) { - animateAccessibilityTranformation(mSentMagnificationSpec, + animateMangificationSpec(mSentMagnificationSpec, mCurrentMagnificationSpec); } else { - setAccessibilityTransformation(mCurrentMagnificationSpec); + setMagnificationSpec(mCurrentMagnificationSpec); } + mAms.onMagnificationStateChanged(); + } + + public void updateMagnificationSpec(float scale, float magnifiedCenterX, + float magnifiedCenterY) { + mCurrentMagnificationSpec.scale = scale; + final int viewportWidth = mMagnifiedFrame.width(); + final float nonNormOffsetX = viewportWidth / 2 - magnifiedCenterX * scale; + mCurrentMagnificationSpec.offsetX = Math.min(Math.max(nonNormOffsetX, + getMinOffsetX()), 0); + final int viewportHeight = mMagnifiedFrame.height(); + final float nonNormOffsetY = viewportHeight / 2 - magnifiedCenterY * scale; + mCurrentMagnificationSpec.offsetY = Math.min(Math.max(nonNormOffsetY, + getMinOffsetY()), 0); + } + + private float getMinOffsetX() { + final float viewportWidth = mMagnifiedFrame.width(); + return viewportWidth - viewportWidth * mCurrentMagnificationSpec.scale; } - private void animateAccessibilityTranformation(MagnificationSpec fromSpec, + private float getMinOffsetY() { + final float viewportHeight = mMagnifiedFrame.height(); + return viewportHeight - viewportHeight * mCurrentMagnificationSpec.scale; + } + + private void animateMangificationSpec(MagnificationSpec fromSpec, MagnificationSpec toSpec) { mTransformationAnimator.setObjectValues(fromSpec, toSpec); mTransformationAnimator.start(); } - @SuppressWarnings("unused") - // Called from an animator. - public MagnificationSpec getAccessibilityTransformation() { + public MagnificationSpec getMagnificationSpec() { return mSentMagnificationSpec; } - public void setAccessibilityTransformation(MagnificationSpec transformation) { - if (DEBUG_TRANSFORMATION) { - Slog.i(LOG_TAG, "Transformation scale: " + transformation.mScale - + " offsetX: " + transformation.mScaledOffsetX - + " offsetY: " + transformation.mScaledOffsetY); + public void setMagnificationSpec(MagnificationSpec spec) { + if (DEBUG_SET_MAGNIFICATION_SPEC) { + Slog.i(LOG_TAG, "Sending: " + spec); } try { - mSentMagnificationSpec.updateFrom(transformation); - mWindowManagerService.magnifyDisplay(mDisplayProvider.getDisplay().getDisplayId(), - transformation.mScale, transformation.mScaledOffsetX, - transformation.mScaledOffsetY); + mSentMagnificationSpec.scale = spec.scale; + mSentMagnificationSpec.offsetX = spec.offsetX; + mSentMagnificationSpec.offsetY = spec.offsetY; + mDisplayMagnifier.setMagnificationSpec(ScreenMagnifier.this, + MagnificationSpec.obtain(spec)); } catch (RemoteException re) { /* ignore */ } } + } - private class MagnificationSpec { - - private static final float DEFAULT_SCALE = 1.0f; - - public float mScale = DEFAULT_SCALE; - - public float mMagnifiedRegionCenterX; - - public float mMagnifiedRegionCenterY; - - public float mScaledOffsetX; - - public float mScaledOffsetY; + private static final class ScreenStateObserver extends BroadcastReceiver { + private static final int MESSAGE_ON_SCREEN_STATE_CHANGE = 1; - public void initialize(float scale, float magnifiedRegionCenterX, - float magnifiedRegionCenterY) { - mScale = scale; + private final Context mContext; + private final MagnificationController mMagnificationController; + private final ViewportWindow mViewportWindow; - final int viewportWidth = mViewport.getBounds().width(); - final int viewportHeight = mViewport.getBounds().height(); - final float minMagnifiedRegionCenterX = (viewportWidth / 2) / scale; - final float minMagnifiedRegionCenterY = (viewportHeight / 2) / scale; - final float maxMagnifiedRegionCenterX = viewportWidth - minMagnifiedRegionCenterX; - final float maxMagnifiedRegionCenterY = viewportHeight - minMagnifiedRegionCenterY; + private final Handler mHandler = new Handler() { + @Override + public void handleMessage(Message message) { + switch (message.what) { + case MESSAGE_ON_SCREEN_STATE_CHANGE: { + String action = (String) message.obj; + handleOnScreenStateChange(action); + } break; + } + } + }; - mMagnifiedRegionCenterX = Math.min(Math.max(magnifiedRegionCenterX, - minMagnifiedRegionCenterX), maxMagnifiedRegionCenterX); - mMagnifiedRegionCenterY = Math.min(Math.max(magnifiedRegionCenterY, - minMagnifiedRegionCenterY), maxMagnifiedRegionCenterY); + public ScreenStateObserver(Context context, + MagnificationController magnificationController, ViewportWindow viewportWindow) { + mContext = context; + mMagnificationController = magnificationController; + mViewportWindow = viewportWindow; + mContext.registerReceiver(this, new IntentFilter(Intent.ACTION_SCREEN_OFF)); + } - mScaledOffsetX = -(mMagnifiedRegionCenterX * scale - viewportWidth / 2); - mScaledOffsetY = -(mMagnifiedRegionCenterY * scale - viewportHeight / 2); - } + public void destroy() { + mContext.unregisterReceiver(this); + } - public void updateFrom(MagnificationSpec other) { - mScale = other.mScale; - mMagnifiedRegionCenterX = other.mMagnifiedRegionCenterX; - mMagnifiedRegionCenterY = other.mMagnifiedRegionCenterY; - mScaledOffsetX = other.mScaledOffsetX; - mScaledOffsetY = other.mScaledOffsetY; + @Override + public void onReceive(Context context, Intent intent) { + mHandler.obtainMessage(MESSAGE_ON_SCREEN_STATE_CHANGE, + intent.getAction()).sendToTarget(); } - public void reset() { - mScale = DEFAULT_SCALE; - mMagnifiedRegionCenterX = 0; - mMagnifiedRegionCenterY = 0; - mScaledOffsetX = 0; - mScaledOffsetY = 0; + private void handleOnScreenStateChange(String action) { + if (mMagnificationController.isMagnifying() + && isScreenMagnificationAutoUpdateEnabled(mContext)) { + mMagnificationController.reset(false); + mViewportWindow.setShown(false, false); } } } - private static final class Viewport { + private static final class ViewportWindow implements DisplayListener { + private static final String WINDOW_TITLE = "Magnification Overlay"; private static final String PROPERTY_NAME_ALPHA = "alpha"; - private static final String PROPERTY_NAME_BOUNDS = "bounds"; private static final int MIN_ALPHA = 0; - private static final int MAX_ALPHA = 255; - private final ArrayList<WindowInfo> mTempWindowInfoList = new ArrayList<WindowInfo>(); + private final Rect mBounds = new Rect(); + + private final ValueAnimator mResizeFrameAnimator; + private final ValueAnimator mShowHideFrameAnimator; - private final Rect mTempRect1 = new Rect(); - private final Rect mTempRect2 = new Rect(); - private final Rect mTempRect3 = new Rect(); + private final WindowManager mWindowManager; + private final DisplayManager mDisplayManager; + private final Display mDisplay; + private final DisplayInfo mDisplayInfo = new DisplayInfo(); + private final int mDisplayId; - private final IWindowManager mWindowManagerService; - private final DisplayProvider mDisplayProvider; + private final ContentView mWindowContent; + private final WindowManager.LayoutParams mWindowParams; - private final ViewportWindow mViewportFrame; + private boolean mShown; + private int mAlpha; - private final ValueAnimator mResizeFrameAnimator; + public ViewportWindow(Context context, int displayId) { + mWindowManager = (WindowManager) context.getSystemService(Service.WINDOW_SERVICE); - private final ValueAnimator mShowHideFrameAnimator; + mDisplayId = displayId; + mDisplayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE); + mDisplay = mDisplayManager.getDisplay(displayId); + mDisplayManager.registerDisplayListener(this, null); + updateDisplayInfo(); - public Viewport(Context context, WindowManager windowManager, - IWindowManager windowManagerService, DisplayProvider displayInfoProvider, - Interpolator animationInterpolator, long animationDuration) { - mWindowManagerService = windowManagerService; - mDisplayProvider = displayInfoProvider; - mViewportFrame = new ViewportWindow(context, windowManager, displayInfoProvider); - - mShowHideFrameAnimator = ObjectAnimator.ofInt(mViewportFrame, PROPERTY_NAME_ALPHA, - MIN_ALPHA, MAX_ALPHA); - mShowHideFrameAnimator.setInterpolator(animationInterpolator); - mShowHideFrameAnimator.setDuration(animationDuration); + ViewGroup.LayoutParams contentParams = new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); + mWindowContent = new ContentView(context); + mWindowContent.setLayoutParams(contentParams); + mWindowContent.setBackgroundColor(R.color.transparent); + + mWindowParams = new WindowManager.LayoutParams( + WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY); + mWindowParams.flags |= WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN + | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE + | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; + mWindowParams.setTitle(WINDOW_TITLE); + mWindowParams.gravity = Gravity.CENTER; + mWindowParams.width = mDisplayInfo.logicalWidth; + mWindowParams.height = mDisplayInfo.logicalHeight; + mWindowParams.format = PixelFormat.TRANSLUCENT; + + Interpolator interpolator = new DecelerateInterpolator(2.5f); + final long longAnimationDuration = context.getResources().getInteger( + com.android.internal.R.integer.config_longAnimTime); + + mShowHideFrameAnimator = ObjectAnimator.ofInt(this, PROPERTY_NAME_ALPHA, + MIN_ALPHA, MAX_ALPHA); + mShowHideFrameAnimator.setInterpolator(interpolator); + mShowHideFrameAnimator.setDuration(longAnimationDuration); mShowHideFrameAnimator.addListener(new AnimatorListener() { @Override public void onAnimationEnd(Animator animation) { if (mShowHideFrameAnimator.getAnimatedValue().equals(MIN_ALPHA)) { - mViewportFrame.hide(); + hide(); } } + @Override public void onAnimationStart(Animator animation) { /* do nothing - stub */ } + @Override public void onAnimationCancel(Animator animation) { /* do nothing - stub */ } + @Override public void onAnimationRepeat(Animator animation) { /* do nothing - stub */ @@ -1514,6 +1280,7 @@ public final class ScreenMagnifier implements EventStreamTransformation { Rect.class, PROPERTY_NAME_BOUNDS); TypeEvaluator<Rect> evaluator = new TypeEvaluator<Rect>() { private final Rect mReusableResultRect = new Rect(); + @Override public Rect evaluate(float fraction, Rect fromFrame, Rect toFrame) { Rect result = mReusableResultRect; @@ -1528,103 +1295,18 @@ public final class ScreenMagnifier implements EventStreamTransformation { return result; } }; - mResizeFrameAnimator = ObjectAnimator.ofObject(mViewportFrame, property, - evaluator, mViewportFrame.mBounds, mViewportFrame.mBounds); - mResizeFrameAnimator.setDuration((long) (animationDuration)); - mResizeFrameAnimator.setInterpolator(animationInterpolator); - - recomputeBounds(false); + mResizeFrameAnimator = ObjectAnimator.ofObject(this, property, + evaluator, mBounds, mBounds); + mResizeFrameAnimator.setDuration(longAnimationDuration); + mResizeFrameAnimator.setInterpolator(interpolator); } - private final Comparator<WindowInfo> mWindowInfoInverseComparator = - new Comparator<WindowInfo>() { - @Override - public int compare(WindowInfo lhs, WindowInfo rhs) { - if (lhs.layer != rhs.layer) { - return rhs.layer - lhs.layer; - } - if (lhs.touchableRegion.top != rhs.touchableRegion.top) { - return rhs.touchableRegion.top - lhs.touchableRegion.top; - } - if (lhs.touchableRegion.left != rhs.touchableRegion.left) { - return rhs.touchableRegion.left - lhs.touchableRegion.left; - } - if (lhs.touchableRegion.right != rhs.touchableRegion.right) { - return rhs.touchableRegion.right - lhs.touchableRegion.right; - } - if (lhs.touchableRegion.bottom != rhs.touchableRegion.bottom) { - return rhs.touchableRegion.bottom - lhs.touchableRegion.bottom; - } - return 0; - } - }; - - public void recomputeBounds(boolean animate) { - Rect magnifiedFrame = mTempRect1; - magnifiedFrame.set(0, 0, 0, 0); - - DisplayInfo displayInfo = mDisplayProvider.getDisplayInfo(); - - Rect availableFrame = mTempRect2; - availableFrame.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight); - - ArrayList<WindowInfo> infos = mTempWindowInfoList; - infos.clear(); - int windowCount = 0; - try { - mWindowManagerService.getVisibleWindowsForDisplay( - mDisplayProvider.getDisplay().getDisplayId(), infos); - Collections.sort(infos, mWindowInfoInverseComparator); - windowCount = infos.size(); - for (int i = 0; i < windowCount; i++) { - WindowInfo info = infos.get(i); - if (info.type == WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY) { - continue; - } - Rect windowFrame = mTempRect3; - windowFrame.set(info.touchableRegion); - if (isWindowMagnified(info.type)) { - magnifiedFrame.union(windowFrame); - magnifiedFrame.intersect(availableFrame); - } else { - subtract(windowFrame, magnifiedFrame); - subtract(availableFrame, windowFrame); - } - if (availableFrame.equals(magnifiedFrame)) { - break; - } - } - } catch (RemoteException re) { - /* ignore */ - } finally { - for (int i = windowCount - 1; i >= 0; i--) { - infos.remove(i).recycle(); - } - } - - final int displayWidth = mDisplayProvider.getDisplayInfo().logicalWidth; - final int displayHeight = mDisplayProvider.getDisplayInfo().logicalHeight; - magnifiedFrame.intersect(0, 0, displayWidth, displayHeight); - - resize(magnifiedFrame, animate); + public boolean isShown() { + return mShown; } - private boolean isWindowMagnified(int type) { - return (type != WindowManager.LayoutParams.TYPE_NAVIGATION_BAR - && type != WindowManager.LayoutParams.TYPE_INPUT_METHOD - && type != WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG); - } - - public void rotationChanged() { - mViewportFrame.rotationChanged(); - } - - public Rect getBounds() { - return mViewportFrame.getBounds(); - } - - public void setFrameShown(boolean shown, boolean animate) { - if (mViewportFrame.isShown() == shown) { + public void setShown(boolean shown, boolean animate) { + if (isShown() == shown) { return; } if (animate) { @@ -1632,7 +1314,7 @@ public final class ScreenMagnifier implements EventStreamTransformation { mShowHideFrameAnimator.reverse(); } else { if (shown) { - mViewportFrame.show(); + show(); mShowHideFrameAnimator.start(); } else { mShowHideFrameAnimator.reverse(); @@ -1641,221 +1323,140 @@ public final class ScreenMagnifier implements EventStreamTransformation { } else { mShowHideFrameAnimator.cancel(); if (shown) { - mViewportFrame.show(); + show(); } else { - mViewportFrame.hide(); + hide(); } } } - private void resize(Rect bounds, boolean animate) { - if (mViewportFrame.getBounds().equals(bounds)) { + private void show() { + if (mShown) { + return; + } + mShown = true; + mWindowManager.addView(mWindowContent, mWindowParams); + if (DEBUG_VIEWPORT_WINDOW) { + Slog.i(LOG_TAG, "ViewportWindow shown."); + } + } + + public void setBounds(Rect bounds, boolean animate) { + if (getBounds().equals(bounds)) { return; } if (animate) { if (mResizeFrameAnimator.isRunning()) { mResizeFrameAnimator.cancel(); } - mResizeFrameAnimator.setObjectValues(mViewportFrame.mBounds, bounds); + mResizeFrameAnimator.setObjectValues(getBounds(), bounds); mResizeFrameAnimator.start(); } else { - mViewportFrame.setBounds(bounds); + setBounds(bounds); } } - private 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; + private void hide() { + if (!mShown) { + return; } - if (lhs.bottom > rhs.bottom) { - lhs.top = rhs.bottom; + mShown = false; + mWindowManager.removeView(mWindowContent); + if (DEBUG_VIEWPORT_WINDOW) { + Slog.i(LOG_TAG, "ViewportWindow hidden."); } - return true; } - private static final class ViewportWindow { - private static final String WINDOW_TITLE = "Magnification Overlay"; - - private final WindowManager mWindowManager; - private final DisplayProvider mDisplayProvider; - - private final ContentView mWindowContent; - private final WindowManager.LayoutParams mWindowParams; - - private final Rect mBounds = new Rect(); - private boolean mShown; - private int mAlpha; - - public ViewportWindow(Context context, WindowManager windowManager, - DisplayProvider displayProvider) { - mWindowManager = windowManager; - mDisplayProvider = displayProvider; - - ViewGroup.LayoutParams contentParams = new ViewGroup.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); - mWindowContent = new ContentView(context); - mWindowContent.setLayoutParams(contentParams); - mWindowContent.setBackgroundColor(R.color.transparent); - - mWindowParams = new WindowManager.LayoutParams( - WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY); - mWindowParams.flags |= WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN - | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE - | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; - mWindowParams.setTitle(WINDOW_TITLE); - mWindowParams.gravity = Gravity.CENTER; - mWindowParams.width = displayProvider.getDisplayInfo().logicalWidth; - mWindowParams.height = displayProvider.getDisplayInfo().logicalHeight; - mWindowParams.format = PixelFormat.TRANSLUCENT; - } - - public boolean isShown() { - return mShown; - } + @SuppressWarnings("unused") + // Called reflectively from an animator. + public int getAlpha() { + return mAlpha; + } - public void show() { - if (mShown) { - return; - } - mShown = true; - mWindowManager.addView(mWindowContent, mWindowParams); - if (DEBUG_VIEWPORT_WINDOW) { - Slog.i(LOG_TAG, "ViewportWindow shown."); - } + @SuppressWarnings("unused") + // Called reflectively from an animator. + public void setAlpha(int alpha) { + if (mAlpha == alpha) { + return; } - - public void hide() { - if (!mShown) { - return; - } - mShown = false; - mWindowManager.removeView(mWindowContent); - if (DEBUG_VIEWPORT_WINDOW) { - Slog.i(LOG_TAG, "ViewportWindow hidden."); - } + mAlpha = alpha; + if (mShown) { + mWindowContent.invalidate(); } - - @SuppressWarnings("unused") - // Called reflectively from an animator. - public int getAlpha() { - return mAlpha; + if (DEBUG_VIEWPORT_WINDOW) { + Slog.i(LOG_TAG, "ViewportFrame set alpha: " + alpha); } + } - @SuppressWarnings("unused") - // Called reflectively from an animator. - public void setAlpha(int alpha) { - if (mAlpha == alpha) { - return; - } - mAlpha = alpha; - if (mShown) { - mWindowContent.invalidate(); - } - if (DEBUG_VIEWPORT_WINDOW) { - Slog.i(LOG_TAG, "ViewportFrame set alpha: " + alpha); - } - } + public Rect getBounds() { + return mBounds; + } - public Rect getBounds() { - return mBounds; + public void setBounds(Rect bounds) { + if (mBounds.equals(bounds)) { + return; } - - public void rotationChanged() { - mWindowParams.width = mDisplayProvider.getDisplayInfo().logicalWidth; - mWindowParams.height = mDisplayProvider.getDisplayInfo().logicalHeight; - if (mShown) { - mWindowManager.updateViewLayout(mWindowContent, mWindowParams); - } + mBounds.set(bounds); + if (mShown) { + mWindowContent.invalidate(); } - - public void setBounds(Rect bounds) { - if (mBounds.equals(bounds)) { - return; - } - mBounds.set(bounds); - if (mShown) { - mWindowContent.invalidate(); - } - if (DEBUG_VIEWPORT_WINDOW) { - Slog.i(LOG_TAG, "ViewportFrame set bounds: " + bounds); - } + if (DEBUG_VIEWPORT_WINDOW) { + Slog.i(LOG_TAG, "ViewportFrame set bounds: " + bounds); } + } - private final class ContentView extends View { - private final Drawable mHighlightFrame; - - public ContentView(Context context) { - super(context); - mHighlightFrame = context.getResources().getDrawable( - R.drawable.magnified_region_frame); - } - - @Override - public void onDraw(Canvas canvas) { - canvas.drawColor(Color.TRANSPARENT, Mode.CLEAR); - mHighlightFrame.setBounds(mBounds); - mHighlightFrame.setAlpha(mAlpha); - mHighlightFrame.draw(canvas); - } + public void rotationChanged() { + mWindowParams.width = mDisplayInfo.logicalWidth; + mWindowParams.height = mDisplayInfo.logicalHeight; + if (mShown) { + mWindowManager.updateViewLayout(mWindowContent, mWindowParams); } } - } - - private static class DisplayProvider implements DisplayListener { - private final WindowManager mWindowManager; - private final DisplayManager mDisplayManager; - private final Display mDefaultDisplay; - private final DisplayInfo mDefaultDisplayInfo = new DisplayInfo(); - public DisplayProvider(Context context, WindowManager windowManager) { - mWindowManager = windowManager; - mDisplayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE); - mDefaultDisplay = mWindowManager.getDefaultDisplay(); - mDisplayManager.registerDisplayListener(this, null); - updateDisplayInfo(); - } + private final class ContentView extends View { + private final Drawable mHighlightFrame; - public DisplayInfo getDisplayInfo() { - return mDefaultDisplayInfo; - } + public ContentView(Context context) { + super(context); + mHighlightFrame = context.getResources().getDrawable( + R.drawable.magnified_region_frame); + } - public Display getDisplay() { - return mDefaultDisplay; + @Override + public void onDraw(Canvas canvas) { + canvas.drawColor(Color.TRANSPARENT, Mode.CLEAR); + mHighlightFrame.setBounds(mBounds); + mHighlightFrame.setAlpha(mAlpha); + mHighlightFrame.draw(canvas); + } } private void updateDisplayInfo() { - if (!mDefaultDisplay.getDisplayInfo(mDefaultDisplayInfo)) { - Slog.e(LOG_TAG, "Default display is not valid."); + if (!mDisplay.getDisplayInfo(mDisplayInfo)) { + Slog.e(LOG_TAG, "Display is not valid."); } } public void destroy() { + setShown(false, true); mDisplayManager.unregisterDisplayListener(this); } @Override - public void onDisplayAdded(int displayId) { - /* do noting */ + public void onDisplayChanged(int displayId) { + if (mDisplayId == displayId) { + updateDisplayInfo(); + } } @Override - public void onDisplayRemoved(int displayId) { - // Having no default display + public void onDisplayAdded(int displayId) { + /* do nothing */ } @Override - public void onDisplayChanged(int displayId) { - updateDisplayInfo(); + public void onDisplayRemoved(int displayId) { + /* do nothing */ } } } 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? |