Loading core/java/android/view/accessibility/AccessibilityManager.java +46 −0 Original line number Diff line number Diff line Loading @@ -1050,6 +1050,52 @@ public final class AccessibilityManager { } } /** * Registers callback for when user initialization has completed. * Does nothing if the same callback is already registered. * * @param callback The callback to be registered * @hide */ public void registerUserInitializationCompleteCallback( @NonNull IUserInitializationCompleteCallback callback) { IAccessibilityManager service; synchronized (mLock) { service = getServiceLocked(); if (service == null) { return; } } try { service.registerUserInitializationCompleteCallback(callback); } catch (RemoteException re) { Log.e(LOG_TAG, "Error while registering userInitializationCompleteCallback. ", re); } } /** * Unregisters callback for when user initialization has completed. * * @param callback The callback to be unregistered * @hide */ public void unregisterUserInitializationCompleteCallback( @NonNull IUserInitializationCompleteCallback callback) { IAccessibilityManager service; synchronized (mLock) { service = getServiceLocked(); if (service == null) { return; } } try { service.unregisterUserInitializationCompleteCallback(callback); } catch (RemoteException re) { Log.e(LOG_TAG, "Error while unregistering userInitializationCompleteCallback. ", re); } } /** * Whether the current accessibility request comes from an * {@link AccessibilityService} with the {@link AccessibilityServiceInfo#isAccessibilityTool} Loading core/java/android/view/accessibility/IAccessibilityManager.aidl +7 −0 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ import android.view.accessibility.IAccessibilityInteractionConnection; import android.view.accessibility.IAccessibilityManagerClient; import android.view.accessibility.AccessibilityWindowAttributes; import android.view.accessibility.IMagnificationConnection; import android.view.accessibility.IUserInitializationCompleteCallback; import android.view.InputEvent; import android.view.IWindow; import android.view.MagnificationSpec; Loading Loading @@ -192,4 +193,10 @@ interface IAccessibilityManager { @EnforcePermission("MANAGE_ACCESSIBILITY") Bundle getA11yFeatureToTileMap(int userId); @RequiresNoPermission void registerUserInitializationCompleteCallback(IUserInitializationCompleteCallback callback); @RequiresNoPermission void unregisterUserInitializationCompleteCallback(IUserInitializationCompleteCallback callback); } core/java/android/view/accessibility/IUserInitializationCompleteCallback.aidl 0 → 100644 +35 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 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.accessibility; /** * A callback for when a new user finishes initializing * NOTE: Must remain a oneway interface, as it is called from system_server while holding a lock. * oneway allows it to return immediately and not hold the lock for longer than is necessary. * @hide */ oneway interface IUserInitializationCompleteCallback { /** * Called when a user initialization completes. * * @param userId the id of the initialized user */ @RequiresNoPermission void onUserInitializationComplete(int userId); } packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java +30 −11 Original line number Diff line number Diff line Loading @@ -21,11 +21,13 @@ import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL; import android.content.Context; import android.hardware.display.DisplayManager; import android.os.Handler; import android.os.UserHandle; import android.text.TextUtils; import android.view.Display; import android.view.WindowManager; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.IUserInitializationCompleteCallback; import androidx.annotation.MainThread; Loading Loading @@ -68,6 +70,9 @@ public class AccessibilityFloatingMenuController implements private int mBtnMode; private String mBtnTargets; private boolean mIsKeyguardVisible; private boolean mIsUserInInitialization; @VisibleForTesting Handler mHandler; @VisibleForTesting final KeyguardUpdateMonitorCallback mKeyguardCallback = new KeyguardUpdateMonitorCallback() { Loading @@ -86,18 +91,14 @@ public class AccessibilityFloatingMenuController implements @Override public void onUserSwitching(int userId) { destroyFloatingMenu(); } @Override public void onUserSwitchComplete(int userId) { mContext = mContext.createContextAsUser(UserHandle.of(userId), /* flags= */ 0); mBtnMode = mAccessibilityButtonModeObserver.getCurrentAccessibilityButtonMode(); mBtnTargets = mAccessibilityButtonTargetsObserver.getCurrentAccessibilityButtonTargets(); handleFloatingMenuVisibility(mIsKeyguardVisible, mBtnMode, mBtnTargets); mIsUserInInitialization = true; } }; @VisibleForTesting final UserInitializationCompleteCallback mUserInitializationCompleteCallback = new UserInitializationCompleteCallback(); @Inject public AccessibilityFloatingMenuController(Context context, WindowManager windowManager, Loading @@ -109,7 +110,8 @@ public class AccessibilityFloatingMenuController implements KeyguardUpdateMonitor keyguardUpdateMonitor, SecureSettings secureSettings, DisplayTracker displayTracker, NavigationModeController navigationModeController) { NavigationModeController navigationModeController, Handler handler) { mContext = context; mWindowManager = windowManager; mViewCaptureAwareWindowManager = viewCaptureAwareWindowManager; Loading @@ -121,6 +123,7 @@ public class AccessibilityFloatingMenuController implements mSecureSettings = secureSettings; mDisplayTracker = displayTracker; mNavigationModeController = navigationModeController; mHandler = handler; mIsKeyguardVisible = false; } Loading Loading @@ -159,6 +162,8 @@ public class AccessibilityFloatingMenuController implements mAccessibilityButtonModeObserver.addListener(this); mAccessibilityButtonTargetsObserver.addListener(this); mKeyguardUpdateMonitor.registerCallback(mKeyguardCallback); mAccessibilityManager.registerUserInitializationCompleteCallback( mUserInitializationCompleteCallback); } /** Loading @@ -172,7 +177,7 @@ public class AccessibilityFloatingMenuController implements */ private void handleFloatingMenuVisibility(boolean keyguardVisible, @AccessibilityButtonMode int mode, String targets) { if (keyguardVisible) { if (keyguardVisible || mIsUserInInitialization) { destroyFloatingMenu(); return; } Loading Loading @@ -210,4 +215,18 @@ public class AccessibilityFloatingMenuController implements mFloatingMenu.hide(); mFloatingMenu = null; } class UserInitializationCompleteCallback extends IUserInitializationCompleteCallback.Stub { @Override public void onUserInitializationComplete(int userId) { mIsUserInInitialization = false; mContext = mContext.createContextAsUser(UserHandle.of(userId), /* flags= */ 0); mBtnMode = mAccessibilityButtonModeObserver.getCurrentAccessibilityButtonMode(); mBtnTargets = mAccessibilityButtonTargetsObserver.getCurrentAccessibilityButtonTargets(); mHandler.post( () -> handleFloatingMenuVisibility(mIsKeyguardVisible, mBtnMode, mBtnTargets)); } } } packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java +7 −2 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import static org.mockito.Mockito.when; import android.content.Context; import android.content.ContextWrapper; import android.hardware.display.DisplayManager; import android.os.Handler; import android.os.UserHandle; import android.provider.Settings; import android.testing.TestableLooper; Loading Loading @@ -80,6 +81,7 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase { private AccessibilityManager mAccessibilityManager; private KeyguardUpdateMonitor mKeyguardUpdateMonitor; private AccessibilityFloatingMenuController mController; private TestableLooper mTestableLooper; @Mock private AccessibilityButtonTargetsObserver mTargetsObserver; @Mock Loading Loading @@ -108,6 +110,7 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase { mViewCaptureAwareWindowManager = new ViewCaptureAwareWindowManager(mWindowManager, mLazyViewCapture, /* isViewCaptureEnabled= */ false); mAccessibilityManager = mContext.getSystemService(AccessibilityManager.class); mTestableLooper = TestableLooper.get(this); when(mTargetsObserver.getCurrentAccessibilityButtonTargets()) .thenReturn(Settings.Secure.getStringForUser(mContextWrapper.getContentResolver(), Loading Loading @@ -231,7 +234,8 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase { mKeyguardCallback.onKeyguardVisibilityChanged(false); mKeyguardCallback.onUserSwitching(fakeUserId); mKeyguardCallback.onUserSwitchComplete(fakeUserId); mController.mUserInitializationCompleteCallback.onUserInitializationComplete(1); mTestableLooper.processAllMessages(); assertThat(mController.mFloatingMenu).isNotNull(); } Loading Loading @@ -346,7 +350,8 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase { new AccessibilityFloatingMenuController(mContextWrapper, windowManager, viewCaptureAwareWindowManager, displayManager, mAccessibilityManager, mTargetsObserver, mModeObserver, mKeyguardUpdateMonitor, mSecureSettings, displayTracker, mNavigationModeController); displayTracker, mNavigationModeController, new Handler( mTestableLooper.getLooper())); controller.init(); return controller; Loading Loading
core/java/android/view/accessibility/AccessibilityManager.java +46 −0 Original line number Diff line number Diff line Loading @@ -1050,6 +1050,52 @@ public final class AccessibilityManager { } } /** * Registers callback for when user initialization has completed. * Does nothing if the same callback is already registered. * * @param callback The callback to be registered * @hide */ public void registerUserInitializationCompleteCallback( @NonNull IUserInitializationCompleteCallback callback) { IAccessibilityManager service; synchronized (mLock) { service = getServiceLocked(); if (service == null) { return; } } try { service.registerUserInitializationCompleteCallback(callback); } catch (RemoteException re) { Log.e(LOG_TAG, "Error while registering userInitializationCompleteCallback. ", re); } } /** * Unregisters callback for when user initialization has completed. * * @param callback The callback to be unregistered * @hide */ public void unregisterUserInitializationCompleteCallback( @NonNull IUserInitializationCompleteCallback callback) { IAccessibilityManager service; synchronized (mLock) { service = getServiceLocked(); if (service == null) { return; } } try { service.unregisterUserInitializationCompleteCallback(callback); } catch (RemoteException re) { Log.e(LOG_TAG, "Error while unregistering userInitializationCompleteCallback. ", re); } } /** * Whether the current accessibility request comes from an * {@link AccessibilityService} with the {@link AccessibilityServiceInfo#isAccessibilityTool} Loading
core/java/android/view/accessibility/IAccessibilityManager.aidl +7 −0 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ import android.view.accessibility.IAccessibilityInteractionConnection; import android.view.accessibility.IAccessibilityManagerClient; import android.view.accessibility.AccessibilityWindowAttributes; import android.view.accessibility.IMagnificationConnection; import android.view.accessibility.IUserInitializationCompleteCallback; import android.view.InputEvent; import android.view.IWindow; import android.view.MagnificationSpec; Loading Loading @@ -192,4 +193,10 @@ interface IAccessibilityManager { @EnforcePermission("MANAGE_ACCESSIBILITY") Bundle getA11yFeatureToTileMap(int userId); @RequiresNoPermission void registerUserInitializationCompleteCallback(IUserInitializationCompleteCallback callback); @RequiresNoPermission void unregisterUserInitializationCompleteCallback(IUserInitializationCompleteCallback callback); }
core/java/android/view/accessibility/IUserInitializationCompleteCallback.aidl 0 → 100644 +35 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 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.accessibility; /** * A callback for when a new user finishes initializing * NOTE: Must remain a oneway interface, as it is called from system_server while holding a lock. * oneway allows it to return immediately and not hold the lock for longer than is necessary. * @hide */ oneway interface IUserInitializationCompleteCallback { /** * Called when a user initialization completes. * * @param userId the id of the initialized user */ @RequiresNoPermission void onUserInitializationComplete(int userId); }
packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java +30 −11 Original line number Diff line number Diff line Loading @@ -21,11 +21,13 @@ import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL; import android.content.Context; import android.hardware.display.DisplayManager; import android.os.Handler; import android.os.UserHandle; import android.text.TextUtils; import android.view.Display; import android.view.WindowManager; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.IUserInitializationCompleteCallback; import androidx.annotation.MainThread; Loading Loading @@ -68,6 +70,9 @@ public class AccessibilityFloatingMenuController implements private int mBtnMode; private String mBtnTargets; private boolean mIsKeyguardVisible; private boolean mIsUserInInitialization; @VisibleForTesting Handler mHandler; @VisibleForTesting final KeyguardUpdateMonitorCallback mKeyguardCallback = new KeyguardUpdateMonitorCallback() { Loading @@ -86,18 +91,14 @@ public class AccessibilityFloatingMenuController implements @Override public void onUserSwitching(int userId) { destroyFloatingMenu(); } @Override public void onUserSwitchComplete(int userId) { mContext = mContext.createContextAsUser(UserHandle.of(userId), /* flags= */ 0); mBtnMode = mAccessibilityButtonModeObserver.getCurrentAccessibilityButtonMode(); mBtnTargets = mAccessibilityButtonTargetsObserver.getCurrentAccessibilityButtonTargets(); handleFloatingMenuVisibility(mIsKeyguardVisible, mBtnMode, mBtnTargets); mIsUserInInitialization = true; } }; @VisibleForTesting final UserInitializationCompleteCallback mUserInitializationCompleteCallback = new UserInitializationCompleteCallback(); @Inject public AccessibilityFloatingMenuController(Context context, WindowManager windowManager, Loading @@ -109,7 +110,8 @@ public class AccessibilityFloatingMenuController implements KeyguardUpdateMonitor keyguardUpdateMonitor, SecureSettings secureSettings, DisplayTracker displayTracker, NavigationModeController navigationModeController) { NavigationModeController navigationModeController, Handler handler) { mContext = context; mWindowManager = windowManager; mViewCaptureAwareWindowManager = viewCaptureAwareWindowManager; Loading @@ -121,6 +123,7 @@ public class AccessibilityFloatingMenuController implements mSecureSettings = secureSettings; mDisplayTracker = displayTracker; mNavigationModeController = navigationModeController; mHandler = handler; mIsKeyguardVisible = false; } Loading Loading @@ -159,6 +162,8 @@ public class AccessibilityFloatingMenuController implements mAccessibilityButtonModeObserver.addListener(this); mAccessibilityButtonTargetsObserver.addListener(this); mKeyguardUpdateMonitor.registerCallback(mKeyguardCallback); mAccessibilityManager.registerUserInitializationCompleteCallback( mUserInitializationCompleteCallback); } /** Loading @@ -172,7 +177,7 @@ public class AccessibilityFloatingMenuController implements */ private void handleFloatingMenuVisibility(boolean keyguardVisible, @AccessibilityButtonMode int mode, String targets) { if (keyguardVisible) { if (keyguardVisible || mIsUserInInitialization) { destroyFloatingMenu(); return; } Loading Loading @@ -210,4 +215,18 @@ public class AccessibilityFloatingMenuController implements mFloatingMenu.hide(); mFloatingMenu = null; } class UserInitializationCompleteCallback extends IUserInitializationCompleteCallback.Stub { @Override public void onUserInitializationComplete(int userId) { mIsUserInInitialization = false; mContext = mContext.createContextAsUser(UserHandle.of(userId), /* flags= */ 0); mBtnMode = mAccessibilityButtonModeObserver.getCurrentAccessibilityButtonMode(); mBtnTargets = mAccessibilityButtonTargetsObserver.getCurrentAccessibilityButtonTargets(); mHandler.post( () -> handleFloatingMenuVisibility(mIsKeyguardVisible, mBtnMode, mBtnTargets)); } } }
packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java +7 −2 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import static org.mockito.Mockito.when; import android.content.Context; import android.content.ContextWrapper; import android.hardware.display.DisplayManager; import android.os.Handler; import android.os.UserHandle; import android.provider.Settings; import android.testing.TestableLooper; Loading Loading @@ -80,6 +81,7 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase { private AccessibilityManager mAccessibilityManager; private KeyguardUpdateMonitor mKeyguardUpdateMonitor; private AccessibilityFloatingMenuController mController; private TestableLooper mTestableLooper; @Mock private AccessibilityButtonTargetsObserver mTargetsObserver; @Mock Loading Loading @@ -108,6 +110,7 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase { mViewCaptureAwareWindowManager = new ViewCaptureAwareWindowManager(mWindowManager, mLazyViewCapture, /* isViewCaptureEnabled= */ false); mAccessibilityManager = mContext.getSystemService(AccessibilityManager.class); mTestableLooper = TestableLooper.get(this); when(mTargetsObserver.getCurrentAccessibilityButtonTargets()) .thenReturn(Settings.Secure.getStringForUser(mContextWrapper.getContentResolver(), Loading Loading @@ -231,7 +234,8 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase { mKeyguardCallback.onKeyguardVisibilityChanged(false); mKeyguardCallback.onUserSwitching(fakeUserId); mKeyguardCallback.onUserSwitchComplete(fakeUserId); mController.mUserInitializationCompleteCallback.onUserInitializationComplete(1); mTestableLooper.processAllMessages(); assertThat(mController.mFloatingMenu).isNotNull(); } Loading Loading @@ -346,7 +350,8 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase { new AccessibilityFloatingMenuController(mContextWrapper, windowManager, viewCaptureAwareWindowManager, displayManager, mAccessibilityManager, mTargetsObserver, mModeObserver, mKeyguardUpdateMonitor, mSecureSettings, displayTracker, mNavigationModeController); displayTracker, mNavigationModeController, new Handler( mTestableLooper.getLooper())); controller.init(); return controller; Loading