Merge "Extract assistant logic from NavigationBar to share with Taskbar" into sc-v2-dev am: 325d89dd12

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/16231766

Change-Id: I34417abf752722ac3f96883cfb484e7a4f382751
This commit is contained in:
Vinit Nayak
2021-11-21 02:27:19 +00:00
committed by Automerger Merge Worker
8 changed files with 519 additions and 186 deletions

View File

@@ -0,0 +1,246 @@
/*
* 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.navigationbar;
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_CLICKABLE;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE;
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.UserHandle;
import android.provider.Settings;
import android.view.accessibility.AccessibilityManager;
import androidx.annotation.NonNull;
import com.android.systemui.Dumpable;
import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.recents.OverviewProxyService;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
import dagger.Lazy;
/**
* Extracts shared elements between navbar and taskbar delegate to de-dupe logic and help them
* experience the joys of friendship.
* The events are then passed through
*
* Currently consolidates
* * A11y
* * Assistant
*/
@SysUISingleton
public final class NavBarHelper implements
AccessibilityButtonModeObserver.ModeChangedListener,
OverviewProxyService.OverviewProxyListener, NavigationModeController.ModeChangedListener,
Dumpable {
private final AccessibilityManager mAccessibilityManager;
private final Lazy<AssistManager> mAssistManagerLazy;
private final UserTracker mUserTracker;
private final AccessibilityButtonModeObserver mAccessibilityButtonModeObserver;
private final List<NavbarTaskbarStateUpdater> mA11yEventListeners = new ArrayList<>();
private Context mContext;
private ContentResolver mContentResolver;
private boolean mAssistantAvailable;
private boolean mLongPressHomeEnabled;
private boolean mAssistantTouchGestureEnabled;
private int mNavBarMode;
private final ContentObserver mAssistContentObserver = new ContentObserver(
new Handler(Looper.getMainLooper())) {
@Override
public void onChange(boolean selfChange, Uri uri) {
updateAssitantAvailability();
}
};
@Inject
public NavBarHelper(AccessibilityManager accessibilityManager,
AccessibilityManagerWrapper accessibilityManagerWrapper,
AccessibilityButtonModeObserver accessibilityButtonModeObserver,
OverviewProxyService overviewProxyService,
Lazy<AssistManager> assistManagerLazy,
NavigationModeController navigationModeController,
UserTracker userTracker,
DumpManager dumpManager) {
mAccessibilityManager = accessibilityManager;
mAssistManagerLazy = assistManagerLazy;
mUserTracker = userTracker;
accessibilityManagerWrapper.addCallback(
accessibilityManager1 -> NavBarHelper.this.dispatchA11yEventUpdate());
mAccessibilityButtonModeObserver = accessibilityButtonModeObserver;
mAccessibilityButtonModeObserver.addListener(this);
mNavBarMode = navigationModeController.addListener(this);
overviewProxyService.addCallback(this);
dumpManager.registerDumpable(this);
}
public void init(Context context) {
mContext = context;
mContentResolver = mContext.getContentResolver();
mContentResolver.registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.ASSISTANT),
false /* notifyForDescendants */, mAssistContentObserver, UserHandle.USER_ALL);
mContentResolver.registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.ASSIST_LONG_PRESS_HOME_ENABLED),
false, mAssistContentObserver, UserHandle.USER_ALL);
mContentResolver.registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.ASSIST_TOUCH_GESTURE_ENABLED),
false, mAssistContentObserver, UserHandle.USER_ALL);
updateAssitantAvailability();
}
public void destroy() {
mContentResolver.unregisterContentObserver(mAssistContentObserver);
}
/**
* @param listener Will immediately get callbacks based on current state
*/
public void registerNavTaskStateUpdater(NavbarTaskbarStateUpdater listener) {
mA11yEventListeners.add(listener);
listener.updateAccessibilityServicesState();
listener.updateAssistantAvailable(mAssistantAvailable);
}
public void removeNavTaskStateUpdater(NavbarTaskbarStateUpdater listener) {
mA11yEventListeners.remove(listener);
}
private void dispatchA11yEventUpdate() {
for (NavbarTaskbarStateUpdater listener : mA11yEventListeners) {
listener.updateAccessibilityServicesState();
}
}
private void dispatchAssistantEventUpdate(boolean assistantAvailable) {
for (NavbarTaskbarStateUpdater listener : mA11yEventListeners) {
listener.updateAssistantAvailable(assistantAvailable);
}
}
@Override
public void onAccessibilityButtonModeChanged(int mode) {
dispatchA11yEventUpdate();
}
/**
* See {@link QuickStepContract#SYSUI_STATE_A11Y_BUTTON_CLICKABLE} and
* {@link QuickStepContract#SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE}
*
* @return the a11y button clickable and long_clickable states, or 0 if there is no
* a11y button in the navbar
*/
public int getA11yButtonState() {
// AccessibilityManagerService resolves services for the current user since the local
// AccessibilityManager is created from a Context with the INTERACT_ACROSS_USERS permission
final List<String> a11yButtonTargets =
mAccessibilityManager.getAccessibilityShortcutTargets(
AccessibilityManager.ACCESSIBILITY_BUTTON);
final int requestingServices = a11yButtonTargets.size();
// If accessibility button is floating menu mode, click and long click state should be
// disabled.
if (mAccessibilityButtonModeObserver.getCurrentAccessibilityButtonMode()
== 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);
}
@Override
public void onConnectionChanged(boolean isConnected) {
if (isConnected) {
updateAssitantAvailability();
}
}
private void updateAssitantAvailability() {
boolean assistantAvailableForUser = mAssistManagerLazy.get()
.getAssistInfoForUser(UserHandle.USER_CURRENT) != null;
boolean longPressDefault = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_assistLongPressHomeEnabledDefault);
mLongPressHomeEnabled = Settings.Secure.getIntForUser(mContentResolver,
Settings.Secure.ASSIST_LONG_PRESS_HOME_ENABLED, longPressDefault ? 1 : 0,
mUserTracker.getUserId()) != 0;
boolean gestureDefault = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_assistTouchGestureEnabledDefault);
mAssistantTouchGestureEnabled = Settings.Secure.getIntForUser(mContentResolver,
Settings.Secure.ASSIST_TOUCH_GESTURE_ENABLED, gestureDefault ? 1 : 0,
mUserTracker.getUserId()) != 0;
mAssistantAvailable = assistantAvailableForUser
&& mAssistantTouchGestureEnabled
&& QuickStepContract.isGesturalMode(mNavBarMode);
dispatchAssistantEventUpdate(mAssistantAvailable);
}
public boolean getLongPressHomeEnabled() {
return mLongPressHomeEnabled;
}
@Override
public void startAssistant(Bundle bundle) {
mAssistManagerLazy.get().startAssist(bundle);
}
@Override
public void onNavigationModeChanged(int mode) {
mNavBarMode = mode;
updateAssitantAvailability();
}
/**
* Callbacks will get fired once immediately after registering via
* {@link #registerNavTaskStateUpdater(NavbarTaskbarStateUpdater)}
*/
public interface NavbarTaskbarStateUpdater {
void updateAccessibilityServicesState();
void updateAssistantAvailable(boolean available);
}
@Override
public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
pw.println("NavbarTaskbarFriendster");
pw.println(" longPressHomeEnabled=" + mLongPressHomeEnabled);
pw.println(" mAssistantTouchGestureEnabled=" + mAssistantTouchGestureEnabled);
pw.println(" mAssistantAvailable=" + mAssistantAvailable);
pw.println(" mNavBarMode=" + mNavBarMode);
}
}

