Android 13 NavigationBar流程

一、概述

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<PackageAndUser> updatedTargets)|_updateActivityManager(affectedPackages, userId);|  |_am.scheduleApplicationInfoChanged(targetPackageNames, userId);|  #ActivityManagerService.java|  |-scheduleApplicationInfoChanged(List<String> packageNames, int userId) |    |_updateApplicationInfoLOSP(@NonNull List<String> packagesToUpdate,boolean updateFrameworkRes, int userId)|      |_mProcessList.updateApplicationInfoLOSP(packagesToUpdate, userId, updateFrameworkRes);|      |  #ProcessList.java|      |  |-updateApplicationInfoLOSP(List<String> 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<WindowProcessController> 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);

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>

/*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<PackageAndUser> updatedTargets) {if (CollectionUtils.isEmpty(updatedTargets)) {return;}persistSettingsLocked();final SparseArray<ArraySet<String>> userTargets = groupTargetsByUserId(updatedTargets);for (int i = 0, n = userTargets.size(); i < n; i++) {final ArraySet<String> targets = userTargets.valueAt(i);final int userId = userTargets.keyAt(i);final List<String> 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<String> 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<String> 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>

 @Overridepublic void scheduleApplicationInfoChanged(List<String> 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<String> 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<String> packagesToUpdate, int userId,boolean updateFrameworkRes) {final ArrayList<WindowProcessController> 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 informationsynchronized (mResourcesManager) {WeakReference<LoadedApk> 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<String> oldPaths = new ArrayList<>();LoadedApk.makePaths(this, apk.getApplicationInfo(), oldPaths);apk.updateApplicationInfo(ai, oldPaths);}if (resApk != null) {final ArrayList<String> oldPaths = new ArrayList<>();LoadedApk.makePaths(this, resApk.getApplicationInfo(), oldPaths);resApk.updateApplicationInfo(ai, oldPaths);}synchronized (mResourcesManager) {// Update all affected Resources objects to use new ResourcesImplmResourcesManager.applyAllPendingAppInfoUpdates();}
}

<-ActivityTaskManagerService.java>

public void updateAssetConfiguration(List<WindowProcessController> 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 managervalues = 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<WindowProcessController> 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() {@Overridepublic 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配置更改}}
}
3.2 #onNavigationModeChanged

<-NavigationBar.java>

private final ModeChangedListener mModeChangedListener = new ModeChangedListener() {@Overridepublic void onNavigationModeChanged(int mode) {mNavBarMode = mode;if (!QuickStepContract.isGesturalMode(mode)) {// Reset the override alphaif (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 invisibleboolean 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 nullbackButton.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 stateif (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 changesmNavigationInflaterView.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 layoutfinal 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 receivermInputMonitor = InputManager.getInstance().monitorGestureInput("edge-swipe", mDisplayId);mInputEventReceiver = new InputChannelCompat.InputEventReceiver(mInputMonitor.getInputChannel(), Looper.getMainLooper(),Choreographer.getInstance(), this::onInputEvent);// Add a nav bar panel windowmIsNewBackAffordanceEnabled = mFeatureFlags.isEnabled(Flags.NEW_BACK_AFFORDANCE);resetEdgeBackPlugin();mPluginManager.addPluginListener(this, NavigationEdgeBackPlugin.class, /*allowMultiple=*/ 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);}}
}@AnyThreadprivate 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 cachenewInfo = 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();
}

