settings、systemUI、framework、launcher
点击选择框,选择手势或者按键。切换时实际上是操作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.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
}
}
1、默认全屏手势,设置中切换时,rro覆盖framework默认配置。
2、配置recent使用哪一个
<string name="config_recentsComponentName" translatable="false"
>com.android.launcher/com.android.quickstep.RecentsActivity</string>
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());
}