我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Android 13 NavigationBar

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Android 13 NavigationBar

Android 13 NavigationBar流程

一、概述

Android SystemUI之NavigationBar

packages/apps/Settings/class="lazy" data-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/class="lazy" data-src/com/android/systemui/navigationbar/NavigationModeController.javaframeworks/base/packages/SystemUI/class="lazy" data-src/com/android/systemui/navigationbar/NavigationBar.javaframeworks/base/packages/SystemUI/class="lazy" data-src/com/android/systemui/navigationbar/NavigationBarController.javaframeworks/base/packages/SystemUI/class="lazy" data-src/com/android/systemui/navigationbar/NavigationBarView.javaframeworks/base/packages/SystemUI/class="lazy" data-src/com/android/systemui/navigationbar/NavigationBarInflaterView.javaframeworks/base/packages/SystemUI/class="lazy" data-src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.javapackages/apps/Launcher3/class="lazy" data-src/com/android/launcher3/util/DisplayController.javapackages/apps/Launcher3/quickstep/class="lazy" data-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

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Android 13 NavigationBar

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

13问13答全面学习Android View绘制

本文通过13问13答学习Android View绘制,供大家参考,具体内容如下 1.View的绘制流程分几步,从哪开始?哪个过程结束以后能看到view? 答:从ViewRoot的performTraversals开始,经过measure,l
2022-06-06

Android判断NavigationBar是否显示的方法(获取屏幕真实的高度)

有些时候,我们需要知道当前手机上是否显示了NavigationBar,也就是屏幕底部的虚拟按键。 比如截屏的时候,要获取屏幕的高度,必须包括NavigationBar的高度。 试过网上的多种方法,但是对那种可以通过手势来显示/隐藏的Navi
2022-06-06

Android 13添加自定义native服务

欢迎加入我的知识星球Android系统开发指南 欢迎关注微信公众号 无限无羡 欢迎关注知乎账号 无限无羡 文章目录 native服务添加selinux权限配置通过binder访问服务 native服务添加 native服务就是用
2023-08-19

Android 13 新特性及适配指南

Android 13(API 33)于 2022年8月15日 正式发布(发布时间较往年早了一些),正式版Release源代码也于当日被推送到AOSP Android开源项目。 截止到笔者撰写这篇文章时,国内部分应用软件开发厂商已逐步接到
2023-08-19

Android 13运行时权限变更一览

本文同步发表于我的微信公众号,扫一扫文章底部的二维码或在微信搜索 郭霖 即可关注,每个工作日都有文章更新。 要不了多久,Android 13正式版就要发布了。 其实就在几个月前,我写了一篇关于Android 13首个开发者体验版的全面
2023-08-19

Android Studio targetApi=33 android 13 setAppCacheEnabled/setAppCachePath/setAppCacheMaxSize 报红问题探究

目录 现象 具体分析 解决方案 总结 参考 现象 可以看到即使加了Api版本判断依然是报红的 具体分析 编译后有如下类似错误提示 Launching lib/main.dart on sdk gphone
2023-08-16

Android 13 wifi adb设置固定端口解决

Android 13 wifi adb设置固定端口解决 本文只管解决介绍不做代码层面具体分析。 文章目录 Android 13 wifi adb设置固定端口解决一、前言二、设置wifi 固定端口号三、打开 "无线调试"1、手动打开设
2023-08-17

Linux/Unix迷的13款Android应用是什么

这篇“Linux/Unix迷的13款Android应用是什么”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Linux/Uni
2023-06-16

编程热搜

  • Android:VolumeShaper
    VolumeShaper(支持版本改一下,minsdkversion:26,android8.0(api26)进一步学习对声音的编辑,可以让音频的声音有变化的播放 VolumeShaper.Configuration的三个参数 durati
    Android:VolumeShaper
  • Android崩溃异常捕获方法
    开发中最让人头疼的是应用突然爆炸,然后跳回到桌面。而且我们常常不知道这种状况会何时出现,在应用调试阶段还好,还可以通过调试工具的日志查看错误出现在哪里。但平时使用的时候给你闹崩溃,那你就欲哭无泪了。 那么今天主要讲一下如何去捕捉系统出现的U
    Android崩溃异常捕获方法
  • android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
    系统的设置–>电池–>使用情况中,统计的能耗的使用情况也是以power_profile.xml的value作为基础参数的1、我的手机中power_profile.xml的内容: HTC t328w代码如下:
    android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
  • Android SQLite数据库基本操作方法
    程序的最主要的功能在于对数据进行操作,通过对数据进行操作来实现某个功能。而数据库就是很重要的一个方面的,Android中内置了小巧轻便,功能却很强的一个数据库–SQLite数据库。那么就来看一下在Android程序中怎么去操作SQLite数
    Android SQLite数据库基本操作方法
  • ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
    工作的时候为了方便直接打开编辑文件,一些常用的软件或者文件我们会放在桌面,但是在ubuntu20.04下直接直接拖拽文件到桌面根本没有效果,在进入桌面后发现软件列表中的软件只能收藏到面板,无法复制到桌面使用,不知道为什么会这样,似乎并不是很
    ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
  • android获取当前手机号示例程序
    代码如下: public String getLocalNumber() { TelephonyManager tManager =
    android获取当前手机号示例程序
  • Android音视频开发(三)TextureView
    简介 TextureView与SurfaceView类似,可用于显示视频或OpenGL场景。 与SurfaceView的区别 SurfaceView不能使用变换和缩放等操作,不能叠加(Overlay)两个SurfaceView。 Textu
    Android音视频开发(三)TextureView
  • android获取屏幕高度和宽度的实现方法
    本文实例讲述了android获取屏幕高度和宽度的实现方法。分享给大家供大家参考。具体分析如下: 我们需要获取Android手机或Pad的屏幕的物理尺寸,以便于界面的设计或是其他功能的实现。下面就介绍讲一讲如何获取屏幕的物理尺寸 下面的代码即
    android获取屏幕高度和宽度的实现方法
  • Android自定义popupwindow实例代码
    先来看看效果图:一、布局
  • Android第一次实验
    一、实验原理 1.1实验目标 编程实现用户名与密码的存储与调用。 1.2实验要求 设计用户登录界面、登录成功界面、用户注册界面,用户注册时,将其用户名、密码保存到SharedPreference中,登录时输入用户名、密码,读取SharedP
    Android第一次实验

目录