diff options
author | Svetoslav Ganov <svetoslavganov@google.com> | 2012-10-12 20:15:29 -0700 |
---|---|---|
committer | Svetoslav Ganov <svetoslavganov@google.com> | 2012-12-03 10:38:48 -0800 |
commit | 152e9bb81aa5b2ab4637f4b2dae04b3ce89fa891 (patch) | |
tree | 8e955c6db3279776dc6795e125513c4f2877ea44 /core/java/android/view | |
parent | 4d58730ff587645778636e87312b1b17846fcac9 (diff) | |
download | frameworks_base-152e9bb81aa5b2ab4637f4b2dae04b3ce89fa891.zip frameworks_base-152e9bb81aa5b2ab4637f4b2dae04b3ce89fa891.tar.gz frameworks_base-152e9bb81aa5b2ab4637f4b2dae04b3ce89fa891.tar.bz2 |
Refactoring of the screen magnification feature.
1. The screen magnification feature was implemented entirely as a part of the accessibility
manager. To achieve that the window manager had to implement a bunch of hooks for an
external client to observe its internal state. This was problematic since it dilutes
the window manager interface and allows code that is deeply coupled with the window
manager to reside outside of it. Also the observer callbacks were IPCs which cannot
be called with the window manager's lock held. To avoid that the window manager had
to post messages requesting notification of interested parties which makes the code
consuming the callbacks to run asynchronously of the window manager. This causes timing
issues and adds unnecessary complexity.
Now the magnification logic is split in two halves. The first half that is responsible
to track the magnified portion of the screen and serve as a policy which windows can be
magnified and it is a part of the window manager. This part exposes higher level APIs
allowing interested parties with the right permissions to control the magnification
of a given display. The APIs also allow a client to be registered for callbacks on
interesting changes such as resize of the magnified region, etc. This part servers
as a mediator between magnification controllers and the window manager.
The second half is a controller that is responsible to drive the magnification
state based on touch interactions. It also presents a highlight when magnified to
suggest the magnified potion of the screen. The controller is responsible for auto
zooming out in case the user context changes - rotation, new actitivity. The controller
also auto pans if a dialog appears and it does not interesect the magnified frame.
bug:7410464
2. By design screen magnification and touch exploration work separately and together. If
magnification is enabled the user sees a larger version of the widgets and a sub section
of the screen content. Accessibility services use the introspection APIs to "see" what
is on the screen so they can speak it, navigate to the next item in response to a
gesture, etc. Hence, the information returned to accessibility services has to reflect
what a sighted user would see on the screen. Therefore, if the screen is magnified
we need to adjust the bounds and position of the infos describing views in a magnified
window such that the info bounds are equivalent to what the user sees.
To improve performance we keep accessibility node info caches in the client process.
However, when magnification state changes we have to clear these caches since the
bounds of the cached infos no longer reflect the screen content which just got smaller
or larger.
This patch propagates not only the window scale as before but also the X/Y pan and the
bounds of the magnified portion of the screen to the introspected app. This information
is used to adjust the bounds of the node infos coming from this window such that the
reported bounds are the same as the user sees not as the app thinks they are. Note that
if magnification is enabled we zoom the content and pan it along the X and Y axis. Also
recomputed is the isVisibleToUser property of the reported info since in a magnified
state the user sees a subset of the window content and the views not in the magnified
viewport should be reported as not visible to the user.
bug:7344059
Change-Id: I6f7832c7a6a65c5368b390eb1f1518d0c7afd7d2
Diffstat (limited to 'core/java/android/view')
-rw-r--r-- | core/java/android/view/AccessibilityInteractionController.java | 120 | ||||
-rw-r--r-- | core/java/android/view/IDisplayMagnificationController.aidl (renamed from core/java/android/view/IDisplayContentChangeListener.aidl) | 16 | ||||
-rw-r--r-- | core/java/android/view/IDisplayMagnificationMediator.aidl | 31 | ||||
-rw-r--r-- | core/java/android/view/IWindowManager.aidl | 32 | ||||
-rw-r--r-- | core/java/android/view/MagnificationSpec.aidl (renamed from core/java/android/view/WindowInfo.aidl) | 2 | ||||
-rw-r--r-- | core/java/android/view/MagnificationSpec.java | 120 | ||||
-rw-r--r-- | core/java/android/view/Surface.java | 26 | ||||
-rw-r--r-- | core/java/android/view/ViewRootImpl.java | 23 | ||||
-rw-r--r-- | core/java/android/view/WindowInfo.java | 175 | ||||
-rw-r--r-- | core/java/android/view/WindowManagerPolicy.java | 8 | ||||
-rw-r--r-- | core/java/android/view/accessibility/AccessibilityInteractionClient.java | 73 | ||||
-rw-r--r-- | core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl | 11 |
12 files changed, 326 insertions, 311 deletions
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, |