Merge "Waits for windowMagnification connection set when requesting enableWindowMagnification" into tm-dev

This commit is contained in:
Minche Li
2022-03-02 01:09:36 +00:00
committed by Android (Google) Code Review
9 changed files with 154 additions and 19 deletions

View File

@@ -2749,6 +2749,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
} }
private void updateWindowMagnificationConnectionIfNeeded(AccessibilityUserState userState) { private void updateWindowMagnificationConnectionIfNeeded(AccessibilityUserState userState) {
if (!mMagnificationController.supportWindowMagnification()) {
return;
}
final boolean connect = (userState.isShortcutMagnificationEnabledLocked() final boolean connect = (userState.isShortcutMagnificationEnabledLocked()
|| userState.isDisplayMagnificationEnabledLocked()) || userState.isDisplayMagnificationEnabledLocked())
&& (userState.getMagnificationCapabilitiesLocked() && (userState.getMagnificationCapabilitiesLocked()

View File

@@ -17,6 +17,7 @@
package com.android.server.accessibility.magnification; package com.android.server.accessibility.magnification;
import static android.accessibilityservice.MagnificationConfig.MAGNIFICATION_MODE_WINDOW; import static android.accessibilityservice.MagnificationConfig.MAGNIFICATION_MODE_WINDOW;
import static android.content.pm.PackageManager.FEATURE_WINDOW_MAGNIFICATION;
import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL; import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL;
import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN; import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_NONE; import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_NONE;
@@ -91,6 +92,8 @@ public class MagnificationController implements WindowMagnificationManager.Callb
private FullScreenMagnificationController mFullScreenMagnificationController; private FullScreenMagnificationController mFullScreenMagnificationController;
private WindowMagnificationManager mWindowMagnificationMgr; private WindowMagnificationManager mWindowMagnificationMgr;
private int mMagnificationCapabilities = ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN; private int mMagnificationCapabilities = ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
/** Whether the platform supports window magnification feature. */
private final boolean mSupportWindowMagnification;
@GuardedBy("mLock") @GuardedBy("mLock")
private int mActivatedMode = ACCESSIBILITY_MAGNIFICATION_MODE_NONE; private int mActivatedMode = ACCESSIBILITY_MAGNIFICATION_MODE_NONE;
@@ -129,6 +132,8 @@ public class MagnificationController implements WindowMagnificationManager.Callb
mScaleProvider = scaleProvider; mScaleProvider = scaleProvider;
LocalServices.getService(WindowManagerInternal.class) LocalServices.getService(WindowManagerInternal.class)
.getAccessibilityController().setUiChangesForAccessibilityCallbacks(this); .getAccessibilityController().setUiChangesForAccessibilityCallbacks(this);
mSupportWindowMagnification = context.getPackageManager().hasSystemFeature(
FEATURE_WINDOW_MAGNIFICATION);
} }
@VisibleForTesting @VisibleForTesting
@@ -185,6 +190,11 @@ public class MagnificationController implements WindowMagnificationManager.Callb
} }
} }
/** Returns {@code true} if the platform supports window magnification feature. */
public boolean supportWindowMagnification() {
return mSupportWindowMagnification;
}
/** /**
* Transitions to the target Magnification mode with current center of the magnification mode * Transitions to the target Magnification mode with current center of the magnification mode
* if it is available. * if it is available.

View File

@@ -396,6 +396,10 @@ public class MagnificationProcessor {
dumpTrackingTypingFocusEnabledState(pw, displayId, config.getMode()); dumpTrackingTypingFocusEnabledState(pw, displayId, config.getMode());
} }
pw.append(" SupportWindowMagnification="
+ mController.supportWindowMagnification()).println();
pw.append(" WindowMagnificationConnectionState="
+ mController.getWindowMagnificationMgr().getConnectionState()).println();
} }
private int getIdOfLastServiceToMagnify(int mode, int displayId) { private int getIdOfLastServiceToMagnify(int mode, int displayId) {

View File

@@ -36,6 +36,7 @@ import android.graphics.Region;
import android.os.Binder; import android.os.Binder;
import android.os.IBinder; import android.os.IBinder;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.SystemClock;
import android.util.Slog; import android.util.Slog;
import android.util.SparseArray; import android.util.SparseArray;
import android.view.MotionEvent; import android.view.MotionEvent;
@@ -87,6 +88,30 @@ public class WindowMagnificationManager implements
}) })
public @interface WindowPosition {} public @interface WindowPosition {}
/** Window magnification connection is connecting. */
private static final int CONNECTING = 0;
/** Window magnification connection is connected. */
private static final int CONNECTED = 1;
/** Window magnification connection is disconnecting. */
private static final int DISCONNECTING = 2;
/** Window magnification connection is disconnected. */
private static final int DISCONNECTED = 3;
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = {"CONNECTION_STATE"}, value = {
CONNECTING,
CONNECTED,
DISCONNECTING,
DISCONNECTED
})
private @interface ConnectionState {
}
@ConnectionState
private int mConnectionState = DISCONNECTED;
private static final int WAIT_CONNECTION_TIMEOUT_MILLIS = 100;
private final Object mLock; private final Object mLock;
private final Context mContext; private final Context mContext;
@VisibleForTesting @VisibleForTesting
@@ -178,7 +203,7 @@ public class WindowMagnificationManager implements
*/ */
public void setConnection(@Nullable IWindowMagnificationConnection connection) { public void setConnection(@Nullable IWindowMagnificationConnection connection) {
if (DBG) { if (DBG) {
Slog.d(TAG, "setConnection :" + connection); Slog.d(TAG, "setConnection :" + connection + " ,mConnectionState=" + mConnectionState);
} }
synchronized (mLock) { synchronized (mLock) {
// Reset connectionWrapper. // Reset connectionWrapper.
@@ -189,6 +214,13 @@ public class WindowMagnificationManager implements
} }
mConnectionWrapper.unlinkToDeath(mConnectionCallback); mConnectionWrapper.unlinkToDeath(mConnectionCallback);
mConnectionWrapper = null; mConnectionWrapper = null;
// The connection is still connecting so it is no need to reset the
// connection state to disconnected.
// TODO b/220086369 will reset the connection immediately when requestConnection
// is called
if (mConnectionState != CONNECTING) {
setConnectionState(DISCONNECTED);
}
} }
if (connection != null) { if (connection != null) {
mConnectionWrapper = new WindowMagnificationConnectionWrapper(connection, mTrace); mConnectionWrapper = new WindowMagnificationConnectionWrapper(connection, mTrace);
@@ -199,9 +231,13 @@ public class WindowMagnificationManager implements
mConnectionCallback = new ConnectionCallback(); mConnectionCallback = new ConnectionCallback();
mConnectionWrapper.linkToDeath(mConnectionCallback); mConnectionWrapper.linkToDeath(mConnectionCallback);
mConnectionWrapper.setConnectionCallback(mConnectionCallback); mConnectionWrapper.setConnectionCallback(mConnectionCallback);
setConnectionState(CONNECTED);
} catch (RemoteException e) { } catch (RemoteException e) {
Slog.e(TAG, "setConnection failed", e); Slog.e(TAG, "setConnection failed", e);
mConnectionWrapper = null; mConnectionWrapper = null;
setConnectionState(DISCONNECTED);
} finally {
mLock.notify();
} }
} }
} }
@@ -229,10 +265,20 @@ public class WindowMagnificationManager implements
if (DBG) { if (DBG) {
Slog.d(TAG, "requestConnection :" + connect); Slog.d(TAG, "requestConnection :" + connect);
} }
if (mTrace.isA11yTracingEnabledForTypes(FLAGS_WINDOW_MAGNIFICATION_CONNECTION)) {
mTrace.logTrace(TAG + ".requestWindowMagnificationConnection",
FLAGS_WINDOW_MAGNIFICATION_CONNECTION, "connect=" + connect);
}
synchronized (mLock) { synchronized (mLock) {
if (connect == isConnected()) { if ((connect && (mConnectionState == CONNECTED || mConnectionState == CONNECTING))
|| (!connect && (mConnectionState == DISCONNECTED
|| mConnectionState == DISCONNECTING))) {
Slog.w(TAG,
"requestConnection duplicated request: connect=" + connect
+ " ,mConnectionState=" + mConnectionState);
return false; return false;
} }
if (connect) { if (connect) {
final IntentFilter intentFilter = new IntentFilter(Intent.ACTION_SCREEN_OFF); final IntentFilter intentFilter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
if (!mReceiverRegistered) { if (!mReceiverRegistered) {
@@ -247,19 +293,42 @@ public class WindowMagnificationManager implements
} }
} }
} }
if (mTrace.isA11yTracingEnabledForTypes(FLAGS_WINDOW_MAGNIFICATION_CONNECTION)) { if (requestConnectionInternal(connect)) {
mTrace.logTrace(TAG + ".requestWindowMagnificationConnection", setConnectionState(connect ? CONNECTING : DISCONNECTING);
FLAGS_WINDOW_MAGNIFICATION_CONNECTION, "connect=" + connect); return true;
} else {
setConnectionState(DISCONNECTED);
return false;
} }
}
private boolean requestConnectionInternal(boolean connect) {
final long identity = Binder.clearCallingIdentity(); final long identity = Binder.clearCallingIdentity();
try { try {
final StatusBarManagerInternal service = LocalServices.getService( final StatusBarManagerInternal service = LocalServices.getService(
StatusBarManagerInternal.class); StatusBarManagerInternal.class);
service.requestWindowMagnificationConnection(connect); if (service != null) {
return service.requestWindowMagnificationConnection(connect);
}
} finally { } finally {
Binder.restoreCallingIdentity(identity); Binder.restoreCallingIdentity(identity);
} }
return true; return false;
}
/**
* Returns window magnification connection state.
*/
public int getConnectionState() {
return mConnectionState;
}
private void setConnectionState(@ConnectionState int state) {
if (DBG) {
Slog.d(TAG, "setConnectionState : state=" + state + " ,mConnectionState="
+ mConnectionState);
}
mConnectionState = state;
} }
/** /**
@@ -849,6 +918,7 @@ public class WindowMagnificationManager implements
mConnectionWrapper.unlinkToDeath(this); mConnectionWrapper.unlinkToDeath(this);
mConnectionWrapper = null; mConnectionWrapper = null;
mConnectionCallback = null; mConnectionCallback = null;
setConnectionState(DISCONNECTED);
resetWindowMagnifiers(); resetWindowMagnifiers();
} }
} }
@@ -1025,8 +1095,19 @@ public class WindowMagnificationManager implements
float centerY, float magnificationFrameOffsetRatioX, float centerY, float magnificationFrameOffsetRatioX,
float magnificationFrameOffsetRatioY, float magnificationFrameOffsetRatioY,
MagnificationAnimationCallback animationCallback) { MagnificationAnimationCallback animationCallback) {
// Wait for the connection with a timeout.
final long endMillis = SystemClock.uptimeMillis() + WAIT_CONNECTION_TIMEOUT_MILLIS;
while (mConnectionState == CONNECTING && (SystemClock.uptimeMillis() < endMillis)) {
try {
mLock.wait(endMillis - SystemClock.uptimeMillis());
} catch (InterruptedException ie) {
/* ignore */
}
}
if (mConnectionWrapper == null) { if (mConnectionWrapper == null) {
Slog.w(TAG, "enableWindowMagnificationInternal mConnectionWrapper is null"); Slog.w(TAG,
"enableWindowMagnificationInternal mConnectionWrapper is null. "
+ "mConnectionState=" + mConnectionState);
return false; return false;
} }
return mConnectionWrapper.enableWindowMagnification( return mConnectionWrapper.enableWindowMagnification(

View File

@@ -157,7 +157,7 @@ public interface StatusBarManagerInternal {
* @see com.android.internal.statusbar.IStatusBar#requestWindowMagnificationConnection(boolean * @see com.android.internal.statusbar.IStatusBar#requestWindowMagnificationConnection(boolean
* request) * request)
*/ */
void requestWindowMagnificationConnection(boolean request); boolean requestWindowMagnificationConnection(boolean request);
/** /**
* Handles a logging command from the WM shell command. * Handles a logging command from the WM shell command.

View File

@@ -637,12 +637,14 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
} }
@Override @Override
public void requestWindowMagnificationConnection(boolean request) { public boolean requestWindowMagnificationConnection(boolean request) {
if (mBar != null) { if (mBar != null) {
try { try {
mBar.requestWindowMagnificationConnection(request); mBar.requestWindowMagnificationConnection(request);
return true;
} catch (RemoteException ex) { } } catch (RemoteException ex) { }
} }
return false;
} }
@Override @Override

View File

@@ -154,6 +154,7 @@ public class AccessibilityManagerServiceTest {
mMockWindowMagnificationMgr); mMockWindowMagnificationMgr);
when(mMockMagnificationController.getFullScreenMagnificationController()).thenReturn( when(mMockMagnificationController.getFullScreenMagnificationController()).thenReturn(
mMockFullScreenMagnificationController); mMockFullScreenMagnificationController);
when(mMockMagnificationController.supportWindowMagnification()).thenReturn(true);
when(mMockWindowManagerService.getAccessibilityController()).thenReturn( when(mMockWindowManagerService.getAccessibilityController()).thenReturn(
mMockA11yController); mMockA11yController);
when(mMockA11yController.isAccessibilityTracingEnabled()).thenReturn(false); when(mMockA11yController.isAccessibilityTracingEnabled()).thenReturn(false);

View File

@@ -41,6 +41,7 @@ import static org.mockito.Mockito.when;
import android.accessibilityservice.MagnificationConfig; import android.accessibilityservice.MagnificationConfig;
import android.content.Context; import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.PointF; import android.graphics.PointF;
import android.graphics.Rect; import android.graphics.Rect;
import android.graphics.Region; import android.graphics.Region;
@@ -100,6 +101,8 @@ public class MagnificationControllerTest {
@Mock @Mock
private Context mContext; private Context mContext;
@Mock @Mock
PackageManager mPackageManager;
@Mock
private FullScreenMagnificationController mScreenMagnificationController; private FullScreenMagnificationController mScreenMagnificationController;
private MagnificationScaleProvider mScaleProvider; private MagnificationScaleProvider mScaleProvider;
@Captor @Captor
@@ -136,6 +139,7 @@ public class MagnificationControllerTest {
mMockResolver = new MockContentResolver(); mMockResolver = new MockContentResolver();
mMockResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider()); mMockResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
when(mContext.getContentResolver()).thenReturn(mMockResolver); when(mContext.getContentResolver()).thenReturn(mMockResolver);
when(mContext.getPackageManager()).thenReturn(mPackageManager);
Settings.Secure.putFloatForUser(mMockResolver, Settings.Secure.putFloatForUser(mMockResolver,
Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, DEFAULT_SCALE, Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, DEFAULT_SCALE,
CURRENT_USER_ID); CURRENT_USER_ID);

View File

@@ -54,6 +54,8 @@ import android.view.accessibility.IRemoteMagnificationAnimationCallback;
import android.view.accessibility.IWindowMagnificationConnectionCallback; import android.view.accessibility.IWindowMagnificationConnectionCallback;
import android.view.accessibility.MagnificationAnimationCallback; import android.view.accessibility.MagnificationAnimationCallback;
import androidx.test.core.app.ApplicationProvider;
import com.android.internal.util.test.FakeSettingsProvider; import com.android.internal.util.test.FakeSettingsProvider;
import com.android.server.LocalServices; import com.android.server.LocalServices;
import com.android.server.accessibility.AccessibilityTraceManager; import com.android.server.accessibility.AccessibilityTraceManager;
@@ -99,12 +101,7 @@ public class WindowMagnificationManagerTest {
mMockCallback, mMockTrace, new MagnificationScaleProvider(mContext)); mMockCallback, mMockTrace, new MagnificationScaleProvider(mContext));
when(mContext.getContentResolver()).thenReturn(mResolver); when(mContext.getContentResolver()).thenReturn(mResolver);
doAnswer((InvocationOnMock invocation) -> { stubSetConnection(false);
final boolean connect = (Boolean) invocation.getArguments()[0];
mWindowMagnificationManager.setConnection(
connect ? mMockConnection.getConnection() : null);
return null;
}).when(mMockStatusBarManagerInternal).requestWindowMagnificationConnection(anyBoolean());
mResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider()); mResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
Settings.Secure.putFloatForUser(mResolver, Settings.Secure.putFloatForUser(mResolver,
@@ -112,6 +109,25 @@ public class WindowMagnificationManagerTest {
CURRENT_USER_ID); CURRENT_USER_ID);
} }
private void stubSetConnection(boolean needDelay) {
doAnswer((InvocationOnMock invocation) -> {
final boolean connect = (Boolean) invocation.getArguments()[0];
// Simulates setConnection() called by another process.
if (needDelay) {
final Context context = ApplicationProvider.getApplicationContext();
context.getMainThreadHandler().postDelayed(
() -> {
mWindowMagnificationManager.setConnection(
connect ? mMockConnection.getConnection() : null);
}, 10);
} else {
mWindowMagnificationManager.setConnection(
connect ? mMockConnection.getConnection() : null);
}
return true;
}).when(mMockStatusBarManagerInternal).requestWindowMagnificationConnection(anyBoolean());
}
@Test @Test
public void setConnection_connectionIsNull_wrapperIsNullAndLinkToDeath() { public void setConnection_connectionIsNull_wrapperIsNullAndLinkToDeath() {
mWindowMagnificationManager.setConnection(mMockConnection.getConnection()); mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
@@ -464,7 +480,7 @@ public class WindowMagnificationManagerTest {
public void public void
requestConnectionToNull_disableAllMagnifiersAndRequestWindowMagnificationConnection() requestConnectionToNull_disableAllMagnifiersAndRequestWindowMagnificationConnection()
throws RemoteException { throws RemoteException {
mWindowMagnificationManager.setConnection(mMockConnection.getConnection()); assertTrue(mWindowMagnificationManager.requestConnection(true));
mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 3f, NaN, NaN); mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 3f, NaN, NaN);
assertTrue(mWindowMagnificationManager.requestConnection(false)); assertTrue(mWindowMagnificationManager.requestConnection(false));
@@ -499,7 +515,7 @@ public class WindowMagnificationManagerTest {
@Test @Test
public void requestConnectionToNull_expectedGetterResults() { public void requestConnectionToNull_expectedGetterResults() {
mWindowMagnificationManager.setConnection(mMockConnection.getConnection()); mWindowMagnificationManager.requestConnection(true);
mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 3f, 1, 1); mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 3f, 1, 1);
mWindowMagnificationManager.requestConnection(false); mWindowMagnificationManager.requestConnection(false);
@@ -512,6 +528,20 @@ public class WindowMagnificationManagerTest {
assertTrue(bounds.isEmpty()); assertTrue(bounds.isEmpty());
} }
@Test
public void enableWindowMagnification_connecting_invokeConnectionMethodAfterConnected()
throws RemoteException {
stubSetConnection(true);
mWindowMagnificationManager.requestConnection(true);
assertTrue(mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 3f, 1, 1));
// Invoke enableWindowMagnification if the connection is connected.
verify(mMockConnection.getConnection()).enableWindowMagnification(
eq(TEST_DISPLAY), eq(3f),
eq(1f), eq(1f), eq(0f), eq(0f), notNull());
}
@Test @Test
public void resetAllMagnification_enabledBySameId_windowMagnifiersDisabled() { public void resetAllMagnification_enabledBySameId_windowMagnifiersDisabled() {
mWindowMagnificationManager.setConnection(mMockConnection.getConnection()); mWindowMagnificationManager.setConnection(mMockConnection.getConnection());