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 ));
}
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 ));
}
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 ));
}
return candidates;
}
@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
@Inject
public NavigationModeController(Context context,
DeviceProvisionedController deviceProvisionedController,
ConfigurationController configurationController,
@UiBackground Executor uiBgExecutor) {
mContext = context;
mCurrentUserContext = context;
mOverlayManager = IOverlayManager.Stub.asInterface(
ServiceManager.getService(Context.OVERLAY_SERVICE));
mUiBgExecutor = uiBgExecutor;
deviceProvisionedController.addCallback(mDeviceProvisionedCallback);
IntentFilter overlayFilter = new IntentFilter(ACTION_OVERLAY_CHANGED);
overlayFilter.addDataScheme("package");
overlayFilter.addDataSchemeSpecificPart("android", PatternMatcher.PATTERN_LITERAL);
mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, overlayFilter, null, null);
configurationController.addCallback(new ConfigurationController.ConfigurationListener() {
@Override
public void onOverlayChanged() {
if (DEBUG) {
Log.d(TAG, "onOverlayChanged");
}
updateCurrentInteractionMode(true );
}
});
updateCurrentInteractionMode(false );
}
public void updateCurrentInteractionMode(boolean notify) {
mCurrentUserContext = getCurrentUserContext();
int mode = getCurrentInteractionMode(mCurrentUserContext);
if (mode == NAV_BAR_MODE_GESTURAL) {
switchToDefaultGestureNavOverlayIfNecessary();
}
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);
}
}
}
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (DEBUG) {
Log.d(TAG, "ACTION_OVERLAY_CHANGED");
}
updateCurrentInteractionMode(true );
}
};
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());
...
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
mEdgeBackGestureHandler = new EdgeBackGestureHandler(context, mOverviewProxyService,
mSysUiFlagContainer, mPluginManager, this::updateStates);
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{}中
mInputMonitor = InputManager.getInstance().monitorGestureInput(
"edge-swipe", mDisplayId);
mInputEventReceiver = new SysUiInputEventReceiver(
mInputMonitor.getInputChannel(), Looper.getMainLooper());
setEdgeBackPlugin(new NavigationBarEdgePanel(mContext));
mPluginManager.addPluginListener(
this, NavigationEdgeBackPlugin.class, false);
class SysUiInputEventReceiver extends InputEventReceiver {
SysUiInputEventReceiver(InputChannel channel, Looper looper) {
super(channel, looper);
}
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
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() {
IOverviewProxy overviewProxy = mOverviewProxyService.getProxy();
if (overviewProxy != null) {
final Runnable toggleRecents = () -> {
try {
if (mOverviewProxyService.getProxy() != null) {
mOverviewProxyService.getProxy().onOverviewToggle();
mOverviewProxyService.notifyToggleRecentApps();
}
} catch (RemoteException e) {
Log.e(TAG, "Cannot send toggle recents through proxy service.", e);
}
};
if (mStatusBarLazy != null && mStatusBarLazy.get().isKeyguardShowing()) {
mStatusBarLazy.get().executeRunnableDismissingKeyguard(() -> {
mTrustManager.reportKeyguardShowingChanged();
mHandler.post(toggleRecents);
}, null, true , false ,
true );
} else {
toggleRecents.run();
}
return;
} else {
}
}
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)) {
return;
}
Log.d("cyk","RecentsActivityCommand run 222 ");
if (mHelper.switchToRecentsIfVisible(this::onTransitionComplete)) {
return;
}
Log.d("cyk","RecentsActivityCommand run 333 ");
mListener = mHelper.createActivityInitListener(this::onActivityReady);
mListener.registerAndStartActivity(mOverviewComponentObserver.getOverviewIntent(),
this::createWindowAnimation, mContext, mMainThreadExecutor.getHandler(),
mAnimationProvider.getRecentsLaunchDuration());
}
|