Proceso de carga de la barra de tareas de la tableta Android 13

A partir de Android 12, si se trata de una pantalla grande, la barra de navegación inferior cambiará para mostrar una barra de tareas, de NavigationBar a Taskbar.

Nota: CentralSurfacesImpl.java tiene la misma función que el statusbar.java original.

El proceso de inicio de CentralSurfacesImpl se ha mencionado anteriormente, por lo que no lo explicaré aquí.

// CentralSurfacesImpl.java
public class CentralSurfacesImpl extends CoreStartable implements
        CentralSurfaces {
    
    
     //省略其他代码....

    protected void makeStatusBarView(@Nullable RegisterStatusBarResult result) {
    
    
        //省略其他代码....
        createNavigationBar(result);
       //省略其他代码....
  
    }

    protected void createNavigationBar(@Nullable RegisterStatusBarResult result) {
    
    
        // 调用 NavigationBarController 的 createNavigationBars()方法创建 NavigationBar
        mNavigationBarController.createNavigationBars(true /* includeDefaultDisplay */, result);
    }

}

Luego mira hacia abajo:

NavigationBarController#createNavigationBars()

// NavigationBarController.java

    public void createNavigationBars(final boolean includeDefaultDisplay,
            RegisterStatusBarResult result) {
    
    
        // 如果需要,更新辅助功能按钮模式
        updateAccessibilityButtonModeIfNeeded();

        // 这里是重点,Android 12 之前版本的,没有这个判断。可以看下 initializeTaskbarIfNecessary() 方法。
        // 如果我们初始化TaskBar,则不需要在默认显示上创建导航栏
        final boolean shouldCreateDefaultNavbar = includeDefaultDisplay
                && !initializeTaskbarIfNecessary();
        Display[] displays = mDisplayManager.getDisplays();
        for (Display display : displays) {
    
    
            if (shouldCreateDefaultNavbar || display.getDisplayId() != DEFAULT_DISPLAY) {
    
    
                createNavigationBar(display, null /* savedState */, result);
            }
        }
    }

    /** @return {@code true} if taskbar is enabled, false otherwise */
    private boolean initializeTaskbarIfNecessary() {
    
    
        // 这里会判断是否是平板。
        // 跟踪代码发现,如果屏幕的(最小边长度*160/dpi值)< 600,就会判断为设备是平板设备
        // system/vendor/mediatek/proprietary/packages/apps/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java
        if (mIsTablet) {
    
    
            Trace.beginSection("NavigationBarController#initializeTaskbarIfNecessary");
            // 移除导航栏
            removeNavigationBar(mContext.getDisplayId());
            // 加载任务栏
            mTaskbarDelegate.init(mContext.getDisplayId());
            Trace.endSection();
        } else {
    
    
            mTaskbarDelegate.destroy();
        }
        return mIsTablet;
    }

Analizamos la tableta, por lo que aquí observamos directamente el método mTaskbarDelegate.init(mContext.getDisplayId());

TaskbarDelegate#init()

// TaskbarDelegate.java
    public void init(int displayId) {
    
    
        if (mInitialized) {
    
    
            return;
        }
        //省略其他代码....

        // 注册监听,切换导航模式时接收回调。
        mEdgeBackGestureHandler.onNavigationModeChanged(
                mNavigationModeController.addListener(this));
        // 边缘手势处理,注意:这里只加载、处理手势。
        // 手势中左右两返回图标由这里加载,底部黑色小横条不在这里加载。
        mEdgeBackGestureHandler.onNavBarAttached();

        //省略其他代码....
    }


    // 导航模式改变回调,进行处理
    @Override
    public void onNavigationModeChanged(int mode) {
    
    
        mNavigationMode = mode;
        mEdgeBackGestureHandler.onNavigationModeChanged(mode);
    }

1. Carga de gestos

EdgeBackGestureHandler#onNavBarAttached()

// EdgeBackGestureHandler.java

    /**
     * @see NavigationBarView#onAttachedToWindow()
     */
    public void onNavBarAttached() {
    
    
        mIsAttached = true;
        mProtoTracer.add(this);
        mOverviewProxyService.addCallback(mQuickSwitchListener);
        mSysUiState.addCallback(mSysUiStateCallback);
        // 重点关注这里,更新视图
        updateIsEnabled();
        startTracking();
    }


    private void updateIsEnabled() {
    
    
        // mIsAttached 是否已经添加上了,mIsGesturalModeEnabled 是否启用手势模式
        boolean isEnabled = mIsAttached && mIsGesturalModeEnabled;
        if (isEnabled == mIsEnabled) {
    
    
            return;
        }
        mIsEnabled = isEnabled;
        // 如果无效的话结束监听 Input
        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);

            try {
    
    
                 // 注销 WMS 里保存的除外区域监听
                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);

            try {
    
    
                // 监听 WMS 里保存的除外区域
                mWindowManagerService.registerSystemGestureExclusionListener(
                        mGestureExclusionListener, mDisplayId);
            } catch (RemoteException | IllegalArgumentException e) {
    
    
                Log.e(TAG, "Failed to register window manager callbacks", e);
            }

            //  注册名为 edge-swipe 的InputMonitor
            mInputMonitor = InputManager.getInstance().monitorGestureInput(
                    "edge-swipe", mDisplayId);
            mInputEventReceiver = new InputChannelCompat.InputEventReceiver(
                    mInputMonitor.getInputChannel(), Looper.getMainLooper(),
                    Choreographer.getInstance(), this::onInputEvent);

            // 添加 NavigationBarEdgePanel 为 Edge Back 事件的处理实现
            setEdgeBackPlugin(
                    new NavigationBarEdgePanel(mContext, mBackAnimation, mLatencyTracker));
            mPluginManager.addPluginListener(
                    this, NavigationEdgeBackPlugin.class, /*allowMultiple=*/ false);
        }
        // 更新 ML 模型资源.
        updateMLModelState();
    }

    // 创建返回手势视图
    private void setEdgeBackPlugin(NavigationEdgeBackPlugin edgeBackPlugin) {
    
    
        if (mEdgeBackPlugin != null) {
    
    
            mEdgeBackPlugin.onDestroy();
        }
        // 缓存 NavigationEdgeBackPlugin 实现
        mEdgeBackPlugin = edgeBackPlugin;
        // 向 NavigationEdgeBackPlugin 注册 Back 手势的触发回调
        mEdgeBackPlugin.setBackCallback(mBackCallback);
        // 准备好手势视图的 Window 参数
        mEdgeBackPlugin.setLayoutParams(createLayoutParams());
        updateDisplaySize();
    }
    
    // 配置返回手势 Window 的参数
    // 包括 flag、type、title 等属性
    private WindowManager.LayoutParams createLayoutParams() {
    
    
        Resources resources = mContext.getResources();
        WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(
                resources.getDimensionPixelSize(R.dimen.navigation_edge_panel_width),
                resources.getDimensionPixelSize(R.dimen.navigation_edge_panel_height),
                WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                        | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
                        | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
                PixelFormat.TRANSLUCENT);
        ...
        layoutParams.setTitle(TAG + mContext.getDisplayId());
        layoutParams.setFitInsetsTypes(0 /* types */);
        layoutParams.setTrustedOverlay();
        return layoutParams;
    }

En este punto, se crea la navegación por gestos. Nota: La vista sigue siendo invisible en este momento, y se mostrará y actualizará cuando ocurran eventos posteriores.

Echemos un vistazo a los eventos relacionados con los gestos:

// EdgeBackGestureHandler.java

    private void onMotionEvent(MotionEvent ev) {
    
    
        int action = ev.getActionMasked();
        if (action == MotionEvent.ACTION_DOWN) {
    
    
            mInputEventReceiver.setBatchingEnabled(false);
            mIsOnLeftEdge = ev.getX() <= mEdgeWidthLeft + mLeftInset;
            mMLResults = 0;
            mLogGesture = false;
            mInRejectedExclusion = false;
            boolean isWithinInsets = isWithinInsets((int) ev.getX(), (int) ev.getY());
            // 根据返回手势是否有效、
            // 点击区域是否是停用区域等条件
            // 得到当前是否允许视图处理该手势
            mAllowGesture = !mDisabledForQuickstep && mIsBackGestureAllowed && isWithinInsets
                    && !mGestureBlockingActivityRunning
                    && !QuickStepContract.isBackGestureDisabled(mSysUiFlags)
                    && isWithinTouchRegion((int) ev.getX(), (int) ev.getY());
            if (mAllowGesture) {
    
    
                // 更新当前是屏幕左侧还是右侧
                mEdgeBackPlugin.setIsLeftPanel(mIsOnLeftEdge);
                // 发射事件给视图
                mEdgeBackPlugin.onMotionEvent(ev);
            }
        } else if (mAllowGesture || mLogGesture) {
    
    
            if (!mThresholdCrossed) {
    
    
                mEndPoint.x = (int) ev.getX();
                mEndPoint.y = (int) ev.getY();
                // 多个手指按下的话取消事件处理
                if (action == MotionEvent.ACTION_POINTER_DOWN) {
    
    
                    if (mAllowGesture) {
    
    
                        logGesture(SysUiStatsLog.BACK_GESTURE__TYPE__INCOMPLETE_MULTI_TOUCH);
                        cancelGesture(ev);
                    }
                    mLogGesture = false;
                    return;
                } else if (action == MotionEvent.ACTION_MOVE) {
    
    
                    // 手指移动超过长按阈值的话
                    // 也要取消事件处理
                    if ((ev.getEventTime() - ev.getDownTime()) > mLongPressTimeout) {
    
    
                        if (mAllowGesture) {
    
    
                            logGesture(SysUiStatsLog.BACK_GESTURE__TYPE__INCOMPLETE_LONG_PRESS);
                            cancelGesture(ev);
                        }
                        mLogGesture = false;
                        return;
                    }
                    ...
                }
            }

            // 通过上述检查的话
            // 将 MOVE、UP 交给视图
            if (mAllowGesture) {
    
    
                // forward touch
                mEdgeBackPlugin.onMotionEvent(ev);
            }
        }
        mProtoTracer.scheduleFrameUpdate();
    }

El evento se pasa a NavigationBarEdgePanel para mostrar el gesto de retorno y desencadenar el retorno.

NavigationBarEdgePanel continúa haciendo el siguiente trabajo: juicio de gestos, actualización de vista y visualización de animación.

La lógica de onMotionEvent():

Cuando está ABAJO, primero deje que la vista se vuelva visible. El
proceso VISIBLE MOVE juzga la distancia a través de handleMoveEvent(), y decide si actualizar y dar mTriggerBack.
Cuando está ARRIBA, verificará esta variable para decidir si activa la acción de retorno, es decir, triggerBack ( )

// NavigationBarEdgePanel.java
    public void onMotionEvent(MotionEvent event) {
    
    
        if (mVelocityTracker == null) {
    
    
            mVelocityTracker = VelocityTracker.obtain();
        }
        mVelocityTracker.addMovement(event);
        switch (event.getActionMasked()) {
    
    
            case MotionEvent.ACTION_DOWN:
                mDragSlopPassed = false;
                resetOnDown();
                mStartX = event.getX();
                mStartY = event.getY();
                setVisibility(VISIBLE);
                updatePosition(event.getY());
                mRegionSamplingHelper.start(mSamplingRect);
                mWindowManager.updateViewLayout(this, mLayoutParams);
                break;
            case MotionEvent.ACTION_MOVE:
                handleMoveEvent(event);
                break;
            case MotionEvent.ACTION_UP:
                if (mTriggerBack) {
    
    
                    triggerBack();
                } else {
    
    
                    cancelBack();
                }
                ...
        }
    }

El flujo de eventos relacionados con los gestos se detiene aquí.

2. Navegación con botones La
navegación con botones comienza con el método onCreate() en TouchInteractionService.java.

// TouchInteractionService.java
    @Override
    public void onCreate() {
    
    
        super.onCreate();
        //省略其他代码....
        
        mTaskbarManager = new TaskbarManager(this);

        //省略其他代码....
    }

Una vez completada la configuración del usuario, de acuerdo con la configuración, si se carga el botón de navegación. Si está cargado, se llamará al método recreateTaskbar() en TaskbarManager.java.

TaskbarManager#recreateTaskbar()

// TaskbarManager.java
    private void recreateTaskbar() {
    
    
        // 销毁现有任务栏
        destroyExistingTaskbar();
        // 获取设备配置文件的
        DeviceProfile dp =
                mUserUnlocked ? LauncherAppState.getIDP(mContext).getDeviceProfile(mContext) : null;
        // 任务栏是否启用
        boolean isTaskBarEnabled = dp != null && dp.isTaskbarPresent;
        if(dp != null){
    
    
            Log.d("yexiao","yexiao"+(dp != null)+"----"+(dp.isTaskbarPresent));
        }
        if (!isTaskBarEnabled) {
    
    
            SystemUiProxy.INSTANCE.get(mContext)
                    .notifyTaskbarStatus(/* visible */ false, /* stashed */ false);
            return;
        }
        // TaskbarActivityContext 按钮导航的视图在里面加载,包括那个底部横线也在里面。
        mTaskbarActivityContext = new TaskbarActivityContext(mContext, dp, mNavButtonController,
                mUnfoldProgressProvider);
        // 初始化
        mTaskbarActivityContext.init(mSharedState);
        if (mActivity != null) {
    
    
            // 设置相关控制器
            mTaskbarActivityContext.setUIController(
                    createTaskbarUIControllerForActivity(mActivity));
        }
    }

Hay un monitor de mDispInfoChangeListener en la clase TaskbarManager. Cuando se cambia el modo de navegación, volverá a llamar aquí en la clase DisplayController.

Luego mire hacia abajo el método de construcción de TaskbarActivityContext:

TaskbarActivityContext público (Contexto ventanaContexto, Perfil de dispositivo dp,
Barra de tareasNavButtonController buttonController, ScopedUnfoldTransitionProgressProvider
unfoldTransitionProgressProvider) { super(windowContext); mDeviceProfile = dp.copy(esto);

final Resources resources = getResources();

mNavMode = DisplayController.getNavigationMode(windowContext);
mImeDrawsImeNavBar = getBoolByName(IME_DRAWS_IME_NAV_BAR_RES_NAME, resources, false);
mIsSafeModeEnabled = TraceHelper.allowIpcs("isSafeMode",
        () -> getPackageManager().isSafeMode());
mIsUserSetupComplete = SettingsCache.INSTANCE.get(this).getValue(
        Settings.Secure.getUriFor(Settings.Secure.USER_SETUP_COMPLETE), 0);
mIsNavBarForceVisible = SettingsCache.INSTANCE.get(this).getValue(
        Settings.Secure.getUriFor(Settings.Secure.NAV_BAR_KIDS_MODE), 0);
mIsNavBarKidsMode = SettingsCache.INSTANCE.get(this).getValue(
        Settings.Secure.getUriFor(Settings.Secure.NAV_BAR_KIDS_MODE), 0);

updateIconSize(resources);

// 首先获取显示和焦点,因为视图可能会在构造函数中使用它们。
Display display = windowContext.getDisplay();
Context c = display.getDisplayId() == Display.DEFAULT_DISPLAY
        ? windowContext.getApplicationContext()
        : windowContext.getApplicationContext().createDisplayContext(display);
mWindowManager = c.getSystemService(WindowManager.class);
mLeftCorner = display.getRoundedCorner(RoundedCorner.POSITION_BOTTOM_LEFT);
mRightCorner = display.getRoundedCorner(RoundedCorner.POSITION_BOTTOM_RIGHT);

// 初始化 views.
mDragLayer = (TaskbarDragLayer) mLayoutInflater.inflate(
        R.layout.taskbar, null, false);
TaskbarView taskbarView = mDragLayer.findViewById(R.id.taskbar_view);
TaskbarScrimView taskbarScrimView = mDragLayer.findViewById(R.id.taskbar_scrim);
FrameLayout navButtonsView = mDragLayer.findViewById(R.id.navbuttons_view);
StashedHandleView stashedHandleView = mDragLayer.findViewById(R.id.stashed_handle);

mAccessibilityDelegate = new TaskbarShortcutMenuAccessibilityDelegate(this);

// 构造控制器 controllers,将会在对应的控制添加对应的图标,以控制逻辑
mControllers = new TaskbarControllers(this,
        new TaskbarDragController(this),
        buttonController,
        getPackageManager().hasSystemFeature(FEATURE_PC)
                ? new DesktopNavbarButtonsViewController(this, navButtonsView) :     
                new NavbarButtonsViewController(this, navButtonsView),
        new RotationButtonController(this,
                c.getColor(R.color.taskbar_nav_icon_light_color),
                c.getColor(R.color.taskbar_nav_icon_dark_color),
                R.drawable.ic_sysbar_rotate_button_ccw_start_0,
                R.drawable.ic_sysbar_rotate_button_ccw_start_90,
                R.drawable.ic_sysbar_rotate_button_cw_start_0,
                R.drawable.ic_sysbar_rotate_button_cw_start_90,
                () -> getDisplay().getRotation()),
        new TaskbarDragLayerController(this, mDragLayer),
        new TaskbarViewController(this, taskbarView),
        new TaskbarScrimViewController(this, taskbarScrimView),
        new TaskbarUnfoldAnimationController(this, unfoldTransitionProgressProvider,
                mWindowManager, WindowManagerGlobal.getWindowManagerService()),
        new TaskbarKeyguardController(this),
        new StashedHandleViewController(this, stashedHandleView),
        new TaskbarStashController(this),
        new TaskbarEduController(this),
        new TaskbarAutohideSuspendController(this),
        new TaskbarPopupController(this),
        new TaskbarForceVisibleImmersiveController(this),
        new TaskbarAllAppsController(this, dp),
        new TaskbarInsetsController(this));

}

public void init(@NonNull TaskbarSharedState sharedState) { mLastRequestedNonFullscreenHeight = getDefaultTaskbarWindowHeight(); mWindowLayoutParams = createDefaultWindowLayoutParams();

//  在 TaskbarControllers控制器里,初始化前面构造方法中添加的各种控制器。
mControllers.init(sharedState);
updateSysuiStateFlags(sharedState.sysuiStateFlags, true /* fromInit */);
// 生成 LayoutParams 用于将视图作为新窗口直接添加到 WindowManager
mWindowManager.addView(mDragLayer, mWindowLayoutParams);

}

Aquí hay un análisis de ejemplo de NavbarButtonsViewController:

// NavbarButtonsViewController.java

    /**
     * Initializes the controller
     */
    public void init(TaskbarControllers controllers) {
    
    

         // 省略部分代码......

        // 强制导航按钮(特别是后退按钮)在设置向导期间可见。
        boolean isInSetup = !mContext.isUserSetupComplete();
        boolean isInKidsMode = mContext.isNavBarKidsModeActive();
        boolean alwaysShowButtons = isThreeButtonNav || isInSetup;

        // 省略部分代码......
         
        if (alwaysShowButtons) {
    
    
            // 初始化按钮
            initButtons(mNavButtonContainer, mEndContextualContainer,
                    mControllers.navButtonController);


        } else {
    
    
          
        }

        // 省略部分代码......
        mSeparateWindowParent.recreateControllers();
    }


    private void initButtons(ViewGroup navContainer, ViewGroup endContainer,
            TaskbarNavButtonController navButtonController) {
    
    
        // back Button
        mBackButton = addButton(R.drawable.ic_sysbar_back, BUTTON_BACK,
                mNavButtonContainer, mControllers.navButtonController, R.id.back);
        mBackButtonAlpha = new MultiValueAlpha(mBackButton, NUM_ALPHA_CHANNELS);
        mBackButtonAlpha.setUpdateVisibility(true);
        mPropertyHolders.add(new StatePropertyHolder(
                mBackButtonAlpha.getProperty(ALPHA_INDEX_KEYGUARD_OR_DISABLE),
                flags -> {
    
    
                    // Show only if not disabled, and if not on the keyguard or otherwise only when
                    // the bouncer or a lockscreen app is showing above the keyguard
                    boolean showingOnKeyguard = (flags & FLAG_KEYGUARD_VISIBLE) == 0 ||
                            (flags & FLAG_ONLY_BACK_FOR_BOUNCER_VISIBLE) != 0 ||
                            (flags & FLAG_KEYGUARD_OCCLUDED) != 0;
                    return (flags & FLAG_DISABLE_BACK) == 0
                            && ((flags & FLAG_KEYGUARD_VISIBLE) == 0 || showingOnKeyguard);
                }));
        boolean isRtl = Utilities.isRtl(mContext.getResources());
        mPropertyHolders.add(new StatePropertyHolder(mBackButton,
                flags -> (flags & FLAG_IME_VISIBLE) != 0 && !mContext.isNavBarKidsModeActive(),
                View.ROTATION, isRtl ? 90 : -90, 0));
        // Translate back button to be at end/start of other buttons for keyguard
        int navButtonSize = mContext.getResources().getDimensionPixelSize(
                R.dimen.taskbar_nav_buttons_size);
        mPropertyHolders.add(new StatePropertyHolder(
                mBackButton, flags -> (flags & FLAG_ONLY_BACK_FOR_BOUNCER_VISIBLE) != 0
                        || (flags & FLAG_KEYGUARD_VISIBLE) != 0,
                VIEW_TRANSLATE_X, navButtonSize * (isRtl ? -2 : 2), 0));

        // home button
        mHomeButton = addButton(R.drawable.ic_sysbar_home, BUTTON_HOME, navContainer,
                navButtonController, R.id.home);
        mHomeButtonAlpha = new MultiValueAlpha(mHomeButton, NUM_ALPHA_CHANNELS);
        mHomeButtonAlpha.setUpdateVisibility(true);
        mPropertyHolders.add(
                new StatePropertyHolder(mHomeButtonAlpha.getProperty(
                        ALPHA_INDEX_KEYGUARD_OR_DISABLE),
                flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0 &&
                        (flags & FLAG_DISABLE_HOME) == 0));

        // Recents button
        View recentsButton = addButton(R.drawable.ic_sysbar_recent, BUTTON_RECENTS,
                navContainer, navButtonController, R.id.recent_apps);
        mHitboxExtender.init(recentsButton, mNavButtonsView, mContext.getDeviceProfile(),
                () -> {
    
    
                    float[] recentsCoords = new float[2];
                    getDescendantCoordRelativeToAncestor(recentsButton, mNavButtonsView,
                            recentsCoords, false);
                    return recentsCoords;
                }, new Handler());
        recentsButton.setOnClickListener(v -> {
    
    
            navButtonController.onButtonClick(BUTTON_RECENTS);
            mHitboxExtender.onRecentsButtonClicked();
        });
        mPropertyHolders.add(new StatePropertyHolder(recentsButton,
                flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0 && (flags & FLAG_DISABLE_RECENTS) == 0
                        && !mContext.isNavBarKidsModeActive()));

        // A11y button
        mA11yButton =  (R.drawable.ic_sysbar_accessibility_button, BUTTON_A11Y,
                endContainer, navButtonController, R.id.accessibility_button,
                R.layout.taskbar_contextual_button);
        mPropertyHolders.add(new StatePropertyHolder(mA11yButton,
                flags -> (flags & FLAG_A11Y_VISIBLE) != 0
                        && (flags & FLAG_ROTATION_BUTTON_VISIBLE) == 0));
    }

El evento se configura directamente al agregar el botón (), y si hay necesidades especiales, se configurará por separado.

Hasta ahora el análisis simple está completo.

Supongo que te gusta

Origin blog.csdn.net/wzx311/article/details/128426217
Recomendado
Clasificación