IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android 切换手势和按键、底部recent键事件传递 -> 正文阅读

[移动开发]Android 切换手势和按键、底部recent键事件传递

Android系统切换手势和按键

涉及到的模块

settings、systemUI、framework、launcher

1、settings

点击选择框,选择手势或者按键。切换时实际上是操作overlay,覆盖掉framework里的默认设置
settings里的System Nacigation显示
vendor/mediatek/proprietary/packages/apps/MtkSettings/src/com/android/settings/gestures/SystemNavigationGestureSettings.java

	//显示列表
	@Override
    protected List<? extends CandidateInfo> getCandidates() {
        final Context c = getContext();
        List<CandidateInfoExtra> candidates = new ArrayList<>();
		//判断包名是否存在,如果存在,则添加到显示列表里
        if (SystemNavigationPreferenceController.isOverlayPackageAvailable(c,
                NAV_BAR_MODE_GESTURAL_OVERLAY)) {
            candidates.add(new CandidateInfoExtra(
                    c.getText(R.string.edge_to_edge_navigation_title),
                    c.getText(R.string.edge_to_edge_navigation_summary),
                    KEY_SYSTEM_NAV_GESTURAL, true /* enabled */));
        }
        if (SystemNavigationPreferenceController.isOverlayPackageAvailable(c,
                NAV_BAR_MODE_2BUTTON_OVERLAY)) {
            candidates.add(new CandidateInfoExtra(
                    c.getText(R.string.swipe_up_to_switch_apps_title),
                    c.getText(R.string.swipe_up_to_switch_apps_summary),
                    KEY_SYSTEM_NAV_2BUTTONS, true /* enabled */));
        }
        if (SystemNavigationPreferenceController.isOverlayPackageAvailable(c,
                NAV_BAR_MODE_3BUTTON_OVERLAY)) {
            candidates.add(new CandidateInfoExtra(
                    c.getText(R.string.legacy_navigation_title),
                    c.getText(R.string.legacy_navigation_summary),
                    KEY_SYSTEM_NAV_3BUTTONS, true /* enabled */));
        }

        return candidates;
    }
//点击事件,setEnabledExclusiveInCategory设置当前启动的覆盖包
@VisibleForTesting
static void setCurrentSystemNavigationMode(IOverlayManager overlayManager, String key) {
    String overlayPackage = NAV_BAR_MODE_GESTURAL_OVERLAY;
    AS155(key);
    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、systemUI

2.1、界面显示或者隐藏三大键

vendor/mediatek/proprietary/packages/apps/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java

//构造方法中监听overlayChange
@Inject
public NavigationModeController(Context context,
        DeviceProvisionedController deviceProvisionedController,
        ConfigurationController configurationController,
        @UiBackground Executor uiBgExecutor) {
    mContext = context;
    mCurrentUserContext = context;
    //1、设置callback
    mOverlayManager = IOverlayManager.Stub.asInterface(
            ServiceManager.getService(Context.OVERLAY_SERVICE));
    mUiBgExecutor = uiBgExecutor;
    deviceProvisionedController.addCallback(mDeviceProvisionedCallback);
    //2、监听ACTION_OVERLAY_CHANGED广播
    IntentFilter overlayFilter = new IntentFilter(ACTION_OVERLAY_CHANGED);
    overlayFilter.addDataScheme("package");
    overlayFilter.addDataSchemeSpecificPart("android", PatternMatcher.PATTERN_LITERAL);
    mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, overlayFilter, null, null);
    //3、设置回调
    configurationController.addCallback(new ConfigurationController.ConfigurationListener() {
        @Override
        public void onOverlayChanged() {
            if (DEBUG) {
                Log.d(TAG, "onOverlayChanged");
            }
            updateCurrentInteractionMode(true /* notify */);
        }
    });
    //4、主动调用一次
    updateCurrentInteractionMode(false /* notify */);
}

//上方四种方式都是在调用这个方法
public void updateCurrentInteractionMode(boolean notify) {
    mCurrentUserContext = getCurrentUserContext();
    //获取当前模式,其实就是读取config_navBarInteractionMode的值
    //getResources().getInteger(com.android.internal.R.integer.config_navBarInteractionMode);
    int mode = getCurrentInteractionMode(mCurrentUserContext);
    if (mode == NAV_BAR_MODE_GESTURAL) {
        switchToDefaultGestureNavOverlayIfNecessary();
    }
    //把值写入系统数据库/data/data/com.android.providers.settings/databases/
    mUiBgExecutor.execute(() ->
        Settings.Secure.putString(mCurrentUserContext.getContentResolver(),
                Secure.NAVIGATION_MODE, String.valueOf(mode)));
    if (DEBUG) {
        Log.e(TAG, "updateCurrentInteractionMode: mode=" + mode);
        dumpAssetPaths(mCurrentUserContext);
    }
	//通知改变
    if (notify) {
        for (int i = 0; i < mListeners.size(); i++) {
            mListeners.get(i).onNavigationModeChanged(mode);
        }
    }
}
//监听overlyChange改变广播更新状态
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (DEBUG) {
                Log.d(TAG, "ACTION_OVERLAY_CHANGED");
            }
            updateCurrentInteractionMode(true /* notify */);
        }
    };

2.2、传递recent的点击事件给launcher
vendor/mediatek/proprietary/packages/apps/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java

private static final String ACTION_QUICKSTEP = "android.intent.action.QUICKSTEP_SERVICE";
...
mRecentsComponentName = ComponentName.unflattenFromString(context.getString(
	com.android.internal.R.string.config_recentsComponentName));
mQuickStepIntent = new Intent(ACTION_QUICKSTEP).setPackage(mRecentsComponentName.getPackageName());
...
//bindService
Intent launcherServiceIntent = new Intent(ACTION_QUICKSTEP)
                .setPackage(mRecentsComponentName.getPackageName());
        try {
            mBound = mContext.bindServiceAsUser(launcherServiceIntent,
                    mOverviewServiceConnection,
                    Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
                    UserHandle.of(getCurrentUserId()));
        } catch (SecurityException e) {
            Log.e(TAG_OPS, "Unable to bind because of security error", e);
        }

2.3、view的显示和OverviewProxyService的初始化注册
vendor/mediatek/proprietary/packages/apps/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java

NavigationBarView构造方法中初始化OverviewProxyService
//初始化EdgeBackGestureHandler,传入mOverviewProxyService
mEdgeBackGestureHandler = new EdgeBackGestureHandler(context, mOverviewProxyService,
                mSysUiFlagContainer, mPluginManager, this::updateStates);
//home键图标,如果启动手势,则是一个白色横线,否则是一个圆点
public KeyButtonDrawable getHomeDrawable() {
    final boolean quickStepEnabled = mOverviewProxyService.shouldShowSwipeUpUI();
    KeyButtonDrawable drawable = quickStepEnabled
            ? getDrawable(R.drawable.ic_sysbar_home_quick_step)
            : getDrawable(R.drawable.ic_sysbar_home);
    orientHomeButton(drawable);
    return drawable;
}
//手势事件
重写onAttachedToWindow,当view被添加上去时执行
@Override
protected void onAttachedToWindow() {
    super.onAttachedToWindow();
    requestApplyInsets();
    reorient();
    onNavigationModeChanged(mNavBarMode);
    setUpSwipeUpOnboarding(isQuickStepSwipeUpEnabled());
    if (mRotationButtonController != null) {
        mRotationButtonController.registerListeners();
    }
	//这个里面注册并处理触摸事件
    mEdgeBackGestureHandler.onNavBarAttached();
    getViewTreeObserver().addOnComputeInternalInsetsListener(mOnComputeInternalInsetsListener);
}

vendor/mediatek/proprietary/packages/apps/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java中

updateIsEnabled{}// Register input event receiver
mInputMonitor = InputManager.getInstance().monitorGestureInput(
        "edge-swipe", mDisplayId);
mInputEventReceiver = new SysUiInputEventReceiver(
        mInputMonitor.getInputChannel(), Looper.getMainLooper());

// Add a nav bar panel window
setEdgeBackPlugin(new NavigationBarEdgePanel(mContext));
mPluginManager.addPluginListener(
        this, NavigationEdgeBackPlugin.class, /*allowMultiple=*/ false);
//SysUiInputEventReceiver内部类
    class SysUiInputEventReceiver extends InputEventReceiver {
        SysUiInputEventReceiver(InputChannel channel, Looper looper) {
            super(channel, looper);
        }
        //重写onInputEvent
        public void onInputEvent(InputEvent event) {
            EdgeBackGestureHandler.this.onInputEvent(event);
            finishInputEvent(event, true);
        }
    }
EdgeBackGestureHandler.this.onInputEvent(event);中具体处理触摸事件,这里不做详细分析了

2.4、如果是三按键模式
点击事件注册在vendor/mediatek/proprietary/packages/apps/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java

//prepareNavigationBarView中
ButtonDispatcher recentsButton = mNavigationBarView.getRecentsButton();
recentsButton.setOnClickListener(this::onRecentsClick);
recentsButton.setOnTouchListener(this::onRecentsTouch);
recentsButton.setLongClickable(true);
recentsButton.setOnLongClickListener(this::onLongPressBackRecents);

2.5、点击事件传递给launcher
上面的onRecentsClick调用callback的toggleRecentApps走到
vendor/mediatek/proprietary/packages/apps/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java的toggleRecentApps方法

@Override
public void toggleRecentApps() {
    // If connected to launcher service, let it handle the toggle logic
    IOverviewProxy overviewProxy = mOverviewProxyService.getProxy();
    if (overviewProxy != null) {
        final Runnable toggleRecents = () -> {
            try {
            	//走这里调用到launcher里面去
                if (mOverviewProxyService.getProxy() != null) {
                    mOverviewProxyService.getProxy().onOverviewToggle();
                    mOverviewProxyService.notifyToggleRecentApps();
                }
            } catch (RemoteException e) {
                Log.e(TAG, "Cannot send toggle recents through proxy service.", e);
            }
        };
        // Preload only if device for current user is unlocked
        if (mStatusBarLazy != null && mStatusBarLazy.get().isKeyguardShowing()) {
            mStatusBarLazy.get().executeRunnableDismissingKeyguard(() -> {
                    // Flush trustmanager before checking device locked per user
                    mTrustManager.reportKeyguardShowingChanged();
                    mHandler.post(toggleRecents);
                }, null,  true /* dismissShade */, false /* afterKeyguardGone */,
                true /* deferred */);
        } else {
            toggleRecents.run();
        }
        return;
    } else {
        // Do nothing
    }
}
3、framework

1、默认全屏手势,设置中切换时,rro覆盖framework默认配置。
2、配置recent使用哪一个

<string name="config_recentsComponentName" translatable="false"
            >com.android.launcher/com.android.quickstep.RecentsActivity</string>
4、launcher

launcher内部判断手势和按键,实现具体功能,比如recentui界面的呼出方式

点击recent,分2中情况
1、在launcher界面点击recent键,切换launcher状态
2、在三方应用界面点击recent键,启动launcher并切换转台
3、recent的点击通过systemUI传递过来
quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java的onOverviewToggle中

@Override
public void onOverviewToggle() {
    mOverviewCommandHelper.onOverviewToggle();
}

具体逻辑都在app/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewCommandHelper.java中:
内部类RecentsActivityCommand

public void run() {
            long elapsedTime = mCreateTime - mLastToggleTime;
            mLastToggleTime = mCreateTime;
            Log.d("cyk","RecentsActivityCommand run 111  elapsedTime: "+elapsedTime);
            if (handleCommand(elapsedTime)) {
                // Command already handled.
                return;
            }
            Log.d("cyk","RecentsActivityCommand run 222  ");
            if (mHelper.switchToRecentsIfVisible(this::onTransitionComplete)) {//launcher界面走这里,里面其实就是切换状态逻辑
                // If successfully switched, then return
                return;
            }
            //其它界面走这里
            Log.d("cyk","RecentsActivityCommand run 333  ");
            // Otherwise, start overview.
            mListener = mHelper.createActivityInitListener(this::onActivityReady);
            mListener.registerAndStartActivity(mOverviewComponentObserver.getOverviewIntent(),
                    this::createWindowAnimation, mContext, mMainThreadExecutor.getHandler(),
                    mAnimationProvider.getRecentsLaunchDuration());
        }
  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-11-17 12:52:17  更:2021-11-17 12:53:44 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 3:20:37-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码