首先
点击下拉菜单的空白处,下拉菜单自动收回功能在android12之后的版本中已经去除,只能通过上滑下拉菜单来收起下拉菜单
下拉菜单全屏显示的情况
以下修改适用于正常显示尺寸设备,下拉菜单占满全屏的情况,下拉菜单不能占满全屏的情况在后面处理
//想在android12之后的版本中也通过点击下拉菜单的空白处自动收起下拉菜单,修改如下
frameworks/base/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
//处理点击下拉菜单空白处的逻辑
private void onEmptySpaceClick() {
if (!mHintAnimationRunning) {
onMiddleClicked();
}
}
private void onMiddleClicked() {
switch (mBarState) {
case KEYGUARD: //密码输入页面
if (!mDozingOnDown) {
mShadeLog.v("onMiddleClicked on Keyguard, mDozingOnDown: false");
// Try triggering face auth, this "might" run. Check
// KeyguardUpdateMonitor#shouldListenForFace to see when face auth won't run.
mKeyguardFaceAuthInteractor.onNotificationPanelClicked();
boolean didFaceAuthRun = mUpdateMonitor.requestFaceAuth(
FaceAuthApiRequestReason.NOTIFICATION_PANEL_CLICKED);
if (didFaceAuthRun) {
mUpdateMonitor.requestActiveUnlock(
ActiveUnlockConfig.ActiveUnlockRequestOrigin.UNLOCK_INTENT,
"lockScreenEmptySpaceTap");
} else {
mLockscreenGestureLogger.write(MetricsEvent.ACTION_LS_HINT,
0 /* lengthDp - N/A */, 0 /* velocityDp - N/A */);
mLockscreenGestureLogger
.log(LockscreenUiEvent.LOCKSCREEN_LOCK_SHOW_HINT);
startUnlockHintAnimation();
}
}
break;
case StatusBarState.SHADE_LOCKED: //锁屏页面的阴影处
if (!mQsController.getExpanded()) {
mStatusBarStateController.setState(KEYGUARD);
}
//添加的修改,阴影位置,点击下拉菜单的空白处返回SHADE
case StatusBarState.SHADE:
//参照android12的处理方式,在子线程中处理点击下拉菜单空白处的逻辑
mView.post(mPostCollapseRunnable);
break;
}
}
//添加的代码,参考原生android12
protected final Runnable mPostCollapseRunnable = new Runnable() {
@Override
public void run() {
collapse(false /* delayed */, 1.0f /* speedUpFactor */);
}
};
//以下是android14现有代码
public void collapse(boolean delayed, float speedUpFactor) {
if (!canBeCollapsed()) {
return;
}
if (mQsController.getExpanded()) {
mQsController.setExpandImmediate(true);
setShowShelfOnly(true);
}
debugLog("collapse: %s", this);
if (canBeCollapsed()) {
cancelHeightAnimator();
notifyExpandingStarted();
// Set after notifyExpandingStarted, as notifyExpandingStarted resets the closing state.
setClosing(true);
if (delayed) {
mNextCollapseSpeedUpFactor = speedUpFactor;
this.mView.postDelayed(mFlingCollapseRunnable, 120);
} else {
fling(0, false /* expand */, speedUpFactor, false /* expandBecauseOfFalsing */);
}
}
}
不规则屏或者大屏幕设备,下拉菜单不能占满全屏时的处理方式
以下修改适用于大屏设备,下拉菜单无法占满全屏,只在屏幕中间居中显示
//下拉菜单view的控制器
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
//以下是android14现有代码,mView是自定义控件NotificationStackScrollLayout.java,点击事件在自定义控件中处理
private void setUpView() {
...
//下拉菜单的触摸事件
mView.setTouchHandler(new TouchHandler());
...
}
class TouchHandler implements Gefingerpoken {
public boolean onInterceptTouchEvent(MotionEvent ev) {
...
//拦截下拉菜单空白处的点击事件
mView.handleEmptySpaceClick(ev);
...
}
public boolean onTouchEvent(MotionEvent ev) {
...
//下拉菜单空白处的点击处理
mView.handleEmptySpaceClick(ev);
....
}
}
//现有的自定义控件
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
//下拉菜单空白处的点击处理
void handleEmptySpaceClick(MotionEvent ev) {
...
switch (ev.getActionMasked()) {
case MotionEvent.ACTION_MOVE: //move事件
final float touchSlop = getTouchSlop(ev);
if (mTouchIsClick && (Math.abs(ev.getY() - mInitialTouchY) > touchSlop
|| Math.abs(ev.getX() - mInitialTouchX) > touchSlop)) {
mTouchIsClick = false;
}
break;
case MotionEvent.ACTION_UP: //up事件
//android14现有代码
//判断当前触摸事件的类型和所在页面,并且触摸位置是否在最后一个通知的下面
//此处最终会执行到NotificationPanelViewController.java中的onEmptySpaceClicked函数中
if (mStatusBarState != StatusBarState.KEYGUARD && mTouchIsClick &&
isBelowLastNotification(mInitialTouchX, mInitialTouchY)) {
debugLog("handleEmptySpaceClick: touch event propagated further");
mOnEmptySpaceClickListener.onEmptySpaceClicked(mInitialTouchX, mInitialTouchY);
}
//添加的修改,针对大屏幕中下拉菜单不能占据全屏的情况,点击的位置在通知区域的左右两边
//isInContentBounds是天机的重写方法
if (mStatusBarState != StatusBarState.KEYGUARD && mTouchIsClick && !isInContentBounds(ev.getX(),ev.getY())){
mOnEmptySpaceClickListener.onEmptySpaceClicked(mInitialTouchX, mInitialTouchY);
}
break;
...
}
}
//添加的修改,判断触摸位置是否是大屏中的下拉菜单的左右空白处
private boolean isInContentBounds(float x, float y) {
int childCount = getChildCount();
for (int i = childCount - 1; i >= 0; i--) {
ExpandableView child = getChildAtIndex(i);
if (child.getVisibility() != View.GONE) {
float chidlWidth = child.getWidth();
float childLeft = child.getX();
if (x > childLeft+chidlWidth || x < childLeft) {
return false;
}
}
}
return true;
}
结语
android高版本已经放弃点击下拉菜单的空白处收起下拉菜单的功能,所以想要高版本中也有此功能可以按照以上部分修改,根据实际情况选择不同的处理方式或者‘全都要’
以上的修改并不能完美的解决下拉菜单自动回收的功能,还是有一点小瑕疵,比如下拉通知栏中有很多通知,有些相同类型的通知会折叠起来,此时如果点击展开折叠起来的通知,此时下拉菜单占满全屏的情况下点击空白位置,下拉通知不会自动收回,再次将通知折叠起来后又可以正常收回,这个情况暂时没有好的解决办法,所以自行选择吧