Loading core/java/android/widget/ToastPresenter.java +17 −13 Original line number Diff line number Diff line Loading @@ -69,7 +69,7 @@ public class ToastPresenter { private final Context mContext; private final Resources mResources; private final WindowManager mWindowManager; private final AccessibilityManager mAccessibilityManager; private final IAccessibilityManager mAccessibilityManager; private final INotificationManager mNotificationManager; private final String mPackageName; private final WindowManager.LayoutParams mParams; Loading @@ -83,16 +83,7 @@ public class ToastPresenter { mWindowManager = context.getSystemService(WindowManager.class); mNotificationManager = notificationManager; mPackageName = packageName; // We obtain AccessibilityManager manually via its constructor instead of using method // AccessibilityManager.getInstance() for 2 reasons: // 1. We want to be able to inject IAccessibilityManager in tests to verify behavior. // 2. getInstance() caches the instance for the process even if we pass a different // context to it. This is problematic for multi-user because callers can pass a context // created via Context.createContextAsUser(). mAccessibilityManager = new AccessibilityManager(context, accessibilityManager, context.getUserId()); mAccessibilityManager = accessibilityManager; mParams = createLayoutParams(); } Loading Loading @@ -283,7 +274,16 @@ public class ToastPresenter { * enabled. */ public void trySendAccessibilityEvent(View view, String packageName) { if (!mAccessibilityManager.isEnabled()) { // We obtain AccessibilityManager manually via its constructor instead of using method // AccessibilityManager.getInstance() for 2 reasons: // 1. We want to be able to inject IAccessibilityManager in tests to verify behavior. // 2. getInstance() caches the instance for the process even if we pass a different // context to it. This is problematic for multi-user because callers can pass a context // created via Context.createContextAsUser(). final AccessibilityManager accessibilityManager = new AccessibilityManager(mContext, mAccessibilityManager, mContext.getUserId()); if (!accessibilityManager.isEnabled()) { accessibilityManager.removeClient(); return; } AccessibilityEvent event = AccessibilityEvent.obtain( Loading @@ -291,7 +291,11 @@ public class ToastPresenter { event.setClassName(Toast.class.getName()); event.setPackageName(packageName); view.dispatchPopulateAccessibilityEvent(event); mAccessibilityManager.sendAccessibilityEvent(event); accessibilityManager.sendAccessibilityEvent(event); // Every new instance of A11yManager registers an IA11yManagerClient object with the // backing service. This client isn't removed until the calling process is destroyed, // causing a leak here. We explicitly remove the client. accessibilityManager.removeClient(); } private void addToastView() { Loading packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java +9 −0 Original line number Diff line number Diff line Loading @@ -84,6 +84,7 @@ public class ToastUITest extends SysuiTestCase { private static final String PACKAGE_NAME_1 = "com.example1.test"; private static final Binder TOKEN_1 = new Binder(); private static final Binder WINDOW_TOKEN_1 = new Binder(); private static final int USER_ID = 1; private static final int UID_2 = 10256; private static final String PACKAGE_NAME_2 = "com.example2.test"; Loading Loading @@ -226,6 +227,14 @@ public class ToastUITest extends SysuiTestCase { assertThat(event.getPackageName()).isEqualTo(PACKAGE_NAME_1); } @Test public void testShowToast_accessibilityManagerClientIsRemoved() throws Exception { when(mContextSpy.getUserId()).thenReturn(USER_ID); mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG, null); verify(mAccessibilityManager).removeClient(any(), eq(USER_ID)); } @Test public void testHideToast_removesView() throws Exception { mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG, Loading Loading
core/java/android/widget/ToastPresenter.java +17 −13 Original line number Diff line number Diff line Loading @@ -69,7 +69,7 @@ public class ToastPresenter { private final Context mContext; private final Resources mResources; private final WindowManager mWindowManager; private final AccessibilityManager mAccessibilityManager; private final IAccessibilityManager mAccessibilityManager; private final INotificationManager mNotificationManager; private final String mPackageName; private final WindowManager.LayoutParams mParams; Loading @@ -83,16 +83,7 @@ public class ToastPresenter { mWindowManager = context.getSystemService(WindowManager.class); mNotificationManager = notificationManager; mPackageName = packageName; // We obtain AccessibilityManager manually via its constructor instead of using method // AccessibilityManager.getInstance() for 2 reasons: // 1. We want to be able to inject IAccessibilityManager in tests to verify behavior. // 2. getInstance() caches the instance for the process even if we pass a different // context to it. This is problematic for multi-user because callers can pass a context // created via Context.createContextAsUser(). mAccessibilityManager = new AccessibilityManager(context, accessibilityManager, context.getUserId()); mAccessibilityManager = accessibilityManager; mParams = createLayoutParams(); } Loading Loading @@ -283,7 +274,16 @@ public class ToastPresenter { * enabled. */ public void trySendAccessibilityEvent(View view, String packageName) { if (!mAccessibilityManager.isEnabled()) { // We obtain AccessibilityManager manually via its constructor instead of using method // AccessibilityManager.getInstance() for 2 reasons: // 1. We want to be able to inject IAccessibilityManager in tests to verify behavior. // 2. getInstance() caches the instance for the process even if we pass a different // context to it. This is problematic for multi-user because callers can pass a context // created via Context.createContextAsUser(). final AccessibilityManager accessibilityManager = new AccessibilityManager(mContext, mAccessibilityManager, mContext.getUserId()); if (!accessibilityManager.isEnabled()) { accessibilityManager.removeClient(); return; } AccessibilityEvent event = AccessibilityEvent.obtain( Loading @@ -291,7 +291,11 @@ public class ToastPresenter { event.setClassName(Toast.class.getName()); event.setPackageName(packageName); view.dispatchPopulateAccessibilityEvent(event); mAccessibilityManager.sendAccessibilityEvent(event); accessibilityManager.sendAccessibilityEvent(event); // Every new instance of A11yManager registers an IA11yManagerClient object with the // backing service. This client isn't removed until the calling process is destroyed, // causing a leak here. We explicitly remove the client. accessibilityManager.removeClient(); } private void addToastView() { Loading
packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java +9 −0 Original line number Diff line number Diff line Loading @@ -84,6 +84,7 @@ public class ToastUITest extends SysuiTestCase { private static final String PACKAGE_NAME_1 = "com.example1.test"; private static final Binder TOKEN_1 = new Binder(); private static final Binder WINDOW_TOKEN_1 = new Binder(); private static final int USER_ID = 1; private static final int UID_2 = 10256; private static final String PACKAGE_NAME_2 = "com.example2.test"; Loading Loading @@ -226,6 +227,14 @@ public class ToastUITest extends SysuiTestCase { assertThat(event.getPackageName()).isEqualTo(PACKAGE_NAME_1); } @Test public void testShowToast_accessibilityManagerClientIsRemoved() throws Exception { when(mContextSpy.getUserId()).thenReturn(USER_ID); mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG, null); verify(mAccessibilityManager).removeClient(any(), eq(USER_ID)); } @Test public void testHideToast_removesView() throws Exception { mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG, Loading