Android 13 NavigationBar流程
一、概述
Android SystemUI之NavigationBar
packages/apps/Settings/src/com/android/settings/gestures/SystemNavigationGestureSettings.javaframeworks/base/core/java/android/content/om/OverlayManager.javaframeworks/base/services/core/java/com/android/server/om/OverlayManagerService.javaframeworks/base/services/core/java/com/android/server/am/ActivityManagerService.javaframeworks/base/services/core/java/com/android/server/am/ProcessList.javaframeworks/base/core/java/android/app/ActivityThread.javaframeworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.javaframeworks/base/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationModeController.javaframeworks/base/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.javaframeworks/base/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.javaframeworks/base/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.javaframeworks/base/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarInflaterView.javaframeworks/base/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.javapackages/apps/Launcher3/src/com/android/launcher3/util/DisplayController.javapackages/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 , 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 ); | |_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);
1、Settings切换Navigation Mode
1.1 #setCurrentSystemNavigationMode
<-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(); }}
2、framework-overlay
2.1 #setEnabledExclusiveInCategory
<-OverlayManager.java>
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>
@Overridepublic 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 , 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); } }}@Overridepublic 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 , UserHandle.USER_NULL, false , 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;}
3、SystemUI流程
3.1 #updateCurrentInteractionMode
<-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 ); }};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配置更改 } }}
3.2 #onNavigationModeChanged
<-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>
@Overridepublic 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, false); } // Update the ML model resources. updateMLModelState();}
4、Launcher3流程
4.1 #onIntent
<-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)); }}
4.2 #onNavigationModeChanged
<-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();}
来源地址:https://blog.csdn.net/TSK_Amine/article/details/129300940