Android 13 NavigationBar

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 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);

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 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;
}

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 /* 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() {
        @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();
}

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();
}

你可能感兴趣的:(Android系统学习,android)