From ba834b2136ac1efd95d4c445ed317a7708a21e4d Mon Sep 17 00:00:00 2001 From: ryanlwlin Date: Thu, 27 Feb 2020 15:56:18 +0800 Subject: [PATCH] Add method to request window magnification connection This method is used by Accessibility framwork to request window magnification connection. When it is called, the connection will be set by AccessibilityManager#setWindowMagnificationConnection. Bug: 136250281 Test: IWindowMagnificationConnectionTest, WindowMagnificationTest Change-Id: Ib4b3c6d7cf90a6c2c1d26029f990285466ff6419 --- .../internal/statusbar/IStatusBar.aidl | 8 ++ .../accessibility/WindowMagnification.java | 49 +++++++- .../systemui/statusbar/CommandQueue.java | 23 ++++ .../IWindowMagnificationConnectionTest.java | 118 ++++++++++++++++++ .../WindowMagnificationTest.java | 97 ++++++++++++++ .../systemui/statusbar/CommandQueueTest.java | 7 ++ .../statusbar/StatusBarManagerInternal.java | 6 + .../statusbar/StatusBarManagerService.java | 9 ++ 8 files changed, 311 insertions(+), 6 deletions(-) create mode 100644 packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl index 380a20c88d569..f2f82a03ae16d 100644 --- a/core/java/com/android/internal/statusbar/IStatusBar.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl @@ -226,4 +226,12 @@ oneway interface IStatusBar * display. */ void suppressAmbientDisplay(boolean suppress); + + /** + * Requests {@link WindowMagnification} to set window magnification connection through + * {@link AccessibilityManager#setWindowMagnificationConnection(IWindowMagnificationConnection)} + * + * @param connect {@code true} if needs connection, otherwise set the connection to null. + */ + void requestWindowMagnificationConnection(boolean connect); } diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java index 826b4b3daef2a..8cd7293d27342 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java @@ -28,37 +28,50 @@ import android.os.RemoteException; import android.provider.Settings; import android.util.Log; import android.view.Display; +import android.view.accessibility.AccessibilityManager; import android.view.accessibility.IWindowMagnificationConnection; import android.view.accessibility.IWindowMagnificationConnectionCallback; +import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.R; import com.android.systemui.SystemUI; import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.statusbar.CommandQueue; import javax.inject.Inject; import javax.inject.Singleton; /** - * Class to handle changes to setting window_magnification value. + * Class to handle the interaction with + * {@link com.android.server.accessibility.AccessibilityManagerService}. It invokes + * {@link AccessibilityManager#setWindowMagnificationConnection(IWindowMagnificationConnection)} + * when {@code IStatusBar#requestWindowMagnificationConnection(boolean)} is called. */ @Singleton -public class WindowMagnification extends SystemUI implements WindowMagnifierCallback { +public class WindowMagnification extends SystemUI implements WindowMagnifierCallback, + CommandQueue.Callbacks { private static final String TAG = "WindowMagnification"; private static final int CONFIG_MASK = ActivityInfo.CONFIG_DENSITY | ActivityInfo.CONFIG_ORIENTATION; - private WindowMagnificationController mWindowMagnificationController; + @VisibleForTesting + protected WindowMagnificationController mWindowMagnificationController; private final Handler mHandler; - //TODO:Set it by the request from AccessibilityManager. - private WindowMagnificationConnectionImpl mWindowMagnificationConnectionImpl; + private final AccessibilityManager mAccessibilityManager; + private final CommandQueue mCommandQueue; + private WindowMagnificationConnectionImpl mWindowMagnificationConnectionImpl; private Configuration mLastConfiguration; @Inject - public WindowMagnification(Context context, @Main Handler mainHandler) { + public WindowMagnification(Context context, @Main Handler mainHandler, + CommandQueue commandQueue) { super(context); mHandler = mainHandler; mLastConfiguration = new Configuration(context.getResources().getConfiguration()); + mAccessibilityManager = (AccessibilityManager) mContext.getSystemService( + Context.ACCESSIBILITY_SERVICE); + mCommandQueue = commandQueue; } @Override @@ -75,6 +88,7 @@ public class WindowMagnification extends SystemUI implements WindowMagnifierCall @Override public void start() { + mCommandQueue.addCallback(this); mContext.getContentResolver().registerContentObserver( Settings.Secure.getUriFor(Settings.Secure.WINDOW_MAGNIFICATION), true, new ContentObserver(mHandler) { @@ -150,6 +164,29 @@ public class WindowMagnification extends SystemUI implements WindowMagnifierCall } } + @Override + public void requestWindowMagnificationConnection(boolean connect) { + if (connect) { + setWindowMagnificationConnection(); + } else { + clearWindowMagnificationConnection(); + } + } + + private void setWindowMagnificationConnection() { + if (mWindowMagnificationConnectionImpl == null) { + mWindowMagnificationConnectionImpl = new WindowMagnificationConnectionImpl(this, + mHandler); + } + mAccessibilityManager.setWindowMagnificationConnection( + mWindowMagnificationConnectionImpl); + } + + private void clearWindowMagnificationConnection() { + mAccessibilityManager.setWindowMagnificationConnection(null); + //TODO: destroy controllers. + } + private static class WindowMagnificationConnectionImpl extends IWindowMagnificationConnection.Stub { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java index 3fe348f3ea029..8cc4ffb319470 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java @@ -126,6 +126,7 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< private static final int MSG_HIDE_TOAST = 54 << MSG_SHIFT; private static final int MSG_TRACING_STATE_CHANGED = 55 << MSG_SHIFT; private static final int MSG_SUPPRESS_AMBIENT_DISPLAY = 56 << MSG_SHIFT; + private static final int MSG_REQUEST_WINDOW_MAGNIFICATION_CONNECTION = 57 << MSG_SHIFT; public static final int FLAG_EXCLUDE_NONE = 0; public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0; @@ -337,6 +338,15 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< * @param enabled */ default void onTracingStateChanged(boolean enabled) { } + + /** + * Requests {@link com.android.systemui.accessibility.WindowMagnification} to invoke + * {@code android.view.accessibility.AccessibilityManager# + * setWindowMagnificationConnection(IWindowMagnificationConnection)} + * + * @param connect {@code true} if needs connection, otherwise set the connection to null. + */ + default void requestWindowMagnificationConnection(boolean connect) { } } public CommandQueue(Context context) { @@ -882,6 +892,14 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< } } + @Override + public void requestWindowMagnificationConnection(boolean connect) { + synchronized (mLock) { + mHandler.obtainMessage(MSG_REQUEST_WINDOW_MAGNIFICATION_CONNECTION, connect) + .sendToTarget(); + } + } + private void handleShowImeButton(int displayId, IBinder token, int vis, int backDisposition, boolean showImeSwitcher, boolean isMultiClientImeEnabled) { if (displayId == INVALID_DISPLAY) return; @@ -1298,6 +1316,11 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< callbacks.suppressAmbientDisplay((boolean) msg.obj); } break; + case MSG_REQUEST_WINDOW_MAGNIFICATION_CONNECTION: + for (int i = 0; i < mCallbacks.size(); i++) { + mCallbacks.get(i).requestWindowMagnificationConnection((Boolean) msg.obj); + } + break; } } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java new file mode 100644 index 0000000000000..492c6107a9878 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2020 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.systemui.accessibility; + +import static org.junit.Assert.assertNotNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.verify; + +import android.content.Context; +import android.os.RemoteException; +import android.testing.AndroidTestingRunner; +import android.view.Display; +import android.view.accessibility.AccessibilityManager; +import android.view.accessibility.IWindowMagnificationConnection; +import android.view.accessibility.IWindowMagnificationConnectionCallback; + +import androidx.test.filters.SmallTest; + +import com.android.systemui.SysuiTestCase; +import com.android.systemui.statusbar.CommandQueue; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +/** + * Tests for {@link android.view.accessibility.IWindowMagnificationConnection} retrieved from + * {@link WindowMagnification} + */ +@SmallTest +@RunWith(AndroidTestingRunner.class) +public class IWindowMagnificationConnectionTest extends SysuiTestCase { + + private static final int TEST_DISPLAY = Display.DEFAULT_DISPLAY; + @Mock + private AccessibilityManager mAccessibilityManager; + @Mock + private CommandQueue mCommandQueue; + @Mock + private IWindowMagnificationConnectionCallback mConnectionCallback; + @Mock + private WindowMagnificationController mWindowMagnificationController; + private IWindowMagnificationConnection mIWindowMagnificationConnection; + private WindowMagnification mWindowMagnification; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + getContext().addMockSystemService(Context.ACCESSIBILITY_SERVICE, mAccessibilityManager); + doAnswer(invocation -> { + mIWindowMagnificationConnection = invocation.getArgument(0); + return null; + }).when(mAccessibilityManager).setWindowMagnificationConnection( + any(IWindowMagnificationConnection.class)); + mWindowMagnification = new WindowMagnification(getContext(), + getContext().getMainThreadHandler(), mCommandQueue); + mWindowMagnification.mWindowMagnificationController = mWindowMagnificationController; + mWindowMagnification.requestWindowMagnificationConnection(true); + assertNotNull(mIWindowMagnificationConnection); + mIWindowMagnificationConnection.setConnectionCallback(mConnectionCallback); + } + + @Test + public void enableWindowMagnification() throws RemoteException { + mIWindowMagnificationConnection.enableWindowMagnification(TEST_DISPLAY, 3.0f, Float.NaN, + Float.NaN); + waitForIdleSync(); + + verify(mWindowMagnificationController).enableWindowMagnification(3.0f, Float.NaN, + Float.NaN); + } + + @Test + public void disableWindowMagnification_deleteWindowMagnification() throws RemoteException { + mIWindowMagnificationConnection.enableWindowMagnification(TEST_DISPLAY, 3.0f, Float.NaN, + Float.NaN); + waitForIdleSync(); + + mIWindowMagnificationConnection.disableWindowMagnification(TEST_DISPLAY); + waitForIdleSync(); + + verify(mWindowMagnificationController).deleteWindowMagnification(); + } + + @Test + public void setScale() throws RemoteException { + mIWindowMagnificationConnection.setScale(TEST_DISPLAY, 3.0f); + waitForIdleSync(); + + verify(mWindowMagnificationController).setScale(3.0f); + } + + @Test + public void moveWindowMagnifier() throws RemoteException { + mIWindowMagnificationConnection.moveWindowMagnifier(TEST_DISPLAY, 100f, 200f); + waitForIdleSync(); + + verify(mWindowMagnificationController).moveWindowMagnifier(100f, 200f); + } +} + diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java new file mode 100644 index 0000000000000..cc76601c8db5c --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2020 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.systemui.accessibility; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.verify; + +import android.content.Context; +import android.graphics.Rect; +import android.os.RemoteException; +import android.testing.AndroidTestingRunner; +import android.view.Display; +import android.view.accessibility.AccessibilityManager; +import android.view.accessibility.IWindowMagnificationConnection; +import android.view.accessibility.IWindowMagnificationConnectionCallback; + +import androidx.test.filters.SmallTest; + +import com.android.systemui.SysuiTestCase; +import com.android.systemui.statusbar.CommandQueue; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +public class WindowMagnificationTest extends SysuiTestCase { + + @Mock + private AccessibilityManager mAccessibilityManager; + private CommandQueue mCommandQueue; + private WindowMagnification mWindowMagnification; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + getContext().addMockSystemService(Context.ACCESSIBILITY_SERVICE, mAccessibilityManager); + + mCommandQueue = new CommandQueue(getContext()); + mWindowMagnification = new WindowMagnification(getContext(), + getContext().getMainThreadHandler(), mCommandQueue); + mWindowMagnification.start(); + } + + @Test + public void requestWindowMagnificationConnection_setWindowMagnificationConnection() { + mCommandQueue.requestWindowMagnificationConnection(true); + waitForIdleSync(); + + verify(mAccessibilityManager).setWindowMagnificationConnection(any( + IWindowMagnificationConnection.class)); + + mCommandQueue.requestWindowMagnificationConnection(false); + waitForIdleSync(); + + verify(mAccessibilityManager).setWindowMagnificationConnection(null); + } + + @Test + public void onWindowMagnifierBoundsChanged() throws RemoteException { + final IWindowMagnificationConnectionCallback connectionCallback = Mockito.mock( + IWindowMagnificationConnectionCallback.class); + final Rect testBounds = new Rect(0, 0, 500, 600); + doAnswer(invocation -> { + IWindowMagnificationConnection connection = invocation.getArgument(0); + connection.setConnectionCallback(connectionCallback); + return null; + }).when(mAccessibilityManager).setWindowMagnificationConnection( + any(IWindowMagnificationConnection.class)); + mCommandQueue.requestWindowMagnificationConnection(true); + waitForIdleSync(); + + mWindowMagnification.onWindowMagnifierBoundsChanged(Display.DEFAULT_DISPLAY, testBounds); + + verify(connectionCallback).onWindowMagnifierBoundsChanged(Display.DEFAULT_DISPLAY, + testBounds); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java index 7c6da630b3bfb..57062f9610257 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java @@ -454,4 +454,11 @@ public class CommandQueueTest extends SysuiTestCase { waitForIdleSync(); verify(mCallbacks).suppressAmbientDisplay(true); } + + @Test + public void testRequestWindowMagnificationConnection() { + mCommandQueue.requestWindowMagnificationConnection(true); + waitForIdleSync(); + verify(mCallbacks).requestWindowMagnificationConnection(true); + } } diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java index d88dccb9afeb2..35329ffe3a4a0 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java @@ -137,4 +137,10 @@ public interface StatusBarManagerInternal { /** @see com.android.internal.statusbar.IStatusBar#hideToast(String, IBinder) */ void hideToast(String packageName, IBinder token); + + /** + * @see com.android.internal.statusbar.IStatusBar#requestWindowMagnificationConnection(boolean + * request) + */ + void requestWindowMagnificationConnection(boolean request); } diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index 84cd4cfd67beb..3164b69f0e516 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -520,6 +520,15 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D } catch (RemoteException ex) { } } } + + @Override + public void requestWindowMagnificationConnection(boolean request) { + if (mBar != null) { + try { + mBar.requestWindowMagnificationConnection(request); + } catch (RemoteException ex) { } + } + } }; private final GlobalActionsProvider mGlobalActionsProvider = new GlobalActionsProvider() {