diff options
31 files changed, 1675 insertions, 1690 deletions
@@ -154,7 +154,8 @@ LOCAL_SRC_FILES += \ core/java/android/view/accessibility/IAccessibilityManager.aidl \ core/java/android/view/accessibility/IAccessibilityManagerClient.aidl \ core/java/android/view/IApplicationToken.aidl \ - core/java/android/view/IDisplayContentChangeListener.aidl \ + core/java/android/view/IDisplayMagnificationMediator.aidl \ + core/java/android/view/IDisplayMagnificationController.aidl \ core/java/android/view/IInputFilter.aidl \ core/java/android/view/IInputFilterHost.aidl \ core/java/android/view/IOnKeyguardExitResult.aidl \ diff --git a/CleanSpec.mk b/CleanSpec.mk index 01d09f6..425794a 100644 --- a/CleanSpec.mk +++ b/CleanSpec.mk @@ -141,6 +141,11 @@ $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/media/audio/ui/*.ogg) $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/telephony/java/com/android/internal/telephony/IExtendedNetworkService.java) $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/telephony/java/com/android/internal/telephony/IExtendedNetworkService.P) $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/ImageProcessing_intermediates) +$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/view/IDisplayContentChangeListener.java) +$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/view/IDisplayContentChangeListener.P) +$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/view/IWindowManager.java) +$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/view/IWindowManager.P) + # ************************************************ # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST # ************************************************ diff --git a/api/current.txt b/api/current.txt index 454e5da..2be13a0 100644 --- a/api/current.txt +++ b/api/current.txt @@ -24746,6 +24746,7 @@ package android.view { method public android.graphics.Canvas lockCanvas(android.graphics.Rect) throws java.lang.IllegalArgumentException, android.view.Surface.OutOfResourcesException; method public void readFromParcel(android.os.Parcel); method public void release(); + method public static java.lang.String rotationToString(int); method public deprecated void unlockCanvas(android.graphics.Canvas); method public void unlockCanvasAndPost(android.graphics.Canvas); method public void writeToParcel(android.os.Parcel, int); diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java index b0bad07..ecf3b19 100644 --- a/core/java/android/accessibilityservice/AccessibilityService.java +++ b/core/java/android/accessibilityservice/AccessibilityService.java @@ -548,6 +548,7 @@ public abstract class AccessibilityService extends Service { private static final int DO_ON_INTERRUPT = 20; private static final int DO_ON_ACCESSIBILITY_EVENT = 30; private static final int DO_ON_GESTURE = 40; + private static final int DO_CLEAR_ACCESSIBILITY_NODE_INFO_CACHE = 50; private final HandlerCaller mCaller; @@ -580,6 +581,11 @@ public abstract class AccessibilityService extends Service { mCaller.sendMessage(message); } + public void clearAccessibilityNodeInfoCache() { + Message message = mCaller.obtainMessage(DO_CLEAR_ACCESSIBILITY_NODE_INFO_CACHE); + mCaller.sendMessage(message); + } + public void executeMessage(Message message) { switch (message.what) { case DO_ON_ACCESSIBILITY_EVENT : @@ -611,6 +617,9 @@ public abstract class AccessibilityService extends Service { final int gestureId = message.arg1; mCallback.onGesture(gestureId); return; + case DO_CLEAR_ACCESSIBILITY_NODE_INFO_CACHE: + AccessibilityInteractionClient.getInstance().clearCache(); + return; default : Log.w(LOG_TAG, "Unknown message type " + message.what); } diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl index d459fd5..5d684e3 100644 --- a/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl +++ b/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl @@ -33,4 +33,6 @@ import android.view.accessibility.AccessibilityEvent; void onInterrupt(); void onGesture(int gesture); + + void clearAccessibilityNodeInfoCache(); } diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl index dd50f3c..f33f503 100644 --- a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl +++ b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl @@ -18,6 +18,7 @@ package android.accessibilityservice; import android.os.Bundle; import android.accessibilityservice.AccessibilityServiceInfo; +import android.view.MagnificationSpec; import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.IAccessibilityInteractionConnectionCallback; @@ -44,9 +45,9 @@ interface IAccessibilityServiceConnection { * @param callback Callback which to receive the result. * @param flags Additional flags. * @param threadId The id of the calling thread. - * @return The current window scale, where zero means a failure. + * @return Whether the call succeeded. */ - float findAccessibilityNodeInfoByAccessibilityId(int accessibilityWindowId, + boolean findAccessibilityNodeInfoByAccessibilityId(int accessibilityWindowId, long accessibilityNodeId, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, long threadId); @@ -66,9 +67,9 @@ interface IAccessibilityServiceConnection { * @param interactionId The id of the interaction for matching with the callback result. * @param callback Callback which to receive the result. * @param threadId The id of the calling thread. - * @return The current window scale, where zero means a failure. + * @return Whether the call succeeded. */ - float findAccessibilityNodeInfosByText(int accessibilityWindowId, long accessibilityNodeId, + boolean findAccessibilityNodeInfosByText(int accessibilityWindowId, long accessibilityNodeId, String text, int interactionId, IAccessibilityInteractionConnectionCallback callback, long threadId); @@ -88,9 +89,9 @@ interface IAccessibilityServiceConnection { * @param interactionId The id of the interaction for matching with the callback result. * @param callback Callback which to receive the result. * @param threadId The id of the calling thread. - * @return The current window scale, where zero means a failure. + * @return Whether the call succeeded. */ - float findAccessibilityNodeInfoByViewId(int accessibilityWindowId, long accessibilityNodeId, + boolean findAccessibilityNodeInfoByViewId(int accessibilityWindowId, long accessibilityNodeId, int viewId, int interactionId, IAccessibilityInteractionConnectionCallback callback, long threadId); @@ -110,9 +111,9 @@ interface IAccessibilityServiceConnection { * @param interactionId The id of the interaction for matching with the callback result. * @param callback Callback which to receive the result. * @param threadId The id of the calling thread. - * @return The current window scale, where zero means a failure. + * @return Whether the call succeeded. */ - float findFocus(int accessibilityWindowId, long accessibilityNodeId, int focusType, + boolean findFocus(int accessibilityWindowId, long accessibilityNodeId, int focusType, int interactionId, IAccessibilityInteractionConnectionCallback callback, long threadId); /** @@ -131,9 +132,9 @@ interface IAccessibilityServiceConnection { * @param interactionId The id of the interaction for matching with the callback result. * @param callback Callback which to receive the result. * @param threadId The id of the calling thread. - * @return The current window scale, where zero means a failure. + * @return Whether the call succeeded. */ - float focusSearch(int accessibilityWindowId, long accessibilityNodeId, int direction, + boolean focusSearch(int accessibilityWindowId, long accessibilityNodeId, int direction, int interactionId, IAccessibilityInteractionConnectionCallback callback, long threadId); /** diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java index 9bee4bf..ba82d79 100644 --- a/core/java/android/view/AccessibilityInteractionController.java +++ b/core/java/android/view/AccessibilityInteractionController.java @@ -18,6 +18,7 @@ package android.view; import static android.view.accessibility.AccessibilityNodeInfo.INCLUDE_NOT_IMPORTANT_VIEWS; +import android.graphics.Point; import android.graphics.Rect; import android.os.Bundle; import android.os.Handler; @@ -26,6 +27,7 @@ import android.os.Message; import android.os.Process; import android.os.RemoteException; import android.util.SparseLongArray; +import android.view.View.AttachInfo; import android.view.accessibility.AccessibilityInteractionClient; import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.AccessibilityNodeProvider; @@ -62,7 +64,10 @@ final class AccessibilityInteractionController { private final ArrayList<View> mTempArrayList = new ArrayList<View>(); + private final Point mTempPoint = new Point(); private final Rect mTempRect = new Rect(); + private final Rect mTempRect1 = new Rect(); + private final Rect mTempRect2 = new Rect(); public AccessibilityInteractionController(ViewRootImpl viewRootImpl) { Looper looper = viewRootImpl.mHandler.getLooper(); @@ -86,7 +91,7 @@ final class AccessibilityInteractionController { public void findAccessibilityNodeInfoByAccessibilityIdClientThread( long accessibilityNodeId, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, - long interrogatingTid) { + long interrogatingTid, MagnificationSpec spec) { Message message = mHandler.obtainMessage(); message.what = PrivateHandler.MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID; message.arg1 = flags; @@ -96,6 +101,7 @@ final class AccessibilityInteractionController { args.argi2 = AccessibilityNodeInfo.getVirtualDescendantId(accessibilityNodeId); args.argi3 = interactionId; args.arg1 = callback; + args.arg2 = spec; message.obj = args; // If the interrogation is performed by the same thread as the main UI @@ -119,6 +125,7 @@ final class AccessibilityInteractionController { final int interactionId = args.argi3; final IAccessibilityInteractionConnectionCallback callback = (IAccessibilityInteractionConnectionCallback) args.arg1; + final MagnificationSpec spec = (MagnificationSpec) args.arg2; args.recycle(); @@ -142,7 +149,10 @@ final class AccessibilityInteractionController { } finally { try { mViewRootImpl.mAttachInfo.mIncludeNotImportantViews = false; - applyApplicationScaleIfNeeded(infos); + applyAppScaleAndMagnificationSpecIfNeeded(infos, spec); + if (spec != null) { + spec.recycle(); + } callback.setFindAccessibilityNodeInfosResult(infos, interactionId); infos.clear(); } catch (RemoteException re) { @@ -153,7 +163,7 @@ final class AccessibilityInteractionController { public void findAccessibilityNodeInfoByViewIdClientThread(long accessibilityNodeId, int viewId, int interactionId, IAccessibilityInteractionConnectionCallback callback, - int flags, int interrogatingPid, long interrogatingTid) { + int flags, int interrogatingPid, long interrogatingTid, MagnificationSpec spec) { Message message = mHandler.obtainMessage(); message.what = PrivateHandler.MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID; message.arg1 = flags; @@ -163,6 +173,7 @@ final class AccessibilityInteractionController { args.argi1 = viewId; args.argi2 = interactionId; args.arg1 = callback; + args.arg2 = spec; message.obj = args; @@ -187,6 +198,7 @@ final class AccessibilityInteractionController { final int interactionId = args.argi2; final IAccessibilityInteractionConnectionCallback callback = (IAccessibilityInteractionConnectionCallback) args.arg1; + final MagnificationSpec spec = (MagnificationSpec) args.arg2; args.recycle(); @@ -212,7 +224,10 @@ final class AccessibilityInteractionController { } finally { try { mViewRootImpl.mAttachInfo.mIncludeNotImportantViews = false; - applyApplicationScaleIfNeeded(info); + applyAppScaleAndMagnificationSpecIfNeeded(info, spec); + if (spec != null) { + spec.recycle(); + } callback.setFindAccessibilityNodeInfoResult(info, interactionId); } catch (RemoteException re) { /* ignore - the other side will time out */ @@ -222,7 +237,7 @@ final class AccessibilityInteractionController { public void findAccessibilityNodeInfosByTextClientThread(long accessibilityNodeId, String text, int interactionId, IAccessibilityInteractionConnectionCallback callback, - int flags, int interrogatingPid, long interrogatingTid) { + int flags, int interrogatingPid, long interrogatingTid, MagnificationSpec spec) { Message message = mHandler.obtainMessage(); message.what = PrivateHandler.MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT; message.arg1 = flags; @@ -230,10 +245,10 @@ final class AccessibilityInteractionController { SomeArgs args = SomeArgs.obtain(); args.arg1 = text; args.arg2 = callback; + args.arg3 = spec; args.argi1 = AccessibilityNodeInfo.getAccessibilityViewId(accessibilityNodeId); args.argi2 = AccessibilityNodeInfo.getVirtualDescendantId(accessibilityNodeId); args.argi3 = interactionId; - message.obj = args; // If the interrogation is performed by the same thread as the main UI @@ -255,6 +270,7 @@ final class AccessibilityInteractionController { final String text = (String) args.arg1; final IAccessibilityInteractionConnectionCallback callback = (IAccessibilityInteractionConnectionCallback) args.arg2; + final MagnificationSpec spec = (MagnificationSpec) args.arg3; final int accessibilityViewId = args.argi1; final int virtualDescendantId = args.argi2; final int interactionId = args.argi3; @@ -310,7 +326,10 @@ final class AccessibilityInteractionController { } finally { try { mViewRootImpl.mAttachInfo.mIncludeNotImportantViews = false; - applyApplicationScaleIfNeeded(infos); + applyAppScaleAndMagnificationSpecIfNeeded(infos, spec); + if (spec != null) { + spec.recycle(); + } callback.setFindAccessibilityNodeInfosResult(infos, interactionId); } catch (RemoteException re) { /* ignore - the other side will time out */ @@ -320,7 +339,7 @@ final class AccessibilityInteractionController { public void findFocusClientThread(long accessibilityNodeId, int focusType, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interogatingPid, - long interrogatingTid) { + long interrogatingTid, MagnificationSpec spec) { Message message = mHandler.obtainMessage(); message.what = PrivateHandler.MSG_FIND_FOCUS; message.arg1 = flags; @@ -331,6 +350,7 @@ final class AccessibilityInteractionController { args.argi2 = AccessibilityNodeInfo.getAccessibilityViewId(accessibilityNodeId); args.argi3 = AccessibilityNodeInfo.getVirtualDescendantId(accessibilityNodeId); args.arg1 = callback; + args.arg2 = spec; message.obj = args; @@ -356,7 +376,7 @@ final class AccessibilityInteractionController { final int virtualDescendantId = args.argi3; final IAccessibilityInteractionConnectionCallback callback = (IAccessibilityInteractionConnectionCallback) args.arg1; - + final MagnificationSpec spec = (MagnificationSpec) args.arg2; args.recycle(); AccessibilityNodeInfo focused = null; @@ -407,7 +427,10 @@ final class AccessibilityInteractionController { } finally { try { mViewRootImpl.mAttachInfo.mIncludeNotImportantViews = false; - applyApplicationScaleIfNeeded(focused); + applyAppScaleAndMagnificationSpecIfNeeded(focused, spec); + if (spec != null) { + spec.recycle(); + } callback.setFindAccessibilityNodeInfoResult(focused, interactionId); } catch (RemoteException re) { /* ignore - the other side will time out */ @@ -417,7 +440,7 @@ final class AccessibilityInteractionController { public void focusSearchClientThread(long accessibilityNodeId, int direction, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interogatingPid, - long interrogatingTid) { + long interrogatingTid, MagnificationSpec spec) { Message message = mHandler.obtainMessage(); message.what = PrivateHandler.MSG_FOCUS_SEARCH; message.arg1 = flags; @@ -427,6 +450,7 @@ final class AccessibilityInteractionController { args.argi2 = direction; args.argi3 = interactionId; args.arg1 = callback; + args.arg2 = spec; message.obj = args; @@ -451,6 +475,7 @@ final class AccessibilityInteractionController { final int interactionId = args.argi3; final IAccessibilityInteractionConnectionCallback callback = (IAccessibilityInteractionConnectionCallback) args.arg1; + final MagnificationSpec spec = (MagnificationSpec) args.arg2; args.recycle(); @@ -476,7 +501,10 @@ final class AccessibilityInteractionController { } finally { try { mViewRootImpl.mAttachInfo.mIncludeNotImportantViews = false; - applyApplicationScaleIfNeeded(next); + applyAppScaleAndMagnificationSpecIfNeeded(next, spec); + if (spec != null) { + spec.recycle(); + } callback.setFindAccessibilityNodeInfoResult(next, interactionId); } catch (RemoteException re) { /* ignore - the other side will time out */ @@ -572,38 +600,84 @@ final class AccessibilityInteractionController { return foundView; } - private void applyApplicationScaleIfNeeded(List<AccessibilityNodeInfo> infos) { + private void applyAppScaleAndMagnificationSpecIfNeeded(List<AccessibilityNodeInfo> infos, + MagnificationSpec spec) { if (infos == null) { return; } final float applicationScale = mViewRootImpl.mAttachInfo.mApplicationScale; - if (applicationScale != 1.0f) { + if (shouldApplyAppScaleAndMagnificationSpec(applicationScale, spec)) { final int infoCount = infos.size(); for (int i = 0; i < infoCount; i++) { AccessibilityNodeInfo info = infos.get(i); - applyApplicationScaleIfNeeded(info); + applyAppScaleAndMagnificationSpecIfNeeded(info, spec); } } } - private void applyApplicationScaleIfNeeded(AccessibilityNodeInfo info) { + private void applyAppScaleAndMagnificationSpecIfNeeded(AccessibilityNodeInfo info, + MagnificationSpec spec) { if (info == null) { return; } + final float applicationScale = mViewRootImpl.mAttachInfo.mApplicationScale; + if (!shouldApplyAppScaleAndMagnificationSpec(applicationScale, spec)) { + return; + } + + Rect boundsInParent = mTempRect; + Rect boundsInScreen = mTempRect1; + + info.getBoundsInParent(boundsInParent); + info.getBoundsInScreen(boundsInScreen); if (applicationScale != 1.0f) { - Rect bounds = mTempRect; + boundsInParent.scale(applicationScale); + boundsInScreen.scale(applicationScale); + } + if (spec != null) { + boundsInParent.scale(spec.scale); + // boundsInParent must not be offset. + boundsInScreen.scale(spec.scale); + boundsInScreen.offset((int) spec.offsetX, (int) spec.offsetY); + } + info.setBoundsInParent(boundsInParent); + info.setBoundsInScreen(boundsInScreen); + + if (spec != null) { + AttachInfo attachInfo = mViewRootImpl.mAttachInfo; + if (attachInfo.mDisplay == null) { + return; + } - info.getBoundsInParent(bounds); - bounds.scale(applicationScale); - info.setBoundsInParent(bounds); + final float scale = attachInfo.mApplicationScale * spec.scale; - info.getBoundsInScreen(bounds); - bounds.scale(applicationScale); - info.setBoundsInScreen(bounds); + Rect visibleWinFrame = mTempRect1; + visibleWinFrame.left = (int) (attachInfo.mWindowLeft * scale + spec.offsetX); + visibleWinFrame.top = (int) (attachInfo.mWindowTop * scale + spec.offsetY); + visibleWinFrame.right = (int) (visibleWinFrame.left + mViewRootImpl.mWidth * scale); + visibleWinFrame.bottom = (int) (visibleWinFrame.top + mViewRootImpl.mHeight * scale); + + attachInfo.mDisplay.getRealSize(mTempPoint); + final int displayWidth = mTempPoint.x; + final int displayHeight = mTempPoint.y; + + Rect visibleDisplayFrame = mTempRect2; + visibleDisplayFrame.set(0, 0, displayWidth, displayHeight); + + visibleWinFrame.intersect(visibleDisplayFrame); + + if (!visibleWinFrame.intersects(boundsInScreen.left, boundsInScreen.top, + boundsInScreen.right, boundsInScreen.bottom)) { + info.setVisibleToUser(false); + } } } + private boolean shouldApplyAppScaleAndMagnificationSpec(float appScale, + MagnificationSpec spec) { + return (appScale != 1.0f || (spec != null && !spec.isNop())); + } /** * This class encapsulates a prefetching strategy for the accessibility APIs for diff --git a/core/java/android/view/IDisplayContentChangeListener.aidl b/core/java/android/view/IDisplayMagnificationController.aidl index ef7edea..efe2775 100644 --- a/core/java/android/view/IDisplayContentChangeListener.aidl +++ b/core/java/android/view/IDisplayMagnificationController.aidl @@ -1,7 +1,7 @@ /* ** Copyright 2012, The Android Open Source Project ** -** Licensed under the Apache License, Version 2.0 (the "License") +** 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 ** @@ -16,18 +16,12 @@ package android.view; -import android.os.IBinder; -import android.view.WindowInfo; -import android.graphics.Rect; - /** - * Interface for observing content changes on a display. - * * {@hide} */ -oneway interface IDisplayContentChangeListener { - void onWindowTransition(int displayId, int transition, in WindowInfo info); - void onRectangleOnScreenRequested(int displayId, in Rect rectangle, boolean immediate); - void onWindowLayersChanged(int displayId); +oneway interface IDisplayMagnificationController { + void onMagnifedFrameChanged(int left, int top, int right, int bottom); + void onRectangleOnScreenRequested(int left, int top, int right, int bottom); void onRotationChanged(int rotation); + void onUserContextChanged(); } diff --git a/core/java/android/view/IDisplayMagnificationMediator.aidl b/core/java/android/view/IDisplayMagnificationMediator.aidl new file mode 100644 index 0000000..aa25dac --- /dev/null +++ b/core/java/android/view/IDisplayMagnificationMediator.aidl @@ -0,0 +1,31 @@ +/* +** Copyright 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 android.view; + +import android.view.IDisplayMagnificationController; +import android.view.MagnificationSpec; + +/** + * {@hide} + */ +interface IDisplayMagnificationMediator { + void addController(int displayId, in IDisplayMagnificationController controller); + void removeController(in IDisplayMagnificationController controller); + void setMagnificationSpec(in IDisplayMagnificationController controller, + in MagnificationSpec spec); + MagnificationSpec getCompatibleMagnificationSpec(in IBinder windowToken); +} diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 0fe2a8e..17f04e9 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -27,17 +27,17 @@ import android.graphics.Rect; import android.os.Bundle; import android.os.IRemoteCallback; import android.view.IApplicationToken; -import android.view.IDisplayContentChangeListener; +import android.view.IDisplayMagnificationMediator; import android.view.IOnKeyguardExitResult; import android.view.IRotationWatcher; import android.view.IWindowSession; import android.view.KeyEvent; import android.view.InputEvent; +import android.view.MagnificationSpec; import android.view.MotionEvent; import android.view.InputChannel; import android.view.InputDevice; import android.view.IInputFilter; -import android.view.WindowInfo; /** * System private interface to the window manager. @@ -221,39 +221,19 @@ interface IWindowManager IBinder getFocusedWindowToken(); /** - * Gets the compatibility scale of e window given its token. - */ - float getWindowCompatibilityScale(IBinder windowToken); - - /** * Sets an input filter for manipulating the input event stream. */ void setInputFilter(in IInputFilter filter); /** - * Sets the scale and offset for implementing accessibility magnification. - */ - void magnifyDisplay(int dipslayId, float scale, float offsetX, float offsetY); - - /** - * Adds a listener for display content changes. - */ - void addDisplayContentChangeListener(int displayId, IDisplayContentChangeListener listener); - - /** - * Removes a listener for display content changes. - */ - void removeDisplayContentChangeListener(int displayId, IDisplayContentChangeListener listener); - - /** - * Gets the info for a window given its token. + * Gets the display magnification mediator. */ - WindowInfo getWindowInfo(IBinder token); + IDisplayMagnificationMediator getDisplayMagnificationMediator(); /** - * Gets the infos for all visible windows. + * Gets the frame of a window given its token. */ - void getVisibleWindowsForDisplay(int displayId, out List<WindowInfo> outInfos); + void getWindowFrame(IBinder token, out Rect outFrame); /** * Device is in safe mode. diff --git a/core/java/android/view/WindowInfo.aidl b/core/java/android/view/MagnificationSpec.aidl index 23e927a..d5fbdef 100644 --- a/core/java/android/view/WindowInfo.aidl +++ b/core/java/android/view/MagnificationSpec.aidl @@ -17,4 +17,4 @@ package android.view; -parcelable WindowInfo; +parcelable MagnificationSpec; diff --git a/core/java/android/view/MagnificationSpec.java b/core/java/android/view/MagnificationSpec.java new file mode 100644 index 0000000..7fb5615 --- /dev/null +++ b/core/java/android/view/MagnificationSpec.java @@ -0,0 +1,120 @@ +/* + * 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 android.view; + +import android.os.Parcel; +import android.os.Parcelable; +import android.util.Pools.SynchronizedPool; + +/** + * This class represents spec for performing screen magnification. + * + * @hide + */ +public class MagnificationSpec implements Parcelable { + private static final int MAX_POOL_SIZE = 20; + private static final SynchronizedPool<MagnificationSpec> sPool = + new SynchronizedPool<MagnificationSpec>(MAX_POOL_SIZE); + + public float scale = 1.0f; + public float offsetX; + public float offsetY; + + private MagnificationSpec() { + /* do nothing - reducing visibility */ + } + + public void initialize(float scale, float offsetX, float offsetY) { + this.scale = scale; + this.offsetX = offsetX; + this.offsetY = offsetY; + } + + public boolean isNop() { + return scale == 1.0f && offsetX == 0 && offsetY == 0; + } + + public static MagnificationSpec obtain(MagnificationSpec other) { + MagnificationSpec info = obtain(); + info.scale = other.scale; + info.offsetX = other.offsetX; + info.offsetY = other.offsetY; + return info; + } + + public static MagnificationSpec obtain() { + MagnificationSpec spec = sPool.acquire(); + return (spec != null) ? spec : new MagnificationSpec(); + } + + public void recycle() { + clear(); + sPool.release(this); + } + + public void clear() { + scale = 1.0f; + offsetX = 0.0f; + offsetY = 0.0f; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeFloat(scale); + parcel.writeFloat(offsetX); + parcel.writeFloat(offsetY); + recycle(); + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("<scale:"); + builder.append(scale); + builder.append(",offsetX:"); + builder.append(offsetX); + builder.append(",offsetY:"); + builder.append(offsetY); + builder.append(">"); + return builder.toString(); + } + + private void initFromParcel(Parcel parcel) { + scale = parcel.readFloat(); + offsetX = parcel.readFloat(); + offsetY = parcel.readFloat(); + } + + public static final Creator<MagnificationSpec> CREATOR = new Creator<MagnificationSpec>() { + @Override + public MagnificationSpec[] newArray(int size) { + return new MagnificationSpec[size]; + } + + @Override + public MagnificationSpec createFromParcel(Parcel parcel) { + MagnificationSpec spec = MagnificationSpec.obtain(); + spec.initFromParcel(parcel); + return spec; + } + }; +} diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java index 550a740..f2c5eac 100644 --- a/core/java/android/view/Surface.java +++ b/core/java/android/view/Surface.java @@ -808,6 +808,32 @@ public class Surface implements Parcelable { } /** + * Returns a human readable representation of a rotation. + * + * @param rotation The rotation. + * @return The rotation symbolic name. + */ + public static 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); + } + } + } + + /** * A Canvas class that can handle the compatibility mode. * This does two things differently. * <ul> diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index e66e30f..5ad7bb3 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -5416,12 +5416,13 @@ public final class ViewRootImpl implements ViewParent, @Override public void findAccessibilityNodeInfoByAccessibilityId(long accessibilityNodeId, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, - int interrogatingPid, long interrogatingTid) { + int interrogatingPid, long interrogatingTid, MagnificationSpec spec) { ViewRootImpl viewRootImpl = mViewRootImpl.get(); if (viewRootImpl != null && viewRootImpl.mView != null) { viewRootImpl.getAccessibilityInteractionController() .findAccessibilityNodeInfoByAccessibilityIdClientThread(accessibilityNodeId, - interactionId, callback, flags, interrogatingPid, interrogatingTid); + interactionId, callback, flags, interrogatingPid, interrogatingTid, + spec); } else { // We cannot make the call and notify the caller so it does not wait. try { @@ -5455,12 +5456,13 @@ public final class ViewRootImpl implements ViewParent, @Override public void findAccessibilityNodeInfoByViewId(long accessibilityNodeId, int viewId, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, - int interrogatingPid, long interrogatingTid) { + int interrogatingPid, long interrogatingTid, MagnificationSpec spec) { ViewRootImpl viewRootImpl = mViewRootImpl.get(); if (viewRootImpl != null && viewRootImpl.mView != null) { viewRootImpl.getAccessibilityInteractionController() .findAccessibilityNodeInfoByViewIdClientThread(accessibilityNodeId, viewId, - interactionId, callback, flags, interrogatingPid, interrogatingTid); + interactionId, callback, flags, interrogatingPid, interrogatingTid, + spec); } else { // We cannot make the call and notify the caller so it does not wait. try { @@ -5474,12 +5476,13 @@ public final class ViewRootImpl implements ViewParent, @Override public void findAccessibilityNodeInfosByText(long accessibilityNodeId, String text, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, - int interrogatingPid, long interrogatingTid) { + int interrogatingPid, long interrogatingTid, MagnificationSpec spec) { ViewRootImpl viewRootImpl = mViewRootImpl.get(); if (viewRootImpl != null && viewRootImpl.mView != null) { viewRootImpl.getAccessibilityInteractionController() .findAccessibilityNodeInfosByTextClientThread(accessibilityNodeId, text, - interactionId, callback, flags, interrogatingPid, interrogatingTid); + interactionId, callback, flags, interrogatingPid, interrogatingTid, + spec); } else { // We cannot make the call and notify the caller so it does not wait. try { @@ -5493,12 +5496,12 @@ public final class ViewRootImpl implements ViewParent, @Override public void findFocus(long accessibilityNodeId, int focusType, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, - int interrogatingPid, long interrogatingTid) { + int interrogatingPid, long interrogatingTid, MagnificationSpec spec) { ViewRootImpl viewRootImpl = mViewRootImpl.get(); if (viewRootImpl != null && viewRootImpl.mView != null) { viewRootImpl.getAccessibilityInteractionController() .findFocusClientThread(accessibilityNodeId, focusType, interactionId, callback, - flags, interrogatingPid, interrogatingTid); + flags, interrogatingPid, interrogatingTid, spec); } else { // We cannot make the call and notify the caller so it does not wait. try { @@ -5512,12 +5515,12 @@ public final class ViewRootImpl implements ViewParent, @Override public void focusSearch(long accessibilityNodeId, int direction, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, - int interrogatingPid, long interrogatingTid) { + int interrogatingPid, long interrogatingTid, MagnificationSpec spec) { ViewRootImpl viewRootImpl = mViewRootImpl.get(); if (viewRootImpl != null && viewRootImpl.mView != null) { viewRootImpl.getAccessibilityInteractionController() .focusSearchClientThread(accessibilityNodeId, direction, interactionId, - callback, flags, interrogatingPid, interrogatingTid); + callback, flags, interrogatingPid, interrogatingTid, spec); } else { // We cannot make the call and notify the caller so it does not wait. try { diff --git a/core/java/android/view/WindowInfo.java b/core/java/android/view/WindowInfo.java deleted file mode 100644 index 7d16e14..0000000 --- a/core/java/android/view/WindowInfo.java +++ /dev/null @@ -1,175 +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 android.view; - -import android.graphics.Rect; -import android.os.IBinder; -import android.os.Parcel; -import android.os.Parcelable; - -/** - * Information the state of a window. - * - * @hide - */ -public class WindowInfo implements Parcelable { - - private static final int MAX_POOL_SIZE = 20; - - private static int UNDEFINED = -1; - - private static Object sPoolLock = new Object(); - private static WindowInfo sPool; - private static int sPoolSize; - - private WindowInfo mNext; - private boolean mInPool; - - public IBinder token; - - public final Rect frame = new Rect(); - - public final Rect touchableRegion = new Rect(); - - public int type = UNDEFINED; - - public float compatibilityScale = UNDEFINED; - - public boolean visible; - - public int displayId = UNDEFINED; - - public int layer = UNDEFINED; - - private WindowInfo() { - /* do nothing - reduce visibility */ - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel parcel, int flags) { - parcel.writeStrongBinder(token); - parcel.writeParcelable(frame, 0); - parcel.writeParcelable(touchableRegion, 0); - parcel.writeInt(type); - parcel.writeFloat(compatibilityScale); - parcel.writeInt(visible ? 1 : 0); - parcel.writeInt(displayId); - parcel.writeInt(layer); - recycle(); - } - - private void initFromParcel(Parcel parcel) { - token = parcel.readStrongBinder(); - frame.set((Rect) parcel.readParcelable(null)); - touchableRegion.set((Rect) parcel.readParcelable(null)); - type = parcel.readInt(); - compatibilityScale = parcel.readFloat(); - visible = (parcel.readInt() == 1); - displayId = parcel.readInt(); - layer = parcel.readInt(); - } - - public static WindowInfo obtain(WindowInfo other) { - WindowInfo info = obtain(); - info.token = other.token; - info.frame.set(other.frame); - info.touchableRegion.set(other.touchableRegion); - info.type = other.type; - info.compatibilityScale = other.compatibilityScale; - info.visible = other.visible; - info.displayId = other.displayId; - info.layer = other.layer; - return info; - } - - public static WindowInfo obtain() { - synchronized (sPoolLock) { - if (sPoolSize > 0) { - WindowInfo info = sPool; - sPool = info.mNext; - info.mNext = null; - info.mInPool = false; - sPoolSize--; - return info; - } else { - return new WindowInfo(); - } - } - } - - public void recycle() { - if (mInPool) { - throw new IllegalStateException("Already recycled."); - } - clear(); - synchronized (sPoolLock) { - if (sPoolSize < MAX_POOL_SIZE) { - mNext = sPool; - sPool = this; - mInPool = true; - sPoolSize++; - } - } - } - - private void clear() { - token = null; - frame.setEmpty(); - touchableRegion.setEmpty(); - type = UNDEFINED; - compatibilityScale = UNDEFINED; - visible = false; - displayId = UNDEFINED; - layer = UNDEFINED; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("Window [token:").append((token != null) ? token.hashCode() : null); - builder.append(", displayId:").append(displayId); - builder.append(", type:").append(type); - builder.append(", visible:").append(visible); - builder.append(", layer:").append(layer); - builder.append(", compatibilityScale:").append(compatibilityScale); - builder.append(", frame:").append(frame); - builder.append(", touchableRegion:").append(touchableRegion); - builder.append("]"); - return builder.toString(); - } - - /** - * @see Parcelable.Creator - */ - public static final Parcelable.Creator<WindowInfo> CREATOR = - new Parcelable.Creator<WindowInfo>() { - public WindowInfo createFromParcel(Parcel parcel) { - WindowInfo info = WindowInfo.obtain(); - info.initFromParcel(parcel); - return info; - } - - public WindowInfo[] newArray(int size) { - return new WindowInfo[size]; - } - }; -} diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java index 26739b3..7bdb44c 100644 --- a/core/java/android/view/WindowManagerPolicy.java +++ b/core/java/android/view/WindowManagerPolicy.java @@ -1112,14 +1112,6 @@ public interface WindowManagerPolicy { public void setLastInputMethodWindowLw(WindowState ime, WindowState target); /** - * Returns whether magnification can be applied to the given window type. - * - * @param attrs The window's LayoutParams. - * @return Whether magnification can be applied. - */ - public boolean canMagnifyWindowLw(WindowManager.LayoutParams attrs); - - /** * Called when the current user changes. Guaranteed to be called before the broadcast * of the new user id is made to all listeners. * diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java index 20b5f17..67df684 100644 --- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java +++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java @@ -17,7 +17,6 @@ package android.view.accessibility; import android.accessibilityservice.IAccessibilityServiceConnection; -import android.graphics.Rect; import android.os.Binder; import android.os.Build; import android.os.Bundle; @@ -102,8 +101,6 @@ public final class AccessibilityInteractionClient private Message mSameThreadMessage; - private final Rect mTempBounds = new Rect(); - // The connection cache is shared between all interrogating threads. private static final SparseArray<IAccessibilityServiceConnection> sConnectionCache = new SparseArray<IAccessibilityServiceConnection>(); @@ -194,14 +191,14 @@ public final class AccessibilityInteractionClient return cachedInfo; } final int interactionId = mInteractionIdCounter.getAndIncrement(); - final float windowScale = connection.findAccessibilityNodeInfoByAccessibilityId( + final boolean success = connection.findAccessibilityNodeInfoByAccessibilityId( accessibilityWindowId, accessibilityNodeId, interactionId, this, prefetchFlags, Thread.currentThread().getId()); // If the scale is zero the call has failed. - if (windowScale > 0) { + if (success) { List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear( interactionId); - finalizeAndCacheAccessibilityNodeInfos(infos, connectionId, windowScale); + finalizeAndCacheAccessibilityNodeInfos(infos, connectionId); if (infos != null && !infos.isEmpty()) { return infos.get(0); } @@ -242,15 +239,13 @@ public final class AccessibilityInteractionClient IAccessibilityServiceConnection connection = getConnection(connectionId); if (connection != null) { final int interactionId = mInteractionIdCounter.getAndIncrement(); - final float windowScale = - connection.findAccessibilityNodeInfoByViewId(accessibilityWindowId, - accessibilityNodeId, viewId, interactionId, this, - Thread.currentThread().getId()); - // If the scale is zero the call has failed. - if (windowScale > 0) { + final boolean success =connection.findAccessibilityNodeInfoByViewId( + accessibilityWindowId, accessibilityNodeId, viewId, interactionId, this, + Thread.currentThread().getId()); + if (success) { AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear( interactionId); - finalizeAndCacheAccessibilityNodeInfo(info, connectionId, windowScale); + finalizeAndCacheAccessibilityNodeInfo(info, connectionId); return info; } } else { @@ -290,14 +285,13 @@ public final class AccessibilityInteractionClient IAccessibilityServiceConnection connection = getConnection(connectionId); if (connection != null) { final int interactionId = mInteractionIdCounter.getAndIncrement(); - final float windowScale = connection.findAccessibilityNodeInfosByText( + final boolean success = connection.findAccessibilityNodeInfosByText( accessibilityWindowId, accessibilityNodeId, text, interactionId, this, Thread.currentThread().getId()); - // If the scale is zero the call has failed. - if (windowScale > 0) { + if (success) { List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear( interactionId); - finalizeAndCacheAccessibilityNodeInfos(infos, connectionId, windowScale); + finalizeAndCacheAccessibilityNodeInfos(infos, connectionId); return infos; } } else { @@ -336,14 +330,13 @@ public final class AccessibilityInteractionClient IAccessibilityServiceConnection connection = getConnection(connectionId); if (connection != null) { final int interactionId = mInteractionIdCounter.getAndIncrement(); - final float windowScale = connection.findFocus(accessibilityWindowId, + final boolean success = connection.findFocus(accessibilityWindowId, accessibilityNodeId, focusType, interactionId, this, Thread.currentThread().getId()); - // If the scale is zero the call has failed. - if (windowScale > 0) { + if (success) { AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear( interactionId); - finalizeAndCacheAccessibilityNodeInfo(info, connectionId, windowScale); + finalizeAndCacheAccessibilityNodeInfo(info, connectionId); return info; } } else { @@ -381,14 +374,13 @@ public final class AccessibilityInteractionClient IAccessibilityServiceConnection connection = getConnection(connectionId); if (connection != null) { final int interactionId = mInteractionIdCounter.getAndIncrement(); - final float windowScale = connection.focusSearch(accessibilityWindowId, + final boolean success = connection.focusSearch(accessibilityWindowId, accessibilityNodeId, direction, interactionId, this, Thread.currentThread().getId()); - // If the scale is zero the call has failed. - if (windowScale > 0) { + if (success) { AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear( interactionId); - finalizeAndCacheAccessibilityNodeInfo(info, connectionId, windowScale); + finalizeAndCacheAccessibilityNodeInfo(info, connectionId); return info; } } else { @@ -604,36 +596,14 @@ public final class AccessibilityInteractionClient } /** - * Applies compatibility scale to the info bounds if it is not equal to one. - * - * @param info The info whose bounds to scale. - * @param scale The scale to apply. - */ - private void applyCompatibilityScaleIfNeeded(AccessibilityNodeInfo info, float scale) { - if (scale == 1.0f) { - return; - } - Rect bounds = mTempBounds; - info.getBoundsInParent(bounds); - bounds.scale(scale); - info.setBoundsInParent(bounds); - - info.getBoundsInScreen(bounds); - bounds.scale(scale); - info.setBoundsInScreen(bounds); - } - - /** * Finalize an {@link AccessibilityNodeInfo} before passing it to the client. * * @param info The info. * @param connectionId The id of the connection to the system. - * @param windowScale The source window compatibility scale. */ - private void finalizeAndCacheAccessibilityNodeInfo(AccessibilityNodeInfo info, int connectionId, - float windowScale) { + private void finalizeAndCacheAccessibilityNodeInfo(AccessibilityNodeInfo info, + int connectionId) { if (info != null) { - applyCompatibilityScaleIfNeeded(info, windowScale); info.setConnectionId(connectionId); info.setSealed(true); sAccessibilityNodeInfoCache.add(info); @@ -645,15 +615,14 @@ public final class AccessibilityInteractionClient * * @param infos The {@link AccessibilityNodeInfo}s. * @param connectionId The id of the connection to the system. - * @param windowScale The source window compatibility scale. */ private void finalizeAndCacheAccessibilityNodeInfos(List<AccessibilityNodeInfo> infos, - int connectionId, float windowScale) { + int connectionId) { if (infos != null) { final int infosCount = infos.size(); for (int i = 0; i < infosCount; i++) { AccessibilityNodeInfo info = infos.get(i); - finalizeAndCacheAccessibilityNodeInfo(info, connectionId, windowScale); + finalizeAndCacheAccessibilityNodeInfo(info, connectionId); } } } diff --git a/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl b/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl index 9b39300..c313b07 100644 --- a/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl +++ b/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl @@ -17,6 +17,7 @@ package android.view.accessibility; import android.os.Bundle; +import android.view.MagnificationSpec; import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.IAccessibilityInteractionConnectionCallback; @@ -30,23 +31,23 @@ oneway interface IAccessibilityInteractionConnection { void findAccessibilityNodeInfoByAccessibilityId(long accessibilityNodeId, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, - long interrogatingTid); + long interrogatingTid, in MagnificationSpec spec); void findAccessibilityNodeInfoByViewId(long accessibilityNodeId, int viewId, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, - long interrogatingTid); + long interrogatingTid, in MagnificationSpec spec); void findAccessibilityNodeInfosByText(long accessibilityNodeId, String text, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, - long interrogatingTid); + long interrogatingTid, in MagnificationSpec spec); void findFocus(long accessibilityNodeId, int focusType, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, - long interrogatingTid); + long interrogatingTid, in MagnificationSpec spec); void focusSearch(long accessibilityNodeId, int direction, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, - long interrogatingTid); + long interrogatingTid, in MagnificationSpec spec); void performAccessibilityAction(long accessibilityNodeId, int action, in Bundle arguments, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, diff --git a/core/java/com/android/internal/policy/PolicyManager.java b/core/java/com/android/internal/policy/PolicyManager.java index 5274e54..462b3a9 100644 --- a/core/java/com/android/internal/policy/PolicyManager.java +++ b/core/java/com/android/internal/policy/PolicyManager.java @@ -22,8 +22,6 @@ import android.view.LayoutInflater; import android.view.Window; import android.view.WindowManagerPolicy; -import com.android.internal.policy.IPolicy; - /** * {@hide} */ diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index e978a8f..6262e4b 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -4520,19 +4520,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { } @Override - public boolean canMagnifyWindowLw(WindowManager.LayoutParams attrs) { - switch (attrs.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; - } - - @Override public void setCurrentUserLw(int newUserId) { if (mKeyguardMediator != null) { mKeyguardMediator.setCurrentUser(newUserId); @@ -4552,6 +4539,71 @@ public class PhoneWindowManager implements WindowManagerPolicy { mKeyguardMediator.showAssistant(); } + /** + * Returns the human readable name of a window transition. + * + * @param transition The window transition. + * @return The transition symbolic name. + */ + public static 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>"; + } + } + } + @Override public void dump(String prefix, PrintWriter pw, String[] args) { pw.print(prefix); pw.print("mSafeMode="); pw.print(mSafeMode); diff --git a/policy/src/com/android/internal/policy/impl/Policy.java b/policy/src/com/android/internal/policy/impl/Policy.java index 153ef0f..42bfc5f 100644 --- a/policy/src/com/android/internal/policy/impl/Policy.java +++ b/policy/src/com/android/internal/policy/impl/Policy.java @@ -24,9 +24,6 @@ import android.view.Window; import android.view.WindowManagerPolicy; import com.android.internal.policy.IPolicy; -import com.android.internal.policy.impl.PhoneLayoutInflater; -import com.android.internal.policy.impl.PhoneWindow; -import com.android.internal.policy.impl.PhoneWindowManager; /** * {@hide} 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? diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java index 3e625f9..141b323 100644 --- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java +++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java @@ -22,6 +22,7 @@ import com.android.internal.view.IInputMethodClient; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.graphics.Bitmap; +import android.graphics.Rect; import android.os.Bundle; import android.os.IBinder; import android.os.IRemoteCallback; @@ -30,13 +31,11 @@ import android.util.DisplayMetrics; import android.view.Display; import android.view.Gravity; import android.view.IApplicationToken; -import android.view.IDisplayContentChangeListener; import android.view.IInputFilter; import android.view.IOnKeyguardExitResult; import android.view.IRotationWatcher; import android.view.IWindowManager; import android.view.IWindowSession; -import android.view.WindowInfo; import java.util.List; @@ -446,7 +445,7 @@ public class IWindowManagerImpl implements IWindowManager { public void lockNow(Bundle options) { // TODO Auto-generated method stub } - + @Override public boolean isSafeModeEnabled() { return false; @@ -464,43 +463,18 @@ public class IWindowManagerImpl implements IWindowManager { } @Override - public float getWindowCompatibilityScale(IBinder windowToken) throws RemoteException { - // TODO Auto-generated method stub - return 0; - } - - @Override public void setInputFilter(IInputFilter filter) throws RemoteException { // TODO Auto-generated method stub } @Override - public void magnifyDisplay(int dipslayId, float scale, float offsetX, float offsetY) - throws RemoteException { - // TODO Auto-generated method stub - } - - @Override - public void addDisplayContentChangeListener(int displayId, - IDisplayContentChangeListener listener) throws RemoteException { - // TODO Auto-generated method stub - } - - @Override - public void removeDisplayContentChangeListener(int displayId, - IDisplayContentChangeListener listener) throws RemoteException { - // TODO Auto-generated method stub - } - - @Override - public WindowInfo getWindowInfo(IBinder token) throws RemoteException { + public IDisplayMagnificationMediator getDisplayMagnificationMediator() { // TODO Auto-generated method stub return null; } @Override - public void getVisibleWindowsForDisplay(int displayId, List<WindowInfo> outInfos) - throws RemoteException { + public void getWindowFrame(IBinder token, Rect outFrame) { // TODO Auto-generated method stub } } |