diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java index 429e859b5403f..f4d4a9ff327d1 100644 --- a/packages/SystemUI/src/com/android/systemui/Dependency.java +++ b/packages/SystemUI/src/com/android/systemui/Dependency.java @@ -42,6 +42,7 @@ import com.android.systemui.statusbar.phone.StatusBarWindowManager; import com.android.systemui.statusbar.phone.StatusBarIconController; import com.android.systemui.statusbar.phone.StatusBarIconControllerImpl; import com.android.systemui.statusbar.policy.AccessibilityController; +import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper; import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.BatteryControllerImpl; import com.android.systemui.statusbar.policy.BluetoothController; @@ -260,6 +261,9 @@ public class Dependency extends SystemUI { mProviders.put(MetricsLogger.class, () -> new MetricsLogger()); + mProviders.put(AccessibilityManagerWrapper.class, + () -> new AccessibilityManagerWrapper(mContext)); + // Put all dependencies above here so the factory can override them if it wants. SystemUIFactory.getInstance().injectDependencies(mProviders, mContext); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java index 7562399b1d709..fa404b5996019 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java @@ -64,6 +64,7 @@ import android.view.WindowManager.LayoutParams; import android.view.WindowManagerGlobal; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; +import android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; @@ -78,6 +79,7 @@ import com.android.systemui.recents.Recents; import com.android.systemui.stackdivider.Divider; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.CommandQueue.Callbacks; +import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper; import com.android.systemui.statusbar.policy.KeyButtonView; import com.android.systemui.statusbar.stack.StackStateAnimator; @@ -138,8 +140,8 @@ public class NavigationBarFragment extends Fragment implements Callbacks { mDivider = SysUiServiceProvider.getComponent(getContext(), Divider.class); mWindowManager = getContext().getSystemService(WindowManager.class); mAccessibilityManager = getContext().getSystemService(AccessibilityManager.class); - mAccessibilityManager.addAccessibilityServicesStateChangeListener( - this::updateAccessibilityServicesState); + Dependency.get(AccessibilityManagerWrapper.class).addCallback( + mAccessibilityListener); mContentResolver = getContext().getContentResolver(); mMagnificationObserver = new MagnificationContentObserver( getContext().getMainThreadHandler()); @@ -164,8 +166,8 @@ public class NavigationBarFragment extends Fragment implements Callbacks { public void onDestroy() { super.onDestroy(); mCommandQueue.removeCallbacks(this); - mAccessibilityManager.removeAccessibilityServicesStateChangeListener( - this::updateAccessibilityServicesState); + Dependency.get(AccessibilityManagerWrapper.class).removeCallback( + mAccessibilityListener); mContentResolver.unregisterContentObserver(mMagnificationObserver); try { WindowManagerGlobal.getWindowManagerService() @@ -625,6 +627,9 @@ public class NavigationBarFragment extends Fragment implements Callbacks { mNavigationBarView.getBarTransitions().finishAnimations(); } + private final AccessibilityServicesStateChangeListener mAccessibilityListener = + this::updateAccessibilityServicesState; + private class MagnificationContentObserver extends ContentObserver { public MagnificationContentObserver(Handler handler) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessibilityManagerWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessibilityManagerWrapper.java new file mode 100644 index 0000000000000..dfa5cbdd3e12a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessibilityManagerWrapper.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2017 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.statusbar.policy; + +import android.content.Context; +import android.view.accessibility.AccessibilityManager; +import android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener; + +/** + * For mocking because AccessibilyManager is final for some reason... + */ +public class AccessibilityManagerWrapper implements + CallbackController { + + private final AccessibilityManager mAccessibilityManager; + + public AccessibilityManagerWrapper(Context context) { + mAccessibilityManager = context.getSystemService(AccessibilityManager.class); + } + + @Override + public void addCallback(AccessibilityServicesStateChangeListener listener) { + mAccessibilityManager.addAccessibilityServicesStateChangeListener(listener); + } + + @Override + public void removeCallback(AccessibilityServicesStateChangeListener listener) { + mAccessibilityManager.removeAccessibilityServicesStateChangeListener(listener); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java index e7cdcb541ee49..53d842a01ed25 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java @@ -14,12 +14,14 @@ package com.android.systemui.statusbar.phone; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import android.content.Context; import android.os.Looper; import android.testing.AndroidTestingRunner; +import android.testing.LeakCheck.Tracker; import android.view.Display; import android.view.WindowManager; @@ -29,11 +31,18 @@ import com.android.systemui.SysuiBaseFragmentTest; import com.android.systemui.recents.Recents; import com.android.systemui.stackdivider.Divider; import com.android.systemui.statusbar.CommandQueue; +import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper; +import com.android.systemui.utils.leaks.BaseLeakChecker; + import android.testing.TestableLooper.RunWithLooper; +import android.view.accessibility.AccessibilityManager; +import android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; @RunWith(AndroidTestingRunner.class) @RunWithLooper(setAsMainLooper = true) @@ -56,6 +65,20 @@ public class NavigationBarFragmentTest extends SysuiBaseFragmentTest { when(windowManager.getDefaultDisplay()).thenReturn( defaultDisplay); mContext.addMockSystemService(Context.WINDOW_SERVICE, windowManager); + + Tracker tracker = mLeakCheck.getTracker("accessibility_manager"); + AccessibilityManagerWrapper wrapper = new AccessibilityManagerWrapper(mContext) { + @Override + public void addCallback(AccessibilityServicesStateChangeListener listener) { + tracker.getLeakInfo(listener).addAllocation(new Throwable()); + } + + @Override + public void removeCallback(AccessibilityServicesStateChangeListener listener) { + tracker.getLeakInfo(listener).clearAllocations(); + } + }; + mDependency.injectTestDependency(AccessibilityManagerWrapper.class, wrapper); } @Test