Android 13 NavigationBar相关推荐

  1. Android 13 返回导航大变更,返回键彻底废弃 + 可预见型返回手势

    /   今日科技快讯   / 据外国媒体报道,马斯克计划裁撤推特约3700个岗位,这占到这家社交媒体公司员工总数的一半,目的是在其440亿美元的收购案之后降低成本.此外,马斯克还打算取消公司现行的远程 ...

  2. Android 13 返回导航大变更:返回键彻底废弃 + 可预见型返回手势

    Android 10 首次引入了全局返回手势,但直到返回触发才能看到目标上层画面.13 针对该特性进行了优化,即返回触发之前可以预览上层画面.同时彻底废弃了返回键相关的 API,这将对现有的 App ...

  3. 【Google Play】声明广告权限 ( you must declare the AD_ID Permission when your app targets Android 13 )

    文章目录 一.广告权限申请要求 二.添加广告权限 一.广告权限申请要求 今天收到 Google Play 邮件 , 要求添加 邮件原文 : Hello Google Play Developer, L ...

  4. Android 13 第一个开发者版本来了,网友直呼:Android 12 还没玩透!

    整理 | 苏宓 出品 | CSDN(ID:CSDNnews) 2 月 10 日,Google 宣布 Android 13 首个预览版面向开发者开放,此版本重点聚焦隐私和安全.提供开发者生产力.应用兼容 ...

  5. 首发Android 13!谷歌Pixel 7 Pro渲染图曝光:后置相机模组吸睛

    据此爆料显示,全新的谷歌Pixel 7系列将于10月份与大家见面,不出意外我的话依旧将包含谷歌Pixel 7和Pixel 7 Pro两个版本,其最大的卖点就是将有望出厂预装Android 13操作系统 ...

  6. android 13 热点启动流程

    近期在看一个热点启动的问题.发现网上基本上都算android 9 的wifi热点启动流程.自己去看android 13 的源码的时候发现与之前相比已经有一些小改动了. 在此总结一下wifie热点的启动 ...

  7. Android 13小米首批支持机型曝光 这4款机型在内

    目前手机的安卓系统大多数都是以Android 12为主,而Android 13的到来还需要点时间,但是最近有消息爆料小米将有4部机型支持Android 13,那么,都是哪些呢?来看看下文是怎么说的吧. ...

  8. 【WLAN】Android 13 p2p / wifi direct介绍

    一. WifiP2pSettings和WifiP2pService介绍 WifiP2pSettings是Settings应用中负责处理P2P相关UI/UE逻辑的主要类,与之交互的则是位于SystemS ...

  9. OPPO 全球首发 Android 13 正式版,适配率超 96%!

    今年5月12日, Android 13 在谷歌I/O大会正式亮相,新系统在隐私保护.功能便捷性等方面进行了重大升级,引发全球瞩目.OPPO 作为国内头部手机厂商之一,不仅首批推出 Android 13 ...

最新文章

  1. Linux 常用命令使用方法
  2. iOS GCD中级篇 - dispatch_group的理解及使用
  3. java 有什么方法可以动态或循环的生成对象名
  4. RabbitMQ (五) 订阅者模式之分发模式 ( fanout )
  5. magento 基本配置
  6. 《Android深度探索》第一章心得体会
  7. 计算机系统-电路设计09-计数器的内部电路实现
  8. c# 获取键盘的输入
  9. Allegro给一个网络赋默认值,取消默认值
  10. 在ubuntu上一键安装TIM的脚本
  11. 隐藏win10资源管理器中显示的「DVD驱动器」
  12. Matplotlib可视化图表
  13. 解决win10显示无线网络已连接但是不能上网的问题
  14. 李云赫天津大学计算机,祝贺创业谷涌现全国自强之星,同济创业谷,陪伴这个世上最有梦想的人...
  15. 二维码学习笔记(二) | 数据分析与数据编码
  16. Android SDK Android NDK 官方下载地址(zt)
  17. java mysql 生僻字 乱码_mysql 生僻字乱码
  18. Linux内核页表管理-那些鲜为人知的秘密
  19. JavaScript入门 轮播/表单验证 Day17
  20. 【变量创建】CFPS应用及C刊变量复盘STATA实战1

热门文章

  1. [渝粤教育] 西北工业大学 机械制图 参考 资料
  2. 十大iOS角色扮演游戏盘点
  3. eclipse工具栏不见了怎么办
  4. 985大学计算机博士毕业发表论文,博士毕业去高校当老师需不需要发表SCI
  5. 风景照片的PS后期处理
  6. 看rom助手如何教你脱离伸手党,做出自己的rom
  7. Linux运维面试精选题库(一)
  8. flash分类:NORflash和NANDflash
  9. 《商用密码应用与安全性评估》第三章商用密码标准与产品应用3.4商用密码标准与产品
  10. 一、对C语言的初步认识