Android SystemUI之NavigationBar
packages/apps/Settings/src/com/android/settings/gestures/SystemNavigationGestureSettings.java
frameworks/base/core/java/android/content/om/OverlayManager.java
frameworks/base/services/core/java/com/android/server/om/OverlayManagerService.java
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
frameworks/base/services/core/java/com/android/server/am/ProcessList.java
frameworks/base/core/java/android/app/ActivityThread.java
frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
frameworks/base/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationModeController.java
frameworks/base/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
frameworks/base/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
frameworks/base/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
frameworks/base/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarInflaterView.java
frameworks/base/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
packages/apps/Launcher3/src/com/android/launcher3/util/DisplayController.java
packages/apps/Launcher3/quickstep/src/com/android/quickstep/TouchInteractionService.java
#SystemNavigationGestureSettings.java
|-setCurrentSystemNavigationMode(IOverlayManager overlayManager, String key)
|_overlayManager.setEnabledExclusiveInCategory(overlayPackage, USER_CURRENT)
#OverlayManager.java
|-setEnabledExclusiveInCategory(@NonNull final String packageName, @NonNull UserHandle user)
|_mService.setEnabledExclusiveInCategory(packageName, user.getIdentifier())
#OverlayManagerService.java
|-setEnabledExclusiveInCategory(@Nullable String packageName,final int userIdArg)
|_mImpl.setEnabledExclusive(overlay, true /* withinCategory */, realUserId).ifPresent(OverlayManagerService.this::updateTargetPackagesLocked);
|_updateTargetPackagesLocked(@Nullable Set updatedTargets)
|_updateActivityManager(affectedPackages, userId);
| |_am.scheduleApplicationInfoChanged(targetPackageNames, userId);
| #ActivityManagerService.java
| |-scheduleApplicationInfoChanged(List packageNames, int userId)
| |_updateApplicationInfoLOSP(@NonNull List packagesToUpdate,boolean updateFrameworkRes, int userId)
| |_mProcessList.updateApplicationInfoLOSP(packagesToUpdate, userId, updateFrameworkRes);
| | #ProcessList.java
| | |-updateApplicationInfoLOSP(List packagesToUpdate, int userId,boolean updateFrameworkRes)
| | |_app.getThread().scheduleApplicationInfoChanged(ai);
| | | #ActivityThread.java
| | | |-scheduleApplicationInfoChanged(ApplicationInfo ai)
| | | |_sendMessage(H.APPLICATION_INFO_CHANGED, ai);
| | | |_handleApplicationInfoChanged(@NonNull final ApplicationInfo ai)
| | |_mService.mActivityTaskManager.updateAssetConfiguration(targetProcesses, updateFrameworkRes);
| | #ActivityTaskManagerService.java
| | |-updateAssetConfiguration(List processes,boolean updateFrameworkRes)
| | |_updateConfiguration(newConfig);
| | | |_updateConfigurationLocked(Configuration values, ActivityRecord starting,boolean initLocale, boolean persistent, int userId, boolean deferResume,ActivityTaskManagerService.UpdateConfigurationResult result)
| | | |_updateGlobalConfigurationLocked(@NonNull Configuration values, boolean initLocale,boolean persistent, int userId, boolean deferResume)
| | |_wpc.updateAssetConfiguration(assetSeq);
| |_executor.execute(display::onOverlayChanged);
| |_executor.execute(mWindowManager::onOverlayChanged);
|_broadcastActionOverlayChanged(targets, userId);
|_ ActivityManager.getService().broadcastIntent(null, intent, null, null, 0, null,null, null, android.app.AppOpsManager.OP_NONE, null, false, false, userId);//ACTION_OVERLAY_CHANGED
#NavigationModeController.java
| |-onReceive(Context context, Intent intent)
| |_updateCurrentInteractionMode(true /* notify */);
| |_mListeners.get(i).onNavigationModeChanged(mode);
| #NavigationBar.java
| |-onNavigationModeChanged(int mode)
| | |_updateScreenPinningGestures();
| | |_ setNavBarMode(mode);
| | |_mView.setShouldShowSwipeUpUi(mOverviewProxyService.shouldShowSwipeUpUI());
| #NavigationBarController..java
| |-onNavigationModeChanged(int mode)
| | |_navBar.getView().updateStates();
| | #NavigationBarView.java
| | |-updateStates()
| | |_mNavigationInflaterView.onLikelyDefaultLayoutChange();
| | #NavigationBarInflaterView.java
| | |-onLikelyDefaultLayoutChange()
| | |_getDefaultLayout()
| #EdgeBackGestureHandler.java
| |-onNavigationModeChanged(int mode)
| |_updateIsEnabled();
| |_ mInputMonitor = InputManager.getInstance().monitorGestureInput("edge-swipe", mDisplayId);
| |_mInputEventReceiver = new InputChannelCompat.InputEventReceiver(mInputMonitor.getInputChannel(), Looper.getMainLooper(),Choreographer.getInstance(), this::onInputEvent);
#DisplayController.java
|-onIntent(Intent intent)
| |_handleInfoChange(display);
| |_MAIN_EXECUTOR.execute(() -> notifyChange(displayInfoContext, flags));
#TouchInteractionService.java
|-initInputMonitor("onNavigationModeChanged()");
|_mInputMonitorCompat = new InputMonitorCompat("swipe-up", mDeviceState.getDisplayId());
|_mInputEventReceiver = mInputMonitorCompat.getInputReceiver(Looper.getMainLooper(),mMainChoreographer, this::onInputEvent);
<-SystemNavigationGestureSettings.java>
static void setCurrentSystemNavigationMode(IOverlayManager overlayManager, String key) {
String overlayPackage = NAV_BAR_MODE_GESTURAL_OVERLAY;
switch (key) {
case KEY_SYSTEM_NAV_GESTURAL:
overlayPackage = NAV_BAR_MODE_GESTURAL_OVERLAY;
break;
case KEY_SYSTEM_NAV_2BUTTONS:
overlayPackage = NAV_BAR_MODE_2BUTTON_OVERLAY;
break;
case KEY_SYSTEM_NAV_3BUTTONS:
overlayPackage = NAV_BAR_MODE_3BUTTON_OVERLAY;
break;
}
try {
overlayManager.setEnabledExclusiveInCategory(overlayPackage, USER_CURRENT);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
<-OverlayManager.java>
/*packageName:
*/product/overlay/NavigationBarModeGestural/NavigationBarModeGesturalOverlay.apk
*/product/overlay/NavigationBarMode3Button/NavigationBarMode3ButtonOverlay.apk
*/
public void setEnabledExclusiveInCategory(@NonNull final String packageName,
@NonNull UserHandle user) throws SecurityException, IllegalStateException {
try {
if (!mService.setEnabledExclusiveInCategory(packageName, user.getIdentifier())) {
throw new IllegalStateException("setEnabledExclusiveInCategory failed");
}
} catch (SecurityException e) {
rethrowSecurityException(e);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
<-OverlayManagerService.java>
@Override
public boolean setEnabledExclusiveInCategory(@Nullable String packageName,
final int userIdArg) {
if (packageName == null) {
return false;
}
try {
traceBegin(TRACE_TAG_RRO, "OMS#setEnabledExclusiveInCategory " + packageName);
final OverlayIdentifier overlay = new OverlayIdentifier(packageName);
final int realUserId = handleIncomingUser(userIdArg,
"setEnabledExclusiveInCategory");
enforceActor(overlay, "setEnabledExclusiveInCategory", realUserId);
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
try {
mImpl.setEnabledExclusive(overlay,
true /* withinCategory */, realUserId)
.ifPresent(OverlayManagerService.this::updateTargetPackagesLocked);
return true;
} catch (OperationFailedException e) {
return false;
}
}
} finally {
Binder.restoreCallingIdentity(ident);
}
} finally {
traceEnd(TRACE_TAG_RRO);
}
}
private void updateTargetPackagesLocked(@Nullable Set updatedTargets) {
if (CollectionUtils.isEmpty(updatedTargets)) {
return;
}
persistSettingsLocked();
final SparseArray> userTargets = groupTargetsByUserId(updatedTargets);
for (int i = 0, n = userTargets.size(); i < n; i++) {
final ArraySet targets = userTargets.valueAt(i);
final int userId = userTargets.keyAt(i);
final List affectedPackages = updatePackageManagerLocked(targets, userId);
if (affectedPackages.isEmpty()) {
// The package manager paths are already up-to-date.
continue;
}
FgThread.getHandler().post(() -> {
// Send configuration changed events for all target packages that have been affected
// by overlay state changes.
updateActivityManager(affectedPackages, userId);//更新所有应用的资源配置
// Do not send broadcasts for all affected targets. Overlays targeting the framework
// or shared libraries may cause too many broadcasts to be sent at once.
broadcastActionOverlayChanged(targets, userId);
});
}
}
private void updateActivityManager(@NonNull List targetPackageNames, final int userId) {
final IActivityManager am = ActivityManager.getService();
try {
am.scheduleApplicationInfoChanged(targetPackageNames, userId);
} catch (RemoteException e) {
Slog.e(TAG, "updateActivityManager remote exception", e);
}
}
private static void broadcastActionOverlayChanged(@NonNull final Set targetPackages,
final int userId) {
CollectionUtils.forEach(targetPackages, target -> {
final Intent intent = new Intent(ACTION_OVERLAY_CHANGED,
Uri.fromParts("package", target, null));
intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
try {
ActivityManager.getService().broadcastIntent(null, intent, null, null, 0, null,
null, null, android.app.AppOpsManager.OP_NONE, null, false, false, userId);
} catch (RemoteException e) {
Slog.e(TAG, "broadcastActionOverlayChanged remote exception", e);
}
});
}
<-ActivityManagerService.java>
@Override
public void scheduleApplicationInfoChanged(List packageNames, int userId) {
enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
"scheduleApplicationInfoChanged()");
final long origId = Binder.clearCallingIdentity();
try {
final boolean updateFrameworkRes = packageNames.contains("android");
synchronized (mProcLock) {
updateApplicationInfoLOSP(packageNames, updateFrameworkRes, userId);
}
AppWidgetManagerInternal widgets = LocalServices.getService(
AppWidgetManagerInternal.class);
if (widgets != null) {
widgets.applyResourceOverlaysToWidgets(new HashSet<>(packageNames), userId,
updateFrameworkRes);
}
} finally {
Binder.restoreCallingIdentity(origId);
}
}
@GuardedBy(anyOf = {"this", "mProcLock"})
private void updateApplicationInfoLOSP(@NonNull List packagesToUpdate,
boolean updateFrameworkRes, int userId) {
if (updateFrameworkRes) {
ParsingPackageUtils.readConfigUseRoundIcon(null);
}
mProcessList.updateApplicationInfoLOSP(packagesToUpdate, userId, updateFrameworkRes);
if (updateFrameworkRes) {
// Update system server components that need to know about changed overlays. Because the
// overlay is applied in ActivityThread, we need to serialize through its thread too.
final Executor executor = ActivityThread.currentActivityThread().getExecutor();
final DisplayManagerInternal display =
LocalServices.getService(DisplayManagerInternal.class);
if (display != null) {
executor.execute(display::onOverlayChanged);
}
if (mWindowManager != null) {
executor.execute(mWindowManager::onOverlayChanged);
}
}
}
<-ProcessList.java>
@GuardedBy(anyOf = {"mService", "mProcLock"})
void updateApplicationInfoLOSP(List packagesToUpdate, int userId,
boolean updateFrameworkRes) {
final ArrayList targetProcesses = new ArrayList<>();
for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
final ProcessRecord app = mLruProcesses.get(i);
if (app.getThread() == null) {
continue;
}
if (userId != UserHandle.USER_ALL && app.userId != userId) {
continue;
}
app.getPkgList().forEachPackage(packageName -> {
if (updateFrameworkRes || packagesToUpdate.contains(packageName)) {
try {
final ApplicationInfo ai = AppGlobals.getPackageManager()
.getApplicationInfo(packageName, STOCK_PM_FLAGS, app.userId);
if (ai != null) {
if (ai.packageName.equals(app.info.packageName)) {
app.info = ai;
PlatformCompatCache.getInstance()
.onApplicationInfoChanged(ai);
}
app.getThread().scheduleApplicationInfoChanged(ai);
targetProcesses.add(app.getWindowProcessController());
}
} catch (RemoteException e) {
Slog.w(TAG, String.format("Failed to update %s ApplicationInfo for %s",
packageName, app));
}
}
});
}
mService.mActivityTaskManager.updateAssetConfiguration(targetProcesses, updateFrameworkRes);
}
<-ActivityThread.java>
public void scheduleApplicationInfoChanged(ApplicationInfo ai) {
mResourcesManager.appendPendingAppInfoUpdate(new String[]{ai.sourceDir}, ai);
mH.removeMessages(H.APPLICATION_INFO_CHANGED, ai);
sendMessage(H.APPLICATION_INFO_CHANGED, ai);
}
public void handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
switch (msg.what) {
...
case APPLICATION_INFO_CHANGED:
handleApplicationInfoChanged((ApplicationInfo) msg.obj);
break;
...
}
Object obj = msg.obj;
if (obj instanceof SomeArgs) {
((SomeArgs) obj).recycle();
}
if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + codeToString(msg.what));
}
}
@VisibleForTesting(visibility = PACKAGE)
public void handleApplicationInfoChanged(@NonNull final ApplicationInfo ai) {
// Updates triggered by package installation go through a package update
// receiver. Here we try to capture ApplicationInfo changes that are
// caused by other sources, such as overlays. That means we want to be as conservative
// about code changes as possible. Take the diff of the old ApplicationInfo and the new
// to see if anything needs to change.
LoadedApk apk;
LoadedApk resApk;
// Update all affected loaded packages with new package information
synchronized (mResourcesManager) {
WeakReference ref = mPackages.get(ai.packageName);
apk = ref != null ? ref.get() : null;
ref = mResourcePackages.get(ai.packageName);
resApk = ref != null ? ref.get() : null;
}
if (apk != null) {
final ArrayList oldPaths = new ArrayList<>();
LoadedApk.makePaths(this, apk.getApplicationInfo(), oldPaths);
apk.updateApplicationInfo(ai, oldPaths);
}
if (resApk != null) {
final ArrayList oldPaths = new ArrayList<>();
LoadedApk.makePaths(this, resApk.getApplicationInfo(), oldPaths);
resApk.updateApplicationInfo(ai, oldPaths);
}
synchronized (mResourcesManager) {
// Update all affected Resources objects to use new ResourcesImpl
mResourcesManager.applyAllPendingAppInfoUpdates();
}
}
<-ActivityTaskManagerService.java>
public void updateAssetConfiguration(List processes,
boolean updateFrameworkRes) {
synchronized (mGlobalLock) {
final int assetSeq = increaseAssetConfigurationSeq();
if (updateFrameworkRes) {
Configuration newConfig = new Configuration();
newConfig.assetsSeq = assetSeq;
updateConfiguration(newConfig);
}
// Always update the override of every process so the asset sequence of the process is
// always greater than or equal to the global configuration.
for (int i = processes.size() - 1; i >= 0; i--) {
final WindowProcessController wpc = processes.get(i);
wpc.updateAssetConfiguration(assetSeq);
}
}
}
@Override
public boolean updateConfiguration(Configuration values) {
mAmInternal.enforceCallingPermission(CHANGE_CONFIGURATION, "updateConfiguration()");
synchronized (mGlobalLock) {
if (mWindowManager == null) {
Slog.w(TAG, "Skip updateConfiguration because mWindowManager isn't set");
return false;
}
if (values == null) {
// sentinel: fetch the current configuration from the window manager
values = mWindowManager.computeNewConfiguration(DEFAULT_DISPLAY);
}
mH.sendMessage(PooledLambda.obtainMessage(
ActivityManagerInternal::updateOomLevelsForDisplay, mAmInternal,
DEFAULT_DISPLAY));
final long origId = Binder.clearCallingIdentity();
try {
if (values != null) {
Settings.System.clearConfiguration(values);
}
updateConfigurationLocked(values, null, false, false /* persistent */,
UserHandle.USER_NULL, false /* deferResume */,
mTmpUpdateConfigurationResult);
return mTmpUpdateConfigurationResult.changes != 0;
} finally {
Binder.restoreCallingIdentity(origId);
}
}
}
boolean updateConfigurationLocked(Configuration values, ActivityRecord starting,
boolean initLocale, boolean persistent, int userId, boolean deferResume,
ActivityTaskManagerService.UpdateConfigurationResult result) {
int changes = 0;
boolean kept = true;
deferWindowLayout();
try {
if (values != null) {
changes = updateGlobalConfigurationLocked(values, initLocale, persistent, userId,
deferResume);
}
kept = ensureConfigAndVisibilityAfterUpdate(starting, changes);
} finally {
continueWindowLayout();
}
if (result != null) {
result.changes = changes;
result.activityRelaunched = !kept;
}
return kept;
}
int updateGlobalConfigurationLocked(@NonNull Configuration values, boolean initLocale,
boolean persistent, int userId, boolean deferResume) {
final DisplayContent defaultDisplay =
mRootWindowContainer.getDisplayContent(DEFAULT_DISPLAY);
mTempConfig.setTo(getGlobalConfiguration());
final int changes = mTempConfig.updateFrom(values);
if (changes == 0) {
// Since calling to Activity.setRequestedOrientation leads to freezing the window with
// setting WindowManagerService.mWaitingForConfig to true, it is important that we call
// performDisplayOverrideConfigUpdate in order to send the new display configuration
// (even if there are no actual changes) to unfreeze the window.
defaultDisplay.performDisplayOverrideConfigUpdate(values, deferResume);
return 0;
}
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.i(TAG_CONFIGURATION,
"Updating global configuration to: " + values);
writeConfigurationChanged(changes);
FrameworkStatsLog.write(FrameworkStatsLog.RESOURCE_CONFIGURATION_CHANGED,
values.colorMode,
values.densityDpi,
values.fontScale,
values.hardKeyboardHidden,
values.keyboard,
values.keyboardHidden,
values.mcc,
values.mnc,
values.navigation,
values.navigationHidden,
values.orientation,
values.screenHeightDp,
values.screenLayout,
values.screenWidthDp,
values.smallestScreenWidthDp,
values.touchscreen,
values.uiMode);
if (!initLocale && !values.getLocales().isEmpty() && values.userSetLocale) {
final LocaleList locales = values.getLocales();
int bestLocaleIndex = 0;
if (locales.size() > 1) {
if (mSupportedSystemLocales == null) {
mSupportedSystemLocales = Resources.getSystem().getAssets().getLocales();
}
bestLocaleIndex = Math.max(0, locales.getFirstMatchIndex(mSupportedSystemLocales));
}
SystemProperties.set("persist.sys.locale",
locales.get(bestLocaleIndex).toLanguageTag());
LocaleList.setDefault(locales, bestLocaleIndex);
final Message m = PooledLambda.obtainMessage(
ActivityTaskManagerService::sendLocaleToMountDaemonMsg, this,
locales.get(bestLocaleIndex));
mH.sendMessage(m);
}
mTempConfig.seq = increaseConfigurationSeqLocked();
// Update stored global config and notify everyone about the change.
mRootWindowContainer.onConfigurationChanged(mTempConfig);
Slog.i(TAG, "Config changes=" + Integer.toHexString(changes) + " " + mTempConfig);
// TODO(multi-display): Update UsageEvents#Event to include displayId.
mUsageStatsInternal.reportConfigurationChange(mTempConfig, mAmInternal.getCurrentUserId());
// TODO: If our config changes, should we auto dismiss any currently showing dialogs?
updateShouldShowDialogsLocked(mTempConfig);
AttributeCache ac = AttributeCache.instance();
if (ac != null) {
ac.updateConfiguration(mTempConfig);
}
// Make sure all resources in our process are updated right now, so that anyone who is going
// to retrieve resource values after we return will be sure to get the new ones. This is
// especially important during boot, where the first config change needs to guarantee all
// resources have that config before following boot code is executed.
mSystemThread.applyConfigurationToResources(mTempConfig);
// We need another copy of global config because we're scheduling some calls instead of
// running them in place. We need to be sure that object we send will be handled unchanged.
final Configuration configCopy = new Configuration(mTempConfig);
if (persistent && Settings.System.hasInterestingConfigurationChanges(changes)) {
final Message msg = PooledLambda.obtainMessage(
ActivityTaskManagerService::sendPutConfigurationForUserMsg,
this, userId, configCopy);
mH.sendMessage(msg);
}
SparseArray pidMap = mProcessMap.getPidMap();
for (int i = pidMap.size() - 1; i >= 0; i--) {
final int pid = pidMap.keyAt(i);
final WindowProcessController app = pidMap.get(pid);
if (DEBUG_CONFIGURATION) {
Slog.v(TAG_CONFIGURATION, "Update process config of "
+ app.mName + " to new config " + configCopy);
}
app.onConfigurationChanged(configCopy);
}
final Message msg = PooledLambda.obtainMessage(
ActivityManagerInternal::broadcastGlobalConfigurationChanged,
mAmInternal, changes, initLocale);
mH.sendMessage(msg);
// Override configuration of the default display duplicates global config, so we need to
// update it also. This will also notify WindowManager about changes.
defaultDisplay.performDisplayOverrideConfigUpdate(mRootWindowContainer.getConfiguration(),
deferResume);
return changes;
}
<-NavigationModeController.java>
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (DEBUG) {
Log.d(TAG, "ACTION_OVERLAY_CHANGED");
}
updateCurrentInteractionMode(true /* notify */);
}
};
public void updateCurrentInteractionMode(boolean notify) {
mCurrentUserContext = getCurrentUserContext();
int mode = getCurrentInteractionMode(mCurrentUserContext);
mUiBgExecutor.execute(() ->
Settings.Secure.putString(mCurrentUserContext.getContentResolver(),
Secure.NAVIGATION_MODE, String.valueOf(mode)));
if (DEBUG) {
Log.d(TAG, "updateCurrentInteractionMode: mode=" + mode);
dumpAssetPaths(mCurrentUserContext);
}
if (notify) {
for (int i = 0; i < mListeners.size(); i++) {
mListeners.get(i).onNavigationModeChanged(mode);//通过onNavigationModeChanged接口回调更新systemUI配置更改
}
}
}
<-NavigationBar.java>
private final ModeChangedListener mModeChangedListener = new ModeChangedListener() {
@Override
public void onNavigationModeChanged(int mode) {
mNavBarMode = mode;
if (!QuickStepContract.isGesturalMode(mode)) {
// Reset the override alpha
if (getBarTransitions() != null) {
getBarTransitions().setBackgroundOverrideAlpha(1f);
}
}
updateScreenPinningGestures();
if (!canShowSecondaryHandle()) {
resetSecondaryHandle();
}
setNavBarMode(mode);
mView.setShouldShowSwipeUpUi(mOverviewProxyService.shouldShowSwipeUpUI());
}
};
private void updateScreenPinningGestures() {
// Change the cancel pin gesture to home and back if recents button is invisible
boolean pinningActive = ActivityManagerWrapper.getInstance().isScreenPinningActive();
ButtonDispatcher backButton = mView.getBackButton();
ButtonDispatcher recentsButton = mView.getRecentsButton();
if (pinningActive) {
boolean recentsVisible = mView.isRecentsButtonVisible();
backButton.setOnLongClickListener(recentsVisible
? this::onLongPressBackRecents
: this::onLongPressBackHome);
recentsButton.setOnLongClickListener(this::onLongPressBackRecents);
} else {
backButton.setOnLongClickListener(null);
recentsButton.setOnLongClickListener(null);
}
// Note, this needs to be set after even if we're setting the listener to null
backButton.setLongClickable(pinningActive);
recentsButton.setLongClickable(pinningActive);
}
<-NavigationBarController…java>
public void onNavigationModeChanged(int mode) {
if (mNavMode == mode) {
return;
}
final int oldMode = mNavMode;
mNavMode = mode;
updateAccessibilityButtonModeIfNeeded();
mHandler.post(() -> {
// create/destroy nav bar based on nav mode only in unfolded state
if (oldMode != mNavMode) {
updateNavbarForTaskbar();
}
for (int i = 0; i < mNavigationBars.size(); i++) {
NavigationBar navBar = mNavigationBars.valueAt(i);
if (navBar == null) {
continue;
}
navBar.getView().updateStates();
}
});
}
<-NavigationBarView.java>
public void updateStates() {
if (mNavigationInflaterView != null) {
// Reinflate the navbar if needed, no-op unless the swipe up state changes
mNavigationInflaterView.onLikelyDefaultLayoutChange();
}
updateSlippery();
reloadNavIcons();
updateNavButtonIcons();
mBgExecutor.execute(() -> setNavBarVirtualKeyHapticFeedbackEnabled(!mShowSwipeUpUi));
getHomeButton().setAccessibilityDelegate(
mShowSwipeUpUi ? mQuickStepAccessibilityDelegate : null);
}
<-NavigationBarInflaterView.java>
@Override
public void onNavigationModeChanged(int mode) {
mNavBarMode = mode;
}
public void onLikelyDefaultLayoutChange() {
// Reevaluate new layout
final String newValue = getDefaultLayout();
if (!Objects.equals(mCurrentLayout, newValue)) {
clearViews();
inflateLayout(newValue);
}
}
protected String getDefaultLayout() {
final int defaultResource = QuickStepContract.isGesturalMode(mNavBarMode)
? R.string.config_navBarLayoutHandle
: mOverviewProxyService.shouldShowSwipeUpUI()
? R.string.config_navBarLayoutQuickstep
: R.string.config_navBarLayout;
return getContext().getString(defaultResource);
}
<-EdgeBackGestureHandler.java>
public void onNavigationModeChanged(int mode) {
mIsGesturalModeEnabled = QuickStepContract.isGesturalMode(mode);
updateIsEnabled();
updateCurrentUserResources();
}
private void updateIsEnabled() {
boolean isEnabled = mIsAttached && mIsGesturalModeEnabled;
if (isEnabled == mIsEnabled) {
return;
}
mIsEnabled = isEnabled;
disposeInputChannel();
if (mEdgeBackPlugin != null) {
mEdgeBackPlugin.onDestroy();
mEdgeBackPlugin = null;
}
if (!mIsEnabled) {
mGestureNavigationSettingsObserver.unregister();
if (DEBUG_MISSING_GESTURE) {
Log.d(DEBUG_MISSING_GESTURE_TAG, "Unregister display listener");
}
mPluginManager.removePluginListener(this);
TaskStackChangeListeners.getInstance().unregisterTaskStackListener(mTaskStackListener);
DeviceConfig.removeOnPropertiesChangedListener(mOnPropertiesChangedListener);
mPipOptional.ifPresent(pip -> pip.setOnIsInPipStateChangedListener(null));
try {
mWindowManagerService.unregisterSystemGestureExclusionListener(
mGestureExclusionListener, mDisplayId);
} catch (RemoteException | IllegalArgumentException e) {
Log.e(TAG, "Failed to unregister window manager callbacks", e);
}
} else {
mGestureNavigationSettingsObserver.register();
updateDisplaySize();
if (DEBUG_MISSING_GESTURE) {
Log.d(DEBUG_MISSING_GESTURE_TAG, "Register display listener");
}
TaskStackChangeListeners.getInstance().registerTaskStackListener(mTaskStackListener);
DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI,
mMainExecutor::execute, mOnPropertiesChangedListener);
mPipOptional.ifPresent(
pip -> pip.setOnIsInPipStateChangedListener(mOnIsInPipStateChangedListener));
try {
mWindowManagerService.registerSystemGestureExclusionListener(
mGestureExclusionListener, mDisplayId);
} catch (RemoteException | IllegalArgumentException e) {
Log.e(TAG, "Failed to register window manager callbacks", e);
}
// Register input event receiver
mInputMonitor = InputManager.getInstance().monitorGestureInput(
"edge-swipe", mDisplayId);
mInputEventReceiver = new InputChannelCompat.InputEventReceiver(
mInputMonitor.getInputChannel(), Looper.getMainLooper(),
Choreographer.getInstance(), this::onInputEvent);
// Add a nav bar panel window
mIsNewBackAffordanceEnabled = mFeatureFlags.isEnabled(Flags.NEW_BACK_AFFORDANCE);
resetEdgeBackPlugin();
mPluginManager.addPluginListener(
this, NavigationEdgeBackPlugin.class, /*allowMultiple=*/ false);
}
// Update the ML model resources.
updateMLModelState();
}
<-DisplayController.java>
private void onIntent(Intent intent) {
if (mDestroyed) {
return;
}
boolean reconfigure = false;
if (ACTION_OVERLAY_CHANGED.equals(intent.getAction())) {
reconfigure = true;
} else if (ACTION_CONFIGURATION_CHANGED.equals(intent.getAction())) {
Configuration config = mContext.getResources().getConfiguration();
reconfigure = mInfo.fontScale != config.fontScale
|| mInfo.densityDpi != config.densityDpi;
}
if (reconfigure) {
Log.d(TAG, "Configuration changed, notifying listeners");
Display display = mDM.getDisplay(DEFAULT_DISPLAY);
if (display != null) {
handleInfoChange(display);
}
}
}
@AnyThread
private void handleInfoChange(Display display) {
WindowManagerProxy wmProxy = WindowManagerProxy.INSTANCE.get(mContext);
Info oldInfo = mInfo;
Context displayInfoContext = getDisplayInfoContext(display);
Info newInfo = new Info(displayInfoContext, wmProxy, oldInfo.mPerDisplayBounds);
Log.d(TAG,"handleInfoChange newInfo.navigationMode ="+newInfo.navigationMode+"; oldInfo.navigationMode ="+oldInfo.navigationMode);
if (newInfo.densityDpi != oldInfo.densityDpi || newInfo.fontScale != oldInfo.fontScale
|| newInfo.navigationMode != oldInfo.navigationMode) {
// Cache may not be valid anymore, recreate without cache
newInfo = new Info(displayInfoContext, wmProxy,
wmProxy.estimateInternalDisplayBounds(displayInfoContext));
}
int change = 0;
if (!newInfo.normalizedDisplayInfo.equals(oldInfo.normalizedDisplayInfo)) {
change |= CHANGE_ACTIVE_SCREEN;
}
if (newInfo.rotation != oldInfo.rotation) {
change |= CHANGE_ROTATION;
}
if (newInfo.densityDpi != oldInfo.densityDpi || newInfo.fontScale != oldInfo.fontScale) {
change |= CHANGE_DENSITY;
}
if (newInfo.navigationMode != oldInfo.navigationMode) {
change |= CHANGE_NAVIGATION_MODE;
}
if (!newInfo.supportedBounds.equals(oldInfo.supportedBounds)
|| !newInfo.mPerDisplayBounds.equals(oldInfo.mPerDisplayBounds)) {
change |= CHANGE_SUPPORTED_BOUNDS;
}
if (DEBUG) {
Log.d(TAG, "handleInfoChange - change: 0b" + Integer.toBinaryString(change));
}
if (change != 0) {
mInfo = newInfo;
final int flags = change;
MAIN_EXECUTOR.execute(() -> notifyChange(displayInfoContext, flags));
}
}
<-TouchInteractionService.java>
private void onNavigationModeChanged() {
initInputMonitor("onNavigationModeChanged()");
resetHomeBounceSeenOnQuickstepEnabledFirstTime();
}
private void initInputMonitor(String reason) {
disposeEventHandlers("Initializing input monitor due to: " + reason);
if (mDeviceState.isButtonNavMode()) {
return;
}
mInputMonitorCompat = new InputMonitorCompat("swipe-up", mDeviceState.getDisplayId());
mInputEventReceiver = mInputMonitorCompat.getInputReceiver(Looper.getMainLooper(),
mMainChoreographer, this::onInputEvent);
mRotationTouchHelper.updateGestureTouchRegions();
}