View File

@@ -68,22 +68,18 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Configuration;
import android.database.ContentObserver;
import android.graphics.Insets;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.RectF;
import android.inputmethodservice.InputMethodService;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.provider.Settings;
import android.telecom.TelecomManager;
import android.text.TextUtils;
import android.util.Log;
@@ -200,8 +196,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
private final Handler mHandler;
private final NavigationBarOverlayController mNavbarOverlayController;
private final UiEventLogger mUiEventLogger;
private final NavigationBarA11yHelper mNavigationBarA11yHelper;
private final UserTracker mUserTracker;
private final NavBarHelper mNavBarHelper;
private final NotificationShadeDepthController mNotificationShadeDepthController;
private Bundle mSavedState;
@@ -213,9 +208,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
private int mNavigationIconHints = 0;
private @TransitionMode int mNavigationBarMode;
private ContentResolver mContentResolver;
private boolean mAssistantAvailable;
private boolean mLongPressHomeEnabled;
private boolean mAssistantTouchGestureEnabled;
private int mDisabledFlags1;
private int mDisabledFlags2;
@@ -309,16 +302,31 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
}
};
private final NavBarHelper.NavbarTaskbarStateUpdater mNavbarTaskbarStateUpdater =
new NavBarHelper.NavbarTaskbarStateUpdater() {
@Override
public void updateAccessibilityServicesState() {
updateAcessibilityStateFlags();
}
@Override
public void updateAssistantAvailable(boolean available) {
// TODO(b/198002034): Content observers currently can still be called back after
// being unregistered, and in this case we can ignore the change if the nav bar
// has been destroyed already
if (mNavigationBarView == null) {
return;
}
mLongPressHomeEnabled = mNavBarHelper.getLongPressHomeEnabled();
updateAssistantEntrypoints(available);
}
};
private final OverviewProxyListener mOverviewProxyListener = new OverviewProxyListener() {
@Override
public void onConnectionChanged(boolean isConnected) {
mNavigationBarView.updateStates();
updateScreenPinningGestures();
// Send the assistant availability upon connection
if (isConnected) {
updateAssistantEntrypoints();
}
}
@Override
@@ -421,20 +429,6 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
}
};
private final ContentObserver mAssistContentObserver = new ContentObserver(
new Handler(Looper.getMainLooper())) {
@Override
public void onChange(boolean selfChange, Uri uri) {
// TODO(b/198002034): Content observers currently can still be called back after being
// unregistered, and in this case we can ignore the change if the nav bar has been
// destroyed already
if (mNavigationBarView == null) {
return;
}
updateAssistantEntrypoints();
}
};
private final DeviceConfig.OnPropertiesChangedListener mOnPropertiesChangedListener =
new DeviceConfig.OnPropertiesChangedListener() {
@Override
@@ -504,7 +498,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
@Main Handler mainHandler,
NavigationBarOverlayController navbarOverlayController,
UiEventLogger uiEventLogger,
NavigationBarA11yHelper navigationBarA11yHelper,
NavBarHelper navBarHelper,
UserTracker userTracker,
LightBarController mainLightBarController,
LightBarController.Factory lightBarControllerFactory,
@@ -535,8 +529,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
mHandler = mainHandler;
mNavbarOverlayController = navbarOverlayController;
mUiEventLogger = uiEventLogger;
mNavigationBarA11yHelper = navigationBarA11yHelper;
mUserTracker = userTracker;
mNavBarHelper = navBarHelper;
mNotificationShadeDepthController = notificationShadeDepthController;
mMainLightBarController = mainLightBarController;
mLightBarControllerFactory = lightBarControllerFactory;
@@ -568,18 +561,9 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
mIsOnDefaultDisplay = mDisplayId == DEFAULT_DISPLAY;
mCommandQueue.addCallback(this);
mAssistantAvailable = mAssistManagerLazy.get()
.getAssistInfoForUser(UserHandle.USER_CURRENT) != null;
mLongPressHomeEnabled = mNavBarHelper.getLongPressHomeEnabled();
mContentResolver = mContext.getContentResolver();
mContentResolver.registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.ASSISTANT),
false /* notifyForDescendants */, mAssistContentObserver, UserHandle.USER_ALL);
mContentResolver.registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.ASSIST_LONG_PRESS_HOME_ENABLED),
false, mAssistContentObserver, UserHandle.USER_ALL);
mContentResolver.registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.ASSIST_TOUCH_GESTURE_ENABLED),
false, mAssistContentObserver, UserHandle.USER_ALL);
mNavBarHelper.init(mContext);
mAllowForceNavBarHandleOpaque = mContext.getResources().getBoolean(
R.bool.allow_force_nav_bar_handle_opaque);
mForceNavBarHandleOpaque = DeviceConfig.getBoolean(
@@ -593,7 +577,6 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
)).filter(duration -> duration != 0);
DeviceConfig.addOnPropertiesChangedListener(
DeviceConfig.NAMESPACE_SYSTEMUI, mHandler::post, mOnPropertiesChangedListener);
updateAssistantEntrypoints();
if (savedState != null) {
mDisabledFlags1 = savedState.getInt(EXTRA_DISABLE_STATE, 0);
@@ -620,8 +603,8 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
mWindowManager.removeViewImmediate(mNavigationBarView.getRootView());
mNavigationModeController.removeListener(this);
mNavigationBarA11yHelper.removeA11yEventListener(mAccessibilityListener);
mContentResolver.unregisterContentObserver(mAssistContentObserver);
mNavBarHelper.removeNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
mNavBarHelper.destroy();
mDeviceProvisionedController.removeCallback(mUserSetupListener);
mNotificationShadeDepthController.removeListener(mDepthListener);
@@ -643,7 +626,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
mNavigationBarView.setWindowVisible(isNavBarWindowVisible());
mNavigationBarView.setBehavior(mBehavior);
mNavigationBarA11yHelper.registerA11yEventListener(mAccessibilityListener);
mNavBarHelper.registerNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
mSplitScreenOptional.ifPresent(mNavigationBarView::registerDockedListener);
mPipOptional.ifPresent(mNavigationBarView::registerPipExclusionBoundsChangeListener);
@@ -716,7 +699,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
mHandler.removeCallbacks(mAutoDim);
mHandler.removeCallbacks(mOnVariableDurationHomeLongClick);
mHandler.removeCallbacks(mEnableLayoutTransitions);
mNavigationBarA11yHelper.removeA11yEventListener(mAccessibilityListener);
mNavBarHelper.removeNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
mFrame = null;
mNavigationBarView = null;
mOrientationHandle = null;
@@ -885,7 +868,6 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
pw.println(" mCurrentRotation=" + mCurrentRotation);
pw.println(" mHomeButtonLongPressDurationMs=" + mHomeButtonLongPressDurationMs);
pw.println(" mLongPressHomeEnabled=" + mLongPressHomeEnabled);
pw.println(" mAssistantTouchGestureEnabled=" + mAssistantTouchGestureEnabled);
pw.println(" mNavigationBarWindowState="
+ windowStateToString(mNavigationBarWindowState));
pw.println(" mNavigationBarMode="
@@ -1165,7 +1147,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
ButtonDispatcher accessibilityButton = mNavigationBarView.getAccessibilityButton();
accessibilityButton.setOnClickListener(this::onAccessibilityClick);
accessibilityButton.setOnLongClickListener(this::onAccessibilityLongClick);
updateAccessibilityServicesState();
updateAcessibilityStateFlags();
ButtonDispatcher imeSwitcherButton = mNavigationBarView.getImeSwitchButton();
imeSwitcherButton.setOnClickListener(this::onImeSwitcherClick);
@@ -1390,8 +1372,8 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
return true;
}
void updateAccessibilityServicesState() {
int a11yFlags = mNavigationBarA11yHelper.getA11yButtonState();
void updateAcessibilityStateFlags() {
int a11yFlags = mNavBarHelper.getA11yButtonState();
if (mNavigationBarView != null) {
boolean clickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0;
@@ -1403,7 +1385,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
public void updateSystemUiStateFlags(int a11yFlags) {
if (a11yFlags < 0) {
a11yFlags = mNavigationBarA11yHelper.getA11yButtonState();
a11yFlags = mNavBarHelper.getA11yButtonState();
}
boolean clickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0;
boolean longClickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0;
@@ -1430,24 +1412,10 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
}
}
private void updateAssistantEntrypoints() {
mAssistantAvailable = mAssistManagerLazy.get()
.getAssistInfoForUser(UserHandle.USER_CURRENT) != null;
boolean longPressDefault = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_assistLongPressHomeEnabledDefault);
mLongPressHomeEnabled = Settings.Secure.getIntForUser(mContentResolver,
Settings.Secure.ASSIST_LONG_PRESS_HOME_ENABLED, longPressDefault ? 1 : 0,
mUserTracker.getUserId()) != 0;
boolean gestureDefault = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_assistTouchGestureEnabledDefault);
mAssistantTouchGestureEnabled = Settings.Secure.getIntForUser(mContentResolver,
Settings.Secure.ASSIST_TOUCH_GESTURE_ENABLED, gestureDefault ? 1 : 0,
mUserTracker.getUserId()) != 0;
private void updateAssistantEntrypoints(boolean assistantAvailable) {
if (mOverviewProxyService.getProxy() != null) {
try {
mOverviewProxyService.getProxy().onAssistantAvailable(mAssistantAvailable
&& mAssistantTouchGestureEnabled
&& QuickStepContract.isGesturalMode(mNavBarMode));
mOverviewProxyService.getProxy().onAssistantAvailable(assistantAvailable);
} catch (RemoteException e) {
Log.w(TAG, "Unable to send assistant availability data to launcher");
}
@@ -1518,8 +1486,6 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
@Override
public void onNavigationModeChanged(int mode) {
mNavBarMode = mode;
// update assistant entry points on system navigation radio button click
updateAssistantEntrypoints();
if (!QuickStepContract.isGesturalMode(mode)) {
// Reset the override alpha
@@ -1558,9 +1524,6 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
mNavigationBarView.getBarTransitions().finishAnimations();
}
private final NavigationBarA11yHelper.NavA11yEventListener mAccessibilityListener =
this::updateAccessibilityServicesState;
private WindowManager.LayoutParams getBarLayoutParams(int rotation) {
WindowManager.LayoutParams lp = getBarLayoutParamsForRotation(rotation);
lp.paramsForRotation = new WindowManager.LayoutParams[4];
@@ -1668,7 +1631,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
}
if (Intent.ACTION_USER_SWITCHED.equals(action)) {
// The accessibility settings may be different for the new user
updateAccessibilityServicesState();
updateAcessibilityStateFlags();
}
}
};
@@ -1704,7 +1667,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
private final Handler mMainHandler;
private final NavigationBarOverlayController mNavbarOverlayController;
private final UiEventLogger mUiEventLogger;
private final NavigationBarA11yHelper mNavigationBarA11yHelper;
private final NavBarHelper mNavBarHelper;
private final UserTracker mUserTracker;
private final LightBarController mMainLightBarController;
private final LightBarController.Factory mLightBarControllerFactory;
@@ -1737,7 +1700,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
@Main Handler mainHandler,
NavigationBarOverlayController navbarOverlayController,
UiEventLogger uiEventLogger,
NavigationBarA11yHelper navigationBarA11yHelper,
NavBarHelper navBarHelper,
UserTracker userTracker,
LightBarController mainLightBarController,
LightBarController.Factory lightBarControllerFactory,
@@ -1767,7 +1730,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
mMainHandler = mainHandler;
mNavbarOverlayController = navbarOverlayController;
mUiEventLogger = uiEventLogger;
mNavigationBarA11yHelper = navigationBarA11yHelper;
mNavBarHelper = navBarHelper;
mUserTracker = userTracker;
mMainLightBarController = mainLightBarController;
mLightBarControllerFactory = lightBarControllerFactory;
@@ -1788,7 +1751,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
mSplitScreenOptional, mRecentsOptional, mStatusBarOptionalLazy,
mShadeController, mNotificationRemoteInputManager,
mNotificationShadeDepthController, mSystemActions, mMainHandler,
mNavbarOverlayController, mUiEventLogger, mNavigationBarA11yHelper,
mNavbarOverlayController, mUiEventLogger, mNavBarHelper,
mUserTracker, mMainLightBarController, mLightBarControllerFactory,
mMainAutoHideController, mAutoHideControllerFactory, mTelecomManagerOptional,
mInputMethodManager);

View File

@@ -1,90 +0,0 @@
package com.android.systemui.navigationbar;
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_CLICKABLE;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE;
import android.view.accessibility.AccessibilityManager;
import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
/**
* Extracts shared elements of a11y necessary between navbar and taskbar delegate
*/
@SysUISingleton
public final class NavigationBarA11yHelper implements
AccessibilityButtonModeObserver.ModeChangedListener {
private final AccessibilityManager mAccessibilityManager;
private final AccessibilityButtonModeObserver mAccessibilityButtonModeObserver;
private final List<NavA11yEventListener> mA11yEventListeners = new ArrayList<>();
@Inject
public NavigationBarA11yHelper(AccessibilityManager accessibilityManager,
AccessibilityManagerWrapper accessibilityManagerWrapper,
AccessibilityButtonModeObserver accessibilityButtonModeObserver) {
mAccessibilityManager = accessibilityManager;
accessibilityManagerWrapper.addCallback(
accessibilityManager1 -> NavigationBarA11yHelper.this.dispatchEventUpdate());
mAccessibilityButtonModeObserver = accessibilityButtonModeObserver;
mAccessibilityButtonModeObserver.addListener(this);
}
public void registerA11yEventListener(NavA11yEventListener listener) {
mA11yEventListeners.add(listener);
}
public void removeA11yEventListener(NavA11yEventListener listener) {
mA11yEventListeners.remove(listener);
}
private void dispatchEventUpdate() {
for (NavA11yEventListener listener : mA11yEventListeners) {
listener.updateAccessibilityServicesState();
}
}
@Override
public void onAccessibilityButtonModeChanged(int mode) {
dispatchEventUpdate();
}
/**
* See {@link QuickStepContract#SYSUI_STATE_A11Y_BUTTON_CLICKABLE} and
* {@link QuickStepContract#SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE}
*
* @return the a11y button clickable and long_clickable states, or 0 if there is no
* a11y button in the navbar
*/
public int getA11yButtonState() {
// AccessibilityManagerService resolves services for the current user since the local
// AccessibilityManager is created from a Context with the INTERACT_ACROSS_USERS permission
final List<String> a11yButtonTargets =
mAccessibilityManager.getAccessibilityShortcutTargets(
AccessibilityManager.ACCESSIBILITY_BUTTON);
final int requestingServices = a11yButtonTargets.size();
// If accessibility button is floating menu mode, click and long click state should be
// disabled.
if (mAccessibilityButtonModeObserver.getCurrentAccessibilityButtonMode()
== 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);
}
public interface NavA11yEventListener {
void updateAccessibilityServicesState();
}
}

View File

@@ -100,7 +100,7 @@ public class NavigationBarController implements
CommandQueue commandQueue,
@Main Handler mainHandler,
ConfigurationController configurationController,
NavigationBarA11yHelper navigationBarA11yHelper,
NavBarHelper navBarHelper,
TaskbarDelegate taskbarDelegate,
NavigationBar.Factory navigationBarFactory,
DumpManager dumpManager,
@@ -115,7 +115,7 @@ public class NavigationBarController implements
mNavMode = navigationModeController.addListener(this);
mTaskbarDelegate = taskbarDelegate;
mTaskbarDelegate.setDependencies(commandQueue, overviewProxyService,
navigationBarA11yHelper, navigationModeController, sysUiFlagsContainer,
navBarHelper, navigationModeController, sysUiFlagsContainer,
dumpManager, autoHideController);
mIsTablet = isTablet(mContext);
dumpManager.registerDumpable(this);

View File

@@ -43,6 +43,8 @@ import android.content.res.Configuration;
import android.hardware.display.DisplayManager;
import android.inputmethodservice.InputMethodService;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.Display;
import android.view.InsetsVisibilities;
import android.view.View;
@@ -73,19 +75,30 @@ import javax.inject.Singleton;
public class TaskbarDelegate implements CommandQueue.Callbacks,
OverviewProxyService.OverviewProxyListener, NavigationModeController.ModeChangedListener,
ComponentCallbacks, Dumpable {
private static final String TAG = TaskbarDelegate.class.getSimpleName();
private final EdgeBackGestureHandler mEdgeBackGestureHandler;
private boolean mInitialized;
private CommandQueue mCommandQueue;
private OverviewProxyService mOverviewProxyService;
private NavigationBarA11yHelper mNavigationBarA11yHelper;
private NavBarHelper mNavBarHelper;
private NavigationModeController mNavigationModeController;
private SysUiState mSysUiState;
private AutoHideController mAutoHideController;
private int mDisplayId;
private int mNavigationIconHints;
private final NavigationBarA11yHelper.NavA11yEventListener mNavA11yEventListener =
this::updateSysuiFlags;
private final NavBarHelper.NavbarTaskbarStateUpdater mNavbarTaskbarStateUpdater =
new NavBarHelper.NavbarTaskbarStateUpdater() {
@Override
public void updateAccessibilityServicesState() {
updateSysuiFlags();
}
@Override
public void updateAssistantAvailable(boolean available) {
updateAssistantAvailability(available);
}
};
private int mDisabledFlags;
private @WindowVisibleState int mTaskBarWindowState = WINDOW_STATE_SHOWING;
private @Behavior int mBehavior;
@@ -125,14 +138,14 @@ public class TaskbarDelegate implements CommandQueue.Callbacks,
public void setDependencies(CommandQueue commandQueue,
OverviewProxyService overviewProxyService,
NavigationBarA11yHelper navigationBarA11yHelper,
NavBarHelper navBarHelper,
NavigationModeController navigationModeController,
SysUiState sysUiState, DumpManager dumpManager,
AutoHideController autoHideController) {
// TODO: adding this in the ctor results in a dagger dependency cycle :(
mCommandQueue = commandQueue;
mOverviewProxyService = overviewProxyService;
mNavigationBarA11yHelper = navigationBarA11yHelper;
mNavBarHelper = navBarHelper;
mNavigationModeController = navigationModeController;
mSysUiState = sysUiState;
dumpManager.registerDumpable(this);
@@ -140,12 +153,16 @@ public class TaskbarDelegate implements CommandQueue.Callbacks,
}
public void init(int displayId) {
if (mInitialized) {
return;
}
mDisplayId = displayId;
mCommandQueue.addCallback(this);
mOverviewProxyService.addCallback(this);
mEdgeBackGestureHandler.onNavigationModeChanged(
mNavigationModeController.addListener(this));
mNavigationBarA11yHelper.registerA11yEventListener(mNavA11yEventListener);
mNavBarHelper.registerNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
mNavBarHelper.init(mContext);
mEdgeBackGestureHandler.onNavBarAttached();
// Initialize component callback
Display display = mDisplayManager.getDisplay(displayId);
@@ -154,23 +171,29 @@ public class TaskbarDelegate implements CommandQueue.Callbacks,
// Set initial state for any listeners
updateSysuiFlags();
mAutoHideController.setNavigationBar(mAutoHideUiElement);
mInitialized = true;
}
public void destroy() {
if (!mInitialized) {
return;
}
mCommandQueue.removeCallback(this);
mOverviewProxyService.removeCallback(this);
mNavigationModeController.removeListener(this);
mNavigationBarA11yHelper.removeA11yEventListener(mNavA11yEventListener);
mNavBarHelper.removeNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
mNavBarHelper.destroy();
mEdgeBackGestureHandler.onNavBarDetached();
if (mWindowContext != null) {
mWindowContext.unregisterComponentCallbacks(this);
mWindowContext = null;
}
mAutoHideController.setNavigationBar(null);
mInitialized = false;
}
private void updateSysuiFlags() {
int a11yFlags = mNavigationBarA11yHelper.getA11yButtonState();
int a11yFlags = mNavBarHelper.getA11yButtonState();
boolean clickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0;
boolean longClickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0;
@@ -194,6 +217,18 @@ public class TaskbarDelegate implements CommandQueue.Callbacks,
.commitUpdate(mDisplayId);
}
private void updateAssistantAvailability(boolean assistantAvailable) {
if (mOverviewProxyService.getProxy() == null) {
return;
}
try {
mOverviewProxyService.getProxy().onAssistantAvailable(assistantAvailable);
} catch (RemoteException e) {
Log.e(TAG, "onAssistantAvailable() failed, available: " + assistantAvailable, e);
}
}
@Override
public void setImeWindowStatus(int displayId, IBinder token, int vis, int backDisposition,
boolean showImeSwitcher) {

View File

@@ -0,0 +1,178 @@
/*
* 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.navigationbar;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.ComponentName;
import android.view.accessibility.AccessibilityManager;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.recents.OverviewProxyService;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import dagger.Lazy;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class NavBarHelperTest extends SysuiTestCase {
@Mock
AccessibilityManager mAccessibilityManager;
@Mock
AccessibilityManagerWrapper mAccessibilityManagerWrapper;
@Mock
AccessibilityButtonModeObserver mAccessibilityButtonModeObserver;
@Mock
OverviewProxyService mOverviewProxyService;
@Mock
Lazy<AssistManager> mAssistManagerLazy;
@Mock
AssistManager mAssistManager;
@Mock
NavigationModeController mNavigationModeController;
@Mock
UserTracker mUserTracker;
@Mock
ComponentName mAssistantComponent;
@Mock
DumpManager mDumpManager;
@Mock
NavBarHelper.NavbarTaskbarStateUpdater mNavbarTaskbarStateUpdater;
private NavBarHelper mNavBarHelper;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
when(mAssistManagerLazy.get()).thenReturn(mAssistManager);
when(mAssistManager.getAssistInfoForUser(anyInt())).thenReturn(mAssistantComponent);
when(mUserTracker.getUserId()).thenReturn(1);
mNavBarHelper = new NavBarHelper(mAccessibilityManager,
mAccessibilityManagerWrapper, mAccessibilityButtonModeObserver,
mOverviewProxyService, mAssistManagerLazy, mNavigationModeController,
mUserTracker, mDumpManager);
}
@Test
public void registerListenersInCtor() {
verify(mAccessibilityButtonModeObserver, times(1)).addListener(mNavBarHelper);
verify(mNavigationModeController, times(1)).addListener(mNavBarHelper);
verify(mOverviewProxyService, times(1)).addCallback(mNavBarHelper);
}
@Test
public void registerAssistantContentObserver() {
mNavBarHelper.init(mContext);
verify(mAssistManager, times(1)).getAssistInfoForUser(anyInt());
}
@Test
public void callbacksFiredWhenRegistering() {
mNavBarHelper.init(mContext);
mNavBarHelper.registerNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
verify(mNavbarTaskbarStateUpdater, times(1))
.updateAccessibilityServicesState();
verify(mNavbarTaskbarStateUpdater, times(1))
.updateAssistantAvailable(anyBoolean());
}
@Test
public void assistantCallbacksFiredAfterConnecting() {
mNavBarHelper.init(mContext);
// 1st set of callbacks get called when registering
mNavBarHelper.registerNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
mNavBarHelper.onConnectionChanged(false);
// assert no more callbacks fired
verify(mNavbarTaskbarStateUpdater, times(1))
.updateAccessibilityServicesState();
verify(mNavbarTaskbarStateUpdater, times(1))
.updateAssistantAvailable(anyBoolean());
mNavBarHelper.onConnectionChanged(true);
// assert no more callbacks fired
verify(mNavbarTaskbarStateUpdater, times(1))
.updateAccessibilityServicesState();
verify(mNavbarTaskbarStateUpdater, times(2))
.updateAssistantAvailable(anyBoolean());
}
@Test
public void a11yCallbacksFiredAfterModeChange() {
mNavBarHelper.init(mContext);
// 1st set of callbacks get called when registering
mNavBarHelper.registerNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
mNavBarHelper.onAccessibilityButtonModeChanged(0);
verify(mNavbarTaskbarStateUpdater, times(2))
.updateAccessibilityServicesState();
verify(mNavbarTaskbarStateUpdater, times(1))
.updateAssistantAvailable(anyBoolean());
}
@Test
public void assistantCallbacksFiredAfterNavModeChange() {
mNavBarHelper.init(mContext);
// 1st set of callbacks get called when registering
mNavBarHelper.registerNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
mNavBarHelper.onNavigationModeChanged(0);
verify(mNavbarTaskbarStateUpdater, times(1))
.updateAccessibilityServicesState();
verify(mNavbarTaskbarStateUpdater, times(2))
.updateAssistantAvailable(anyBoolean());
}
@Test
public void removeListenerNoCallbacksFired() {
mNavBarHelper.init(mContext);
// 1st set of callbacks get called when registering
mNavBarHelper.registerNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
// Remove listener
mNavBarHelper.removeNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
// Would have fired 2nd callback if not removed
mNavBarHelper.onAccessibilityButtonModeChanged(0);
// assert no more callbacks fired
verify(mNavbarTaskbarStateUpdater, times(1))
.updateAccessibilityServicesState();
verify(mNavbarTaskbarStateUpdater, times(1))
.updateAssistantAvailable(anyBoolean());
}
}

View File

@@ -82,7 +82,7 @@ public class NavigationBarControllerTest extends SysuiTestCase {
mCommandQueue,
Dependency.get(Dependency.MAIN_HANDLER),
mock(ConfigurationController.class),
mock(NavigationBarA11yHelper.class),
mock(NavBarHelper.class),
mock(TaskbarDelegate.class),
mNavigationBarFactory,
mock(DumpManager.class),

View File

@@ -131,7 +131,7 @@ public class NavigationBarTest extends SysuiTestCase {
@Mock
EdgeBackGestureHandler mEdgeBackGestureHandler;
@Mock
NavigationBarA11yHelper mNavigationBarA11yHelper;
NavBarHelper mNavBarHelper;
@Mock
private LightBarController mLightBarController;
@Mock
@@ -220,6 +220,7 @@ public class NavigationBarTest extends SysuiTestCase {
new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_SYSTEMUI)
.setLong(HOME_BUTTON_LONG_PRESS_DURATION_MS, 100)
.build());
when(mNavBarHelper.getLongPressHomeEnabled()).thenReturn(true);
mNavigationBar.onViewAttachedToWindow(mNavigationBar.createView(null));
mNavigationBar.onHomeTouch(mNavigationBar.getView(), MotionEvent.obtain(
@@ -284,14 +285,14 @@ public class NavigationBarTest extends SysuiTestCase {
public void testA11yEventAfterDetach() {
View v = mNavigationBar.createView(null);
mNavigationBar.onViewAttachedToWindow(v);
verify(mNavigationBarA11yHelper).registerA11yEventListener(any(
NavigationBarA11yHelper.NavA11yEventListener.class));
verify(mNavBarHelper).registerNavTaskStateUpdater(any(
NavBarHelper.NavbarTaskbarStateUpdater.class));
mNavigationBar.onViewDetachedFromWindow(v);
verify(mNavigationBarA11yHelper).removeA11yEventListener(any(
NavigationBarA11yHelper.NavA11yEventListener.class));
verify(mNavBarHelper).removeNavTaskStateUpdater(any(
NavBarHelper.NavbarTaskbarStateUpdater.class));
// Should be safe even though the internal view is now null.
mNavigationBar.updateAccessibilityServicesState();
mNavigationBar.updateAcessibilityStateFlags();
}
private NavigationBar createNavBar(Context context) {
@@ -321,7 +322,7 @@ public class NavigationBarTest extends SysuiTestCase {
mHandler,
mock(NavigationBarOverlayController.class),
mUiEventLogger,
mNavigationBarA11yHelper,
mNavBarHelper,
mock(UserTracker.class),
mLightBarController,
mLightBarcontrollerFactory,