SystemUI导航栏

android13-release


1、系统中参数项

1.1 相关开关属性

设置->系统->手势->系统导航->“三按钮”导航
在这里插入图片描述

  • 设置中:“三按钮”导航
    packages/apps/Settings/src/com/android/settings/gestures/SystemNavigationGestureSettings.java
    packages/apps/Settings/res/values-zh-rCN/strings.xml
    <string name="legacy_navigation_title" msgid="7877402855994423727">"“三按钮”导航"</string>

  • 默认导航栏模式:config_navBarInteractionMode
    frameworks/base/core/res/res/values/config.xml
   <!-- Controls the navigation bar interaction mode:
        0: 3 button mode (back, home, overview buttons)
        1: 2 button mode (back, home buttons + swipe up for overview)
        2: gestures only for back, home and overview -->
   <integer name="config_navBarInteractionMode">0</integer>

   <!-- Whether a software navigation bar should be shown. NOTE: in the future this may be
        autodetected from the Configuration. -->
   <bool name="config_showNavigationBar">false</bool>
  • Settings数据库中:adb shell settings get Secure navigation_mode
    frameworks/base/core/java/android/provider/Settings.java
/**
 * Navigation bar mode.
 *  0 = 3 button
 *  1 = 2 button
 *  2 = fully gestural
 * @hide
 */
@Readable
public static final String NAVIGATION_MODE =
        "navigation_mode";
  • prop属性"qemu.hw.mainkeys":允许系统属性覆盖此设置。由仿真器使用。使用方法hasNavigationBar()
  • 导航栏高度:navigation_bar_height
    frameworks/base/core/res/res/values/dimens.xml
   <!-- Height of the bottom navigation / system bar. -->
   <dimen name="navigation_bar_height">48dp</dimen>
   <!-- Height of the bottom navigation bar in portrait; often the same as @dimen/navigation_bar_height -->
   <dimen name="navigation_bar_height_landscape">48dp</dimen>

2.2 属性设置代码

设置中显示判断:

  • String NAV_BAR_MODE_3BUTTON_OVERLAY = "com.android.internal.systemui.navbar.threebutton";
    /product/overlay/NavigationBarMode3Button/NavigationBarMode3ButtonOverlay.apk
  • String NAV_BAR_MODE_2BUTTON_OVERLAY = "com.android.internal.systemui.navbar.twobutton";
    /product/overlay/NavigationBarMode2Button/NavigationBarMode2ButtonOverlay.apk
  • String NAV_BAR_MODE_GESTURAL_OVERLAY = "com.android.internal.systemui.navbar.gestural";
    /product/overlay/NavigationBarModeGestural/NavigationBarModeGesturalOverlay.apk

packages/apps/Settings/src/com/android/settings/gestures/SystemNavigationPreferenceController.java

static boolean isOverlayPackageAvailable(Context context, String overlayPackage) {
    try {
        return context.getPackageManager().getPackageInfo(overlayPackage, 0) != null;
    } catch (PackageManager.NameNotFoundException e) {
        // Not found, just return unavailable
        return false;
    }
}

frameworks/base/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java

private int mNavBarMode = NAV_BAR_MODE_3BUTTON;

mNavBarMode = mNavigationModeController.addListener(mModeChangedListener);

frameworks/base/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationModeController.java

private int getCurrentInteractionMode(Context context) {
    int mode = context.getResources().getInteger(
            com.android.internal.R.integer.config_navBarInteractionMode);
    if (DEBUG) {
        Log.d(TAG, "getCurrentInteractionMode: mode=" + mode
                + " contextUser=" + context.getUserId());
    }
    return mode;
}

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

frameworks/base/services/core/java/com/android/server/wm/DisplayPolicy.java

if (mDisplayContent.isDefaultDisplay) {
    mHasStatusBar = true;
    mHasNavigationBar = mContext.getResources().getBoolean(R.bool.config_showNavigationBar);

    // Allow a system property to override this. Used by the emulator.
    // See also hasNavigationBar().
    String navBarOverride = SystemProperties.get("qemu.hw.mainkeys");
    if ("1".equals(navBarOverride)) {
        mHasNavigationBar = false;
    } else if ("0".equals(navBarOverride)) {
        mHasNavigationBar = true;
    }
} else {
    mHasStatusBar = false;
    mHasNavigationBar = mDisplayContent.supportsSystemDecorations();
}

2、设置中设置“三按钮”导航更新流程

2.1 属性资源覆盖叠加

OverlayManagerService 运行时资源叠加层 (RRO)
点击设置后,导航栏模式通过 OverlayManagerService 服务对 config_navBarInteractionMode 资源进行叠加,而settings的Secure表中navigation_mode属性只是记录模式。
frameworks/base/services/core/java/com/android/server/om/OverlayManagerService.java

资源叠加主要文件:config.xml
frameworks/base/core/res/res/values/config.xml
/product/overlay/NavigationBarMode3Button/NavigationBarMode3ButtonOverlay.apk
/product/overlay/NavigationBarMode2Button/NavigationBarMode2ButtonOverlay.apk
/product/overlay/NavigationBarModeGestural/NavigationBarModeGesturalOverlay.apk

  • updateActivityManager(affectedPackages, userId):发送受覆盖状态更改影响的所有目标包的配置更改事件。
  • broadcastActionOverlayChanged(targets, userId):发送覆盖包已更改广播ACTION_OVERLAY_CHANGED
private void updateTargetPackagesLocked(@Nullable Set<PackageAndUser> updatedTargets) {
    if (CollectionUtils.isEmpty(updatedTargets)) {
        return;
    }
    persistSettingsLocked();
    final SparseArray<ArraySet<String>> userTargets = groupTargetsByUserId(updatedTargets);
    for (int i = 0, n = userTargets.size(); i < n; i++) {
        final ArraySet<String> targets = userTargets.valueAt(i);
        final int userId = userTargets.keyAt(i);
        final List<String> affectedPackages = updatePackageManagerLocked(targets, userId);
        if (affectedPackages.isEmpty()) {
            // The package manager paths are already up-to-date.
            continue;
        }

        FgThread.getHandler().post(() -> {
            // Send configuration changed events for all target packages that have been affected
            // by overlay state changes.
            updateActivityManager(affectedPackages, userId);

            // Do not send broadcasts for all affected targets. Overlays targeting the framework
            // or shared libraries may cause too many broadcasts to be sent at once.
            broadcastActionOverlayChanged(targets, userId);
        });
    }
}

2.2 SystemUI导航栏接收改变广播

mReceiver :监听ACTION_OVERLAY_CHANGED广播
Secure.NAVIGATION_MODE:记录导航栏模式改变值
mListeners.get(i).onNavigationModeChanged(mode):通知导航栏模式改变的ModeChangedListener监听

frameworks/base/packages/SystemUI/src/com/android/systemui/navigationbar/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 NavigationModeController(Context context,
        DeviceProvisionedController deviceProvisionedController,
        ConfigurationController configurationController,
        @UiBackground Executor uiBgExecutor,
        DumpManager dumpManager) {
    //... ...
    IntentFilter overlayFilter = new IntentFilter(ACTION_OVERLAY_CHANGED);
    overlayFilter.addDataScheme("package");
    overlayFilter.addDataSchemeSpecificPart("android", PatternMatcher.PATTERN_LITERAL);
    mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, overlayFilter, null, null);
    //... ...
}

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

2.3 SystemUI导航栏布局更新

NavigationModeController通知监听执行onNavigationModeChanged方法更新,最后 navBar.getView().updateStates()执行更新界面NavigationBarView

  • updateSlippery():更新WindowManager.LayoutParams.FLAG_SLIPERY状态,具体取决于是否启用了向上滑动,或者通知是否在未处于动画状态的情况下完全打开。如果启用了slide,触摸事件将离开导航栏窗口并进入全屏应用程序/主页窗口,如果没有,则手势离开导航栏后,导航栏将收到取消的触摸事件。
  • reloadNavIcons():重新导入导航栏相关图片资源
  • updateNavButtonIcons:更新界面导航栏图标、显示状态,及活动触摸区域

frameworks/base/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java

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

frameworks/base/packages/SystemUI/src/com/android/systemui/navigationbar/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();
    WindowManagerWrapper.getInstance().setNavBarVirtualKeyHapticFeedbackEnabled(
            !mShowSwipeUpUi);
    getHomeButton().setAccessibilityDelegate(
            mShowSwipeUpUi ? mQuickStepAccessibilityDelegate : null);
}

2.4 时序图

在这里插入图片描述

3、布局文件

3.1 xml文件配置

frameworks/base/packages/SystemUI/res/layout/navigation_bar.xml

<com.android.systemui.navigationbar.NavigationBarView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/navigation_bar_view"
    android:layout_height="match_parent"
    android:layout_width="match_parent"
    android:clipChildren="false"
    android:clipToPadding="false"
    android:background="@drawable/system_bar_background">

    <com.android.systemui.navigationbar.NavigationBarInflaterView
        android:id="@+id/navigation_inflater"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:clipChildren="false"
        android:clipToPadding="false" />

</com.android.systemui.navigationbar.NavigationBarView>

frameworks/base/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarInflaterView.java

View createView(String buttonSpec, ViewGroup parent, LayoutInflater inflater) {
    View v = null;
    String button = extractButton(buttonSpec);
    if (LEFT.equals(button)) {
        button = extractButton(NAVSPACE);
    } else if (RIGHT.equals(button)) {
        button = extractButton(MENU_IME_ROTATE);
    }
    if (HOME.equals(button)) {
        v = inflater.inflate(R.layout.home, parent, false);
    } else if (BACK.equals(button)) {
        v = inflater.inflate(R.layout.back, parent, false);
    } else if (RECENT.equals(button)) {
        v = inflater.inflate(R.layout.recent_apps, parent, false);
    } else if (MENU_IME_ROTATE.equals(button)) {
        v = inflater.inflate(R.layout.menu_ime, parent, false);
    } else if (NAVSPACE.equals(button)) {
        v = inflater.inflate(R.layout.nav_key_space, parent, false);
    } else if (CLIPBOARD.equals(button)) {
        v = inflater.inflate(R.layout.clipboard, parent, false);
    } else if (CONTEXTUAL.equals(button)) {
        v = inflater.inflate(R.layout.contextual, parent, false);
    } else if (HOME_HANDLE.equals(button)) {
        v = inflater.inflate(R.layout.home_handle, parent, false);
    } else if (IME_SWITCHER.equals(button)) {
        v = inflater.inflate(R.layout.ime_switcher, parent, false);
    } else if (button.startsWith(KEY)) {
        String uri = extractImage(button);
        int code = extractKeycode(button);
        v = inflater.inflate(R.layout.custom_key, parent, false);
        ((KeyButtonView) v).setCode(code);
        if (uri != null) {
            if (uri.contains(":")) {
                ((KeyButtonView) v).loadAsync(Icon.createWithContentUri(uri));
            } else if (uri.contains("/")) {
                int index = uri.indexOf('/');
                String pkg = uri.substring(0, index);
                int id = Integer.parseInt(uri.substring(index + 1));
                ((KeyButtonView) v).loadAsync(Icon.createWithResource(pkg, id));
            }
        }
    }
    return v;
}

配置文件:frameworks/base/packages/SystemUI/res/values/config.xml

   <!-- Nav bar button default ordering/layout -->
   <string name="config_navBarLayout" translatable="false">left[.5W],back[1WC];home;recent[1WC],right[.5W]</string>
   <string name="config_navBarLayoutQuickstep" translatable="false">back[1.7WC];home;contextual[1.7WC]</string>
   <string name="config_navBarLayoutHandle" translatable="false">back[70AC];home_handle;ime_switcher[70AC]</string>

frameworks/base/packages/SystemUI/res/layout/home.xml
frameworks/base/packages/SystemUI/res/layout/back.xml
frameworks/base/packages/SystemUI/res/layout/recent_apps.xml
frameworks/base/packages/SystemUI/res/layout/menu_ime.xml
frameworks/base/packages/SystemUI/res/layout/nav_key_space.xml
frameworks/base/packages/SystemUI/res/layout/contextual.xml
frameworks/base/packages/SystemUI/res/layout/home_handle.xml
frameworks/base/packages/SystemUI/res/layout/ime_switcher.xml
frameworks/base/packages/SystemUI/res/layout/custom_key.xml

3.2 back、home、recent_apps

3.2.1 转换成获取 ButtonDispatcher

通过对应xml布局id,将布局给到对应idButtonDispatcher,xml中布局自定对象frameworks/base/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/KeyButtonView.java

frameworks/base/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/ButtonDispatcher.java
frameworks/base/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java

mButtonDispatchers.put(R.id.back, new ButtonDispatcher(R.id.back));
mButtonDispatchers.put(R.id.home, new ButtonDispatcher(R.id.home));
mButtonDispatchers.put(R.id.home_handle, new ButtonDispatcher(R.id.home_handle));
mButtonDispatchers.put(R.id.recent_apps, new ButtonDispatcher(R.id.recent_apps));
mButtonDispatchers.put(R.id.ime_switcher, imeSwitcherButton);
mButtonDispatchers.put(R.id.accessibility_button, accessibilityButton);
mButtonDispatchers.put(R.id.menu_container, mContextualButtonGroup);

@Override
public void onFinishInflate() {
    super.onFinishInflate();
    mNavigationInflaterView = findViewById(R.id.navigation_inflater);
    mNavigationInflaterView.setButtonDispatchers(mButtonDispatchers);

    updateOrientationViews();
    reloadNavIcons();
}

frameworks/base/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarInflaterView.java

public void setButtonDispatchers(SparseArray<ButtonDispatcher> buttonDispatchers) {
    mButtonDispatchers = buttonDispatchers;
    clearDispatcherViews();
    for (int i = 0; i < buttonDispatchers.size(); i++) {
        initiallyFill(buttonDispatchers.valueAt(i));
    }
}

private void initiallyFill(ButtonDispatcher buttonDispatcher) {
    addAll(buttonDispatcher, mHorizontal.findViewById(R.id.ends_group));
    addAll(buttonDispatcher, mHorizontal.findViewById(R.id.center_group));
    addAll(buttonDispatcher, mVertical.findViewById(R.id.ends_group));
    addAll(buttonDispatcher, mVertical.findViewById(R.id.center_group));
}

private void addAll(ButtonDispatcher buttonDispatcher, ViewGroup parent) {
    for (int i = 0; i < parent.getChildCount(); i++) {
        // Need to manually search for each id, just in case each group has more than one
        // of a single id.  It probably mostly a waste of time, but shouldn't take long
        // and will only happen once.
        if (parent.getChildAt(i).getId() == buttonDispatcher.getId()) {
            buttonDispatcher.addView(parent.getChildAt(i));
        }
        if (parent.getChildAt(i) instanceof ViewGroup) {
            addAll(buttonDispatcher, (ViewGroup) parent.getChildAt(i));
        }
    }
}

3.2.2 ButtonDispatcher点击事件

back、home在布局中配置keyCode,通过onTouchEvent触摸判断,sendEvent发送注入事件mInputManager.injectInputEvent()

frameworks/base/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/KeyButtonView.java

@Override
public void setOnClickListener(OnClickListener onClickListener) {
    super.setOnClickListener(onClickListener);
    mOnClickListener = onClickListener;
}

@Override
public boolean onTouchEvent(MotionEvent ev) {
    final boolean showSwipeUI = mOverviewProxyService.shouldShowSwipeUpUI();
    final int action = ev.getAction();
    int x, y;
    if (action == MotionEvent.ACTION_DOWN) {
        mGestureAborted = false;
    }
    if (mGestureAborted) {
        setPressed(false);
        return false;
    }

    switch (action) {
        case MotionEvent.ACTION_DOWN:
            mDownTime = SystemClock.uptimeMillis();
            mLongClicked = false;
            setPressed(true);

            mTouchDownX = (int) ev.getX();
            mTouchDownY = (int) ev.getY();
            if (mCode != KEYCODE_UNKNOWN) {
                sendEvent(KeyEvent.ACTION_DOWN, 0, mDownTime);
            } else {
                // Provide the same haptic feedback that the system offers for virtual keys.
                performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
            }
            if (!showSwipeUI) {
                playSoundEffect(SoundEffectConstants.CLICK);
            }
            removeCallbacks(mCheckLongPress);
            postDelayed(mCheckLongPress, ViewConfiguration.getLongPressTimeout());
            break;
        case MotionEvent.ACTION_MOVE:
            x = (int) ev.getX();
            y = (int) ev.getY();

            float slop = QuickStepContract.getQuickStepTouchSlopPx(getContext());
            if (Math.abs(x - mTouchDownX) > slop || Math.abs(y - mTouchDownY) > slop) {
                // When quick step is enabled, prevent animating the ripple triggered by
                // setPressed and decide to run it on touch up
                setPressed(false);
                removeCallbacks(mCheckLongPress);
            }
            break;
        case MotionEvent.ACTION_CANCEL:
            setPressed(false);
            if (mCode != KEYCODE_UNKNOWN) {
                sendEvent(KeyEvent.ACTION_UP, KeyEvent.FLAG_CANCELED);
            }
            removeCallbacks(mCheckLongPress);
            break;
        case MotionEvent.ACTION_UP:
            final boolean doIt = isPressed() && !mLongClicked;
            setPressed(false);
            final boolean doHapticFeedback = (SystemClock.uptimeMillis() - mDownTime) > 150;
            if (showSwipeUI) {
                if (doIt) {
                    // Apply haptic feedback on touch up since there is none on touch down
                    performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
                    playSoundEffect(SoundEffectConstants.CLICK);
                }
            } else if (doHapticFeedback && !mLongClicked) {
                // Always send a release ourselves because it doesn't seem to be sent elsewhere
                // and it feels weird to sometimes get a release haptic and other times not.
                performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY_RELEASE);
            }
            if (mCode != KEYCODE_UNKNOWN) {
                if (doIt) {
                    sendEvent(KeyEvent.ACTION_UP, 0);
                    sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
                } else {
                    sendEvent(KeyEvent.ACTION_UP, KeyEvent.FLAG_CANCELED);
                }
            } else {
                // no key code, just a regular ImageView
                if (doIt && mOnClickListener != null) {
                    mOnClickListener.onClick(this);
                    sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
                }
            }
            removeCallbacks(mCheckLongPress);
            break;
    }

    return true;
}

private void sendEvent(int action, int flags, long when) {
    mMetricsLogger.write(new LogMaker(MetricsEvent.ACTION_NAV_BUTTON_EVENT)
            .setType(MetricsEvent.TYPE_ACTION)
            .setSubtype(mCode)
            .addTaggedData(MetricsEvent.FIELD_NAV_ACTION, action)
            .addTaggedData(MetricsEvent.FIELD_FLAGS, flags));
    logSomePresses(action, flags);
    if (mCode == KeyEvent.KEYCODE_BACK && flags != KeyEvent.FLAG_LONG_PRESS) {
        Log.i(TAG, "Back button event: " + KeyEvent.actionToString(action));
        if (action == MotionEvent.ACTION_UP) {
            mOverviewProxyService.notifyBackAction((flags & KeyEvent.FLAG_CANCELED) == 0,
                    -1, -1, true /* isButton */, false /* gestureSwipeLeft */);
        }
    }
    final int repeatCount = (flags & KeyEvent.FLAG_LONG_PRESS) != 0 ? 1 : 0;
    final KeyEvent ev = new KeyEvent(mDownTime, when, action, mCode, repeatCount,
            0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
            flags | KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY,
            InputDevice.SOURCE_KEYBOARD);

    int displayId = INVALID_DISPLAY;

    // Make KeyEvent work on multi-display environment
    if (getDisplay() != null) {
        displayId = getDisplay().getDisplayId();
    }
    if (displayId != INVALID_DISPLAY) {
        ev.setDisplayId(displayId);
    }
    mInputManager.injectInputEvent(ev, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
}

frameworks/base/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java

private void prepareNavigationBarView() {
    mView.reorient();

    ButtonDispatcher recentsButton = mView.getRecentsButton();
    recentsButton.setOnClickListener(this::onRecentsClick);
    recentsButton.setOnTouchListener(this::onRecentsTouch);

    ButtonDispatcher homeButton = mView.getHomeButton();
    homeButton.setOnTouchListener(this::onHomeTouch);

    reconfigureHomeLongClick();

    ButtonDispatcher accessibilityButton = mView.getAccessibilityButton();
    accessibilityButton.setOnClickListener(this::onAccessibilityClick);
    accessibilityButton.setOnLongClickListener(this::onAccessibilityLongClick);
    updateAccessibilityStateFlags();

    ButtonDispatcher imeSwitcherButton = mView.getImeSwitchButton();
    imeSwitcherButton.setOnClickListener(this::onImeSwitcherClick);

    updateScreenPinningGestures();
}

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);
}
2023-10-22 01:11:08.481   791-791   KeyButtonView           com.android.systemui                 I  Back button event: ACTION_DOWN
2023-10-22 01:11:08.576   791-791   KeyButtonView           com.android.systemui                 I  Back button event: ACTION_UP
2023-10-22 01:11:12.156   791-791   ShadeControllerImpl     com.android.systemui                 V  NotificationShadeWindow: com.android.systemui.shade.NotificationShadeWindowView{ecab581 I.E...... ......ID 0,0-1440,2560} canPanelBeCollapsed(): false
2023-10-22 01:11:12.196   791-791   ShadeControllerImpl     com.android.systemui                 V  NotificationShadeWindow: com.android.systemui.shade.NotificationShadeWindowView{ecab581 I.E...... ......ID 0,0-1440,2560} canPanelBeCollapsed(): false
2023-10-22 01:11:19.590   791-791   ShadeControllerImpl     com.android.systemui                 V  NotificationShadeWindow: com.android.systemui.shade.NotificationShadeWindowView{ecab581 I.E...... ......ID 0,0-1440,2560} canPanelBeCollapsed(): false
2023-10-22 01:11:19.642   791-791   ShadeControllerImpl     com.android.systemui                 V  NotificationShadeWindow: com.android.systemui.shade.NotificationShadeWindowView{ecab581 I.E...... ......ID 0,0-1440,2560} canPanelBeCollapsed(): false
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xhBruce

佛系随缘,共同探讨

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值