本篇文章补充一下之前https://blog.csdn.net/a396604593/article/details/123487805文章中的一些没填上的坑。
此代码基于Android 12
上篇:Launcher功能入口
上篇:launcher功能入口(二)
本篇:launcher功能入口(三)
10、上滑进入recent
packages\apps\Launcher3\quickstep\src\com\android\launcher3\uioverrides\touchcontrollers\NoButtonNavbarToOverviewTouchController.java
public void onDragStart(boolean start, float startDisplacement) {
if (handlingOverviewAnim()) {//判断是否拦截
//设置停顿监听
mMotionPauseDetector.setOnMotionPauseListener(this::onMotionPauseDetected);
}
}
//mDidTouchStartInNavBar赋值
@Override
protected boolean canInterceptTouch(MotionEvent ev) {
mDidTouchStartInNavBar = (ev.getEdgeFlags() & EDGE_NAV_BAR) != 0;
return super.canInterceptTouch(ev);
}
//判断时在底部上滑,并且在主界面
private boolean handlingOverviewAnim() {
int stateFlags = SystemUiProxy.INSTANCE.get(mLauncher).getLastSystemUiStateFlags();
return mDidTouchStartInNavBar && mStartState == NORMAL
&& (stateFlags & SYSUI_STATE_OVERVIEW_DISABLED) == 0;
}
//运动暂停检测,recent的触发是底部上滑并且停顿了一下,就会进入recent界面(Android 12,之前版本的recent触发有所不同)
mMotionPauseDetector.addPosition(event);
//取消mCurrentAnimation动画,进入recent
private void onMotionPauseDetected() {
if (mCurrentAnimation == null) {
return;
}
mNormalToHintOverviewScrimAnimator = null;
mCurrentAnimation.getTarget().addListener(newCancelListener(() ->
mLauncher.getStateManager().goToState(OVERVIEW, true, forSuccessCallback(() -> {
mOverviewResistYAnim = AnimatorControllerWithResistance
.createRecentsResistanceFromOverviewAnim(mLauncher, null)
.createPlaybackController();
mReachedOverview = true;
maybeSwipeInteractionToOverviewComplete();
}))));
mCurrentAnimation.getTarget().removeListener(mClearStateOnCancelListener);
mCurrentAnimation.dispatchOnCancel();
mStartedOverview = true;
VibratorWrapper.INSTANCE.get(mLauncher).vibrate(OVERVIEW_HAPTIC);
}
12、上滑进入all apps
1、packages\apps\Launcher3\src\com\android\launcher3\touch\BaseSwipeDetector.java
处理触摸滚动事件
public boolean onTouchEvent(MotionEvent ev) {...}
2、packages\apps\Launcher3\src\com\android\launcher3\touch\AbstractStateChangeTouchController.java
中判断滑动距离或者速度,决定进入或者不进入allapps
public void onDragEnd(float velocity) {
...
if (fling) {
targetState =
Float.compare(Math.signum(velocity), Math.signum(mProgressMultiplier)) == 0
? mToState : mFromState;
// snap to top or bottom using the release velocity
} else {
targetState =
(interpolatedProgress > SUCCESS_TRANSITION_PROGRESS) ? mToState : mFromState;
}
...
}
注意:mCurrentAnimation动画负责进入退出all apps
没有直接调用packages\apps\Launcher3\src\com\android\launcher3\statemanager\StateManager.java中的goToState方法。
12.1、上滑进入应用列表界面透明度变化
packages/apps/Launcher3/src/com/android/launcher3/allapps/AllAppsTransitionController.java
setAlphas中处理
12.2、快速滑动进入退出allapps界面速度分析
packages/apps/Launcher3/src/com/android/launcher3/touch/SwipeDetector.java
private void reportDragEnd() {
mVelocityTracker.computeCurrentVelocity(1000, mMaxVelocity);//速度计算,计算一秒滑过多少像素
float velocity = mDir.getVelocity(mVelocityTracker, mIsRtl) / 1000;//一秒钟滑动过多少k像素
if (DBG) {
Log.d(TAG, String.format("onScrollEnd disp=%.1f, velocity=%.1f",
mDisplacement, velocity));
}
//
mListener.onDragEnd(velocity, Math.abs(velocity) > RELEASE_VELOCITY_PX_MS);//传入速度和速递阈值判断,速度大于1k 才认为是fling
}
packages/apps/Launcher3/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
onDragEnd根据参数判断是否是fling 如果是 则进入或者退出allapps, 如果不是 判断动画距离是否过半,如果超过0.5f 则改变状态,否则回到上一个状态
13、桌面下拉显示通知栏
packages\apps\Launcher3\quickstep\src\com\android\launcher3\uioverrides\touchcontrollers\StatusBarTouchController.java
StatusBarTouchController拦截滑动事件并传递给systemui
//事件拦截
private boolean canInterceptTouch(MotionEvent ev) {...}
//事件分发
private void dispatchTouchEvent(MotionEvent ev) {
if (mSystemUiProxy.isActive()) {
mLastAction = ev.getActionMasked();
mSystemUiProxy.onStatusBarMotionEvent(ev);
}
}
1、触摸事件的根是从packages\apps\Launcher3\src\com\android\launcher3\dragndrop\DragLayer.java分发下来。
packages\apps\Launcher3\src\com\android\launcher3\views\BaseDragLayer.java中找到处理事件对应的controller
然后由具体的controller处理滑动事件。
private TouchController findControllerToHandleTouch(MotionEvent ev) {
AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(mActivity);
if (topView != null
&& (isEventInLauncher(ev) || topView.canInterceptEventsInSystemGestureRegion())
&& topView.onControllerInterceptTouchEvent(ev)) {
return topView;
}
for (TouchController controller : mControllers) {
if (controller.onControllerInterceptTouchEvent(ev)) {
Log.d("TouchController","TouchController: "+controller);
return controller;
}
}
return null;
}
2、TouchController 接口,主要关注onControllerTouchEvent和onControllerInterceptTouchEvent方法。
触摸事件都在TouchController的实现类中进行。比较多,这里就不贴出来了
public interface TouchController {
/**
* Called when the draglayer receives touch event.
*/
boolean onControllerTouchEvent(MotionEvent ev);
/**
* Called when the draglayer receives a intercept touch event.
*/
boolean onControllerInterceptTouchEvent(MotionEvent ev);
/**
* Called when one handed mode state changed
*/
default void onOneHandedModeStateChanged(boolean activated) { }
default void dump(String prefix, PrintWriter writer) { }
}
3、launcher中滑动处理比较多,有时候找不到对应的处理逻辑。
要忽略复杂多变的实现类,从事件传递根或者重要接口出发,判断是哪个实现类拦截处理了触摸事件。
然后再找具体的拦截判断和触摸事件处理逻辑
implements TouchController, SingleAxisSwipeDetector.Listener
https://blog.csdn.net/a396604593/article/details/123487805中
11、三方应用界面上滑返回launcher
简单写了一下三方应用界面上滑launcher怎么处理输入事件。
跟踪此类问题和触摸事件类似,实现类比较多,要多关注接口。有一个整体的逻辑之后再看具体的处理
也可以看一下其它人写的https://blog.csdn.net/tq501501/article/details/120002676还不错。
有时候通知圆点显示三角形,没有默认赋予权限。
配置config_defaultListenerAccessPackages
即可,framework下面的不生效需要查一下是否gms包覆盖掉了:
vendor/partner_gms/overlay/GmsConfigOverlayCommon/res/values/config.xml
<!-- Colon separated list of package names that should be granted Notification Listener access -->
<string name="config_defaultListenerAccessPackages" translatable="false">com.android.launcher3:com.google.android.projection.gearhead</string>
临时验证:
adb shell settings put secure enabled_notification_listeners com.google.android.projection.gearhead/com.google.android.gearhead.notifications.SharedNotificationListenerManager$ListenerService:com.android.launcher3/com.android.launcher3.notification.NotificationListener
之前写过一点流程,忘记了,这里加一个跳转链接https://blog.csdn.net/a396604593/article/details/128025161
AppWidgetResizeFrame.showForWidget