Observer for the accessibility button mode and notify its listeners for the changes
* Update accessibility button state (visibility) in navigationbar when accessibility button mode listener receive the changes. Bug: 173938894 Bug: 173940864 Test: atest AccessibilityButtonModeObserverTest Change-Id: I03b961c95a20e4698491443012beb3ab73333199
This commit is contained in:
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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 android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
|
||||
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.MainThread;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.database.ContentObserver;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.provider.Settings;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.systemui.dagger.SysUISingleton;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
/**
|
||||
* Observes changes of the accessibility button mode
|
||||
* {@link Settings.Secure#ACCESSIBILITY_BUTTON_MODE} and notify its listeners.
|
||||
*/
|
||||
@MainThread
|
||||
@SysUISingleton
|
||||
public class AccessibilityButtonModeObserver {
|
||||
|
||||
private static final int ACCESSIBILITY_BUTTON_MODE_DEFAULT =
|
||||
ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR;
|
||||
|
||||
private final ContentResolver mContentResolver;
|
||||
@VisibleForTesting
|
||||
final ContentObserver mContentObserver;
|
||||
|
||||
private final List<ModeChangedListener> mListeners = new ArrayList<>();
|
||||
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({
|
||||
ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR,
|
||||
ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU
|
||||
})
|
||||
private @interface AccessibilityButtonMode {}
|
||||
|
||||
/** Listener for accessibility button mode changes. */
|
||||
public interface ModeChangedListener {
|
||||
|
||||
/**
|
||||
* Called when accessibility button mode changes.
|
||||
*
|
||||
* @param mode Current accessibility button mode.
|
||||
*/
|
||||
void onAccessibilityButtonModeChanged(@AccessibilityButtonMode int mode);
|
||||
}
|
||||
|
||||
@Inject
|
||||
public AccessibilityButtonModeObserver(Context context) {
|
||||
mContentResolver = context.getContentResolver();
|
||||
mContentObserver = new ContentObserver(new Handler(Looper.getMainLooper())) {
|
||||
@Override
|
||||
public void onChange(boolean selfChange) {
|
||||
updateAccessibilityButtonModeChanged();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a listener to receive updates from settings key {@link
|
||||
* Settings.Secure#ACCESSIBILITY_BUTTON_MODE}.
|
||||
*
|
||||
* @param listener A {@link ModeChangedListener} object.
|
||||
*/
|
||||
public void addListener(@NonNull ModeChangedListener listener) {
|
||||
Objects.requireNonNull(listener, "listener must be non-null");
|
||||
|
||||
mListeners.add(listener);
|
||||
|
||||
if (mListeners.size() == 1) {
|
||||
mContentResolver.registerContentObserver(
|
||||
Settings.Secure.getUriFor(
|
||||
Settings.Secure.ACCESSIBILITY_BUTTON_MODE), /* notifyForDescendants= */
|
||||
false, mContentObserver);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters a listener previously registered with {@link #addListener(ModeChangedListener)}.
|
||||
*
|
||||
* @param listener A {@link ModeChangedListener} object.
|
||||
*/
|
||||
public void removeListener(@NonNull ModeChangedListener listener) {
|
||||
Objects.requireNonNull(listener, "listener must be non-null");
|
||||
|
||||
mListeners.remove(listener);
|
||||
|
||||
if (mListeners.isEmpty()) {
|
||||
mContentResolver.unregisterContentObserver(mContentObserver);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current accessibility button mode from the current user's settings.
|
||||
*
|
||||
* See {@link Settings.Secure#ACCESSIBILITY_BUTTON_MODE}.
|
||||
*/
|
||||
@AccessibilityButtonMode
|
||||
public int getCurrentAccessibilityButtonMode() {
|
||||
return Settings.Secure.getInt(mContentResolver, Settings.Secure.ACCESSIBILITY_BUTTON_MODE,
|
||||
ACCESSIBILITY_BUTTON_MODE_DEFAULT);
|
||||
}
|
||||
|
||||
private void updateAccessibilityButtonModeChanged() {
|
||||
final int mode = getCurrentAccessibilityButtonMode();
|
||||
final int listenerSize = mListeners.size();
|
||||
for (int i = 0; i < listenerSize; i++) {
|
||||
mListeners.get(i).onAccessibilityButtonModeChanged(mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -45,6 +45,7 @@ import com.android.keyguard.ViewMediatorCallback;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||
import com.android.systemui.Prefs;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
|
||||
import com.android.systemui.accessibility.ModeSwitchesController;
|
||||
import com.android.systemui.accessibility.SystemActions;
|
||||
import com.android.systemui.assist.AssistManager;
|
||||
@@ -212,6 +213,7 @@ public class DependencyProvider {
|
||||
MetricsLogger metricsLogger,
|
||||
OverviewProxyService overviewProxyService,
|
||||
NavigationModeController navigationModeController,
|
||||
AccessibilityButtonModeObserver accessibilityButtonModeObserver,
|
||||
StatusBarStateController statusBarStateController,
|
||||
SysUiState sysUiFlagsContainer,
|
||||
BroadcastDispatcher broadcastDispatcher,
|
||||
@@ -236,6 +238,7 @@ public class DependencyProvider {
|
||||
metricsLogger,
|
||||
overviewProxyService,
|
||||
navigationModeController,
|
||||
accessibilityButtonModeObserver,
|
||||
statusBarStateController,
|
||||
sysUiFlagsContainer,
|
||||
broadcastDispatcher,
|
||||
|
||||
@@ -111,6 +111,7 @@ import com.android.internal.util.LatencyTracker;
|
||||
import com.android.internal.view.AppearanceRegion;
|
||||
import com.android.systemui.Dependency;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
|
||||
import com.android.systemui.accessibility.SystemActions;
|
||||
import com.android.systemui.assist.AssistHandleViewController;
|
||||
import com.android.systemui.assist.AssistManager;
|
||||
@@ -156,7 +157,8 @@ import dagger.Lazy;
|
||||
* Contains logic for a navigation bar view.
|
||||
*/
|
||||
public class NavigationBar implements View.OnAttachStateChangeListener,
|
||||
Callbacks, NavigationModeController.ModeChangedListener, DisplayManager.DisplayListener {
|
||||
Callbacks, NavigationModeController.ModeChangedListener,
|
||||
AccessibilityButtonModeObserver.ModeChangedListener, DisplayManager.DisplayListener {
|
||||
|
||||
public static final String TAG = "NavigationBar";
|
||||
private static final boolean DEBUG = false;
|
||||
@@ -184,6 +186,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
|
||||
private final NotificationRemoteInputManager mNotificationRemoteInputManager;
|
||||
private final OverviewProxyService mOverviewProxyService;
|
||||
private final NavigationModeController mNavigationModeController;
|
||||
private final AccessibilityButtonModeObserver mAccessibilityButtonModeObserver;
|
||||
private final BroadcastDispatcher mBroadcastDispatcher;
|
||||
private final CommandQueue mCommandQueue;
|
||||
private final Optional<Pip> mPipOptional;
|
||||
@@ -222,6 +225,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
|
||||
|
||||
private boolean mTransientShown;
|
||||
private int mNavBarMode = NAV_BAR_MODE_3BUTTON;
|
||||
private int mA11yBtnMode;
|
||||
private LightBarController mLightBarController;
|
||||
private AutoHideController mAutoHideController;
|
||||
|
||||
@@ -414,6 +418,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
|
||||
MetricsLogger metricsLogger,
|
||||
OverviewProxyService overviewProxyService,
|
||||
NavigationModeController navigationModeController,
|
||||
AccessibilityButtonModeObserver accessibilityButtonModeObserver,
|
||||
StatusBarStateController statusBarStateController,
|
||||
SysUiState sysUiFlagsContainer,
|
||||
BroadcastDispatcher broadcastDispatcher,
|
||||
@@ -441,7 +446,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
|
||||
mNotificationRemoteInputManager = notificationRemoteInputManager;
|
||||
mOverviewProxyService = overviewProxyService;
|
||||
mNavigationModeController = navigationModeController;
|
||||
mNavBarMode = navigationModeController.addListener(this);
|
||||
mAccessibilityButtonModeObserver = accessibilityButtonModeObserver;
|
||||
mBroadcastDispatcher = broadcastDispatcher;
|
||||
mCommandQueue = commandQueue;
|
||||
mPipOptional = pipOptional;
|
||||
@@ -451,6 +456,10 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
|
||||
mHandler = mainHandler;
|
||||
mNavbarOverlayController = navbarOverlayController;
|
||||
mUiEventLogger = uiEventLogger;
|
||||
|
||||
mNavBarMode = mNavigationModeController.addListener(this);
|
||||
mAccessibilityButtonModeObserver.addListener(this);
|
||||
mA11yBtnMode = mAccessibilityButtonModeObserver.getCurrentAccessibilityButtonMode();
|
||||
}
|
||||
|
||||
public View getView() {
|
||||
@@ -524,6 +533,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
|
||||
mContext.getSystemService(WindowManager.class).removeViewImmediate(
|
||||
mNavigationBarView.getRootView());
|
||||
mNavigationModeController.removeListener(this);
|
||||
mAccessibilityButtonModeObserver.removeListener(this);
|
||||
|
||||
mAccessibilityManagerWrapper.removeCallback(mAccessibilityListener);
|
||||
mContentResolver.unregisterContentObserver(mAssistContentObserver);
|
||||
@@ -1391,6 +1401,12 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
|
||||
outFeedbackEnabled[0] = feedbackEnabled;
|
||||
}
|
||||
|
||||
// If accessibility button is floating menu mode, click and long click state should be
|
||||
// disabled.
|
||||
if (mA11yBtnMode == Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (requestingServices >= 1 ? SYSUI_STATE_A11Y_BUTTON_CLICKABLE : 0)
|
||||
| (requestingServices >= 2 ? SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE : 0);
|
||||
}
|
||||
@@ -1475,6 +1491,12 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAccessibilityButtonModeChanged(int mode) {
|
||||
mA11yBtnMode = mode;
|
||||
updateAccessibilityServicesState(mAccessibilityManager);
|
||||
}
|
||||
|
||||
public void disableAnimationsDuringHide(long delay) {
|
||||
mNavigationBarView.setLayoutTransitionsEnabled(false);
|
||||
mNavigationBarView.postDelayed(() -> mNavigationBarView.setLayoutTransitionsEnabled(true),
|
||||
|
||||
@@ -43,6 +43,7 @@ import com.android.internal.logging.UiEventLogger;
|
||||
import com.android.internal.statusbar.RegisterStatusBarResult;
|
||||
import com.android.settingslib.applications.InterestingConfigChanges;
|
||||
import com.android.systemui.Dumpable;
|
||||
import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
|
||||
import com.android.systemui.accessibility.SystemActions;
|
||||
import com.android.systemui.assist.AssistHandleViewController;
|
||||
import com.android.systemui.assist.AssistManager;
|
||||
@@ -91,6 +92,7 @@ public class NavigationBarController implements Callbacks,
|
||||
private final MetricsLogger mMetricsLogger;
|
||||
private final OverviewProxyService mOverviewProxyService;
|
||||
private final NavigationModeController mNavigationModeController;
|
||||
private final AccessibilityButtonModeObserver mAccessibilityButtonModeObserver;
|
||||
private final StatusBarStateController mStatusBarStateController;
|
||||
private final SysUiState mSysUiFlagsContainer;
|
||||
private final BroadcastDispatcher mBroadcastDispatcher;
|
||||
@@ -127,6 +129,7 @@ public class NavigationBarController implements Callbacks,
|
||||
MetricsLogger metricsLogger,
|
||||
OverviewProxyService overviewProxyService,
|
||||
NavigationModeController navigationModeController,
|
||||
AccessibilityButtonModeObserver accessibilityButtonModeObserver,
|
||||
StatusBarStateController statusBarStateController,
|
||||
SysUiState sysUiFlagsContainer,
|
||||
BroadcastDispatcher broadcastDispatcher,
|
||||
@@ -151,6 +154,7 @@ public class NavigationBarController implements Callbacks,
|
||||
mMetricsLogger = metricsLogger;
|
||||
mOverviewProxyService = overviewProxyService;
|
||||
mNavigationModeController = navigationModeController;
|
||||
mAccessibilityButtonModeObserver = accessibilityButtonModeObserver;
|
||||
mStatusBarStateController = statusBarStateController;
|
||||
mSysUiFlagsContainer = sysUiFlagsContainer;
|
||||
mBroadcastDispatcher = broadcastDispatcher;
|
||||
@@ -281,6 +285,7 @@ public class NavigationBarController implements Callbacks,
|
||||
mMetricsLogger,
|
||||
mOverviewProxyService,
|
||||
mNavigationModeController,
|
||||
mAccessibilityButtonModeObserver,
|
||||
mStatusBarStateController,
|
||||
mSysUiFlagsContainer,
|
||||
mBroadcastDispatcher,
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.anyInt;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.provider.Settings;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnit;
|
||||
import org.mockito.junit.MockitoRule;
|
||||
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
@SmallTest
|
||||
public class AccessibilityButtonModeObserverTest extends SysuiTestCase {
|
||||
|
||||
@Rule
|
||||
public MockitoRule mockito = MockitoJUnit.rule();
|
||||
|
||||
@Mock
|
||||
private AccessibilityButtonModeObserver.ModeChangedListener mListener;
|
||||
|
||||
private AccessibilityButtonModeObserver mAccessibilityButtonModeObserver;
|
||||
|
||||
private static final int TEST_A11Y_BTN_MODE_VALUE =
|
||||
Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
|
||||
|
||||
@Before
|
||||
public void setUpController() {
|
||||
Settings.Secure.putInt(mContext.getContentResolver(),
|
||||
Settings.Secure.ACCESSIBILITY_BUTTON_MODE,
|
||||
Settings.Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR);
|
||||
mAccessibilityButtonModeObserver = new AccessibilityButtonModeObserver(mContext);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onChange_haveListener_invokeCallback() {
|
||||
mAccessibilityButtonModeObserver.addListener(mListener);
|
||||
Settings.Secure.putInt(mContext.getContentResolver(),
|
||||
Settings.Secure.ACCESSIBILITY_BUTTON_MODE, TEST_A11Y_BTN_MODE_VALUE);
|
||||
|
||||
mAccessibilityButtonModeObserver.mContentObserver.onChange(false);
|
||||
|
||||
verify(mListener).onAccessibilityButtonModeChanged(TEST_A11Y_BTN_MODE_VALUE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onChange_noListener_noInvokeCallback() {
|
||||
mAccessibilityButtonModeObserver.addListener(mListener);
|
||||
mAccessibilityButtonModeObserver.removeListener(mListener);
|
||||
Settings.Secure.putInt(mContext.getContentResolver(),
|
||||
Settings.Secure.ACCESSIBILITY_BUTTON_MODE, TEST_A11Y_BTN_MODE_VALUE);
|
||||
|
||||
mAccessibilityButtonModeObserver.mContentObserver.onChange(false);
|
||||
|
||||
verify(mListener, never()).onAccessibilityButtonModeChanged(anyInt());
|
||||
}
|
||||
}
|
||||
@@ -45,6 +45,7 @@ import com.android.internal.logging.MetricsLogger;
|
||||
import com.android.internal.logging.UiEventLogger;
|
||||
import com.android.systemui.Dependency;
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
|
||||
import com.android.systemui.accessibility.SystemActions;
|
||||
import com.android.systemui.assist.AssistManager;
|
||||
import com.android.systemui.broadcast.BroadcastDispatcher;
|
||||
@@ -93,6 +94,7 @@ public class NavigationBarControllerTest extends SysuiTestCase {
|
||||
mock(MetricsLogger.class),
|
||||
mock(OverviewProxyService.class),
|
||||
mock(NavigationModeController.class),
|
||||
mock(AccessibilityButtonModeObserver.class),
|
||||
mock(StatusBarStateController.class),
|
||||
mock(SysUiState.class),
|
||||
mock(BroadcastDispatcher.class),
|
||||
|
||||
@@ -61,6 +61,7 @@ import com.android.internal.logging.UiEventLogger;
|
||||
import com.android.systemui.Dependency;
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
import com.android.systemui.SysuiTestableContext;
|
||||
import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
|
||||
import com.android.systemui.accessibility.SystemActions;
|
||||
import com.android.systemui.assist.AssistManager;
|
||||
import com.android.systemui.broadcast.BroadcastDispatcher;
|
||||
@@ -220,6 +221,7 @@ public class NavigationBarTest extends SysuiTestCase {
|
||||
new MetricsLogger(),
|
||||
mOverviewProxyService,
|
||||
mock(NavigationModeController.class),
|
||||
mock(AccessibilityButtonModeObserver.class),
|
||||
mock(StatusBarStateController.class),
|
||||
mMockSysUiState,
|
||||
mBroadcastDispatcher,
|
||||
|
||||
Reference in New Issue
Block a user