Merge "Open QS when swiping from status bar in power menu" into sc-v2-dev am: 6a129229b4

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/14927010

Change-Id: I020d4ab4e9154a763a9e895c90ea4d1cfb497709
This commit is contained in:
Beth Thibodeau
2021-06-16 15:54:51 +00:00
committed by Automerger Merge Worker
4 changed files with 154 additions and 17 deletions

View File

@@ -72,6 +72,7 @@ import com.android.systemui.plugins.GlobalActions.GlobalActionsManager;
import com.android.systemui.plugins.GlobalActionsPanelPlugin; import com.android.systemui.plugins.GlobalActionsPanelPlugin;
import com.android.systemui.statusbar.NotificationShadeDepthController; import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.telephony.TelephonyListenerManager; import com.android.systemui.telephony.TelephonyListenerManager;
@@ -133,7 +134,8 @@ public class GlobalActionsDialog extends GlobalActionsDialogLite
IWindowManager iWindowManager, IWindowManager iWindowManager,
@Background Executor backgroundExecutor, @Background Executor backgroundExecutor,
UiEventLogger uiEventLogger, UiEventLogger uiEventLogger,
RingerModeTracker ringerModeTracker, SysUiState sysUiState, @Main Handler handler) { RingerModeTracker ringerModeTracker, SysUiState sysUiState, @Main Handler handler,
StatusBar statusBar) {
super(context, windowManagerFuncs, super(context, windowManagerFuncs,
audioManager, iDreamManager, audioManager, iDreamManager,
@@ -151,7 +153,7 @@ public class GlobalActionsDialog extends GlobalActionsDialogLite
iWindowManager, iWindowManager,
backgroundExecutor, backgroundExecutor,
uiEventLogger, uiEventLogger,
ringerModeTracker, sysUiState, handler); ringerModeTracker, sysUiState, handler, statusBar);
mLockPatternUtils = lockPatternUtils; mLockPatternUtils = lockPatternUtils;
mKeyguardStateController = keyguardStateController; mKeyguardStateController = keyguardStateController;
@@ -226,7 +228,8 @@ public class GlobalActionsDialog extends GlobalActionsDialogLite
ActionsDialog dialog = new ActionsDialog(getContext(), mAdapter, mOverflowAdapter, ActionsDialog dialog = new ActionsDialog(getContext(), mAdapter, mOverflowAdapter,
this::getWalletViewController, mDepthController, mSysuiColorExtractor, this::getWalletViewController, mDepthController, mSysuiColorExtractor,
mStatusBarService, mNotificationShadeWindowController, mStatusBarService, mNotificationShadeWindowController,
mSysUiState, this::onRotate, isKeyguardShowing(), mPowerAdapter, getEventLogger()); mSysUiState, this::onRotate, isKeyguardShowing(), mPowerAdapter, getEventLogger(),
getStatusBar());
if (shouldShowLockMessage(dialog)) { if (shouldShowLockMessage(dialog)) {
dialog.showLockMessage(); dialog.showLockMessage();
@@ -294,11 +297,13 @@ public class GlobalActionsDialog extends GlobalActionsDialogLite
SysuiColorExtractor sysuiColorExtractor, IStatusBarService statusBarService, SysuiColorExtractor sysuiColorExtractor, IStatusBarService statusBarService,
NotificationShadeWindowController notificationShadeWindowController, NotificationShadeWindowController notificationShadeWindowController,
SysUiState sysuiState, Runnable onRotateCallback, boolean keyguardShowing, SysUiState sysuiState, Runnable onRotateCallback, boolean keyguardShowing,
MyPowerOptionsAdapter powerAdapter, UiEventLogger uiEventLogger) { MyPowerOptionsAdapter powerAdapter, UiEventLogger uiEventLogger,
StatusBar statusBar) {
super(context, com.android.systemui.R.style.Theme_SystemUI_Dialog_GlobalActions, super(context, com.android.systemui.R.style.Theme_SystemUI_Dialog_GlobalActions,
adapter, overflowAdapter, depthController, sysuiColorExtractor, adapter, overflowAdapter, depthController, sysuiColorExtractor,
statusBarService, notificationShadeWindowController, sysuiState, statusBarService, notificationShadeWindowController, sysuiState,
onRotateCallback, keyguardShowing, powerAdapter, uiEventLogger); onRotateCallback, keyguardShowing, powerAdapter, uiEventLogger,
statusBar);
mWalletFactory = walletFactory; mWalletFactory = walletFactory;
// Update window attributes // Update window attributes

View File

@@ -74,8 +74,10 @@ import android.telephony.TelephonyManager;
import android.util.ArraySet; import android.util.ArraySet;
import android.util.Log; import android.util.Log;
import android.view.ContextThemeWrapper; import android.view.ContextThemeWrapper;
import android.view.GestureDetector;
import android.view.IWindowManager; import android.view.IWindowManager;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.Window; import android.view.Window;
@@ -119,6 +121,7 @@ import com.android.systemui.plugins.GlobalActionsPanelPlugin;
import com.android.systemui.scrim.ScrimDrawable; import com.android.systemui.scrim.ScrimDrawable;
import com.android.systemui.statusbar.NotificationShadeDepthController; import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.telephony.TelephonyListenerManager; import com.android.systemui.telephony.TelephonyListenerManager;
@@ -227,6 +230,7 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
private int mDialogPressDelay = DIALOG_PRESS_DELAY; // ms private int mDialogPressDelay = DIALOG_PRESS_DELAY; // ms
protected Handler mMainHandler; protected Handler mMainHandler;
private int mSmallestScreenWidthDp; private int mSmallestScreenWidthDp;
private final StatusBar mStatusBar;
@VisibleForTesting @VisibleForTesting
public enum GlobalActionsEvent implements UiEventLogger.UiEventEnum { public enum GlobalActionsEvent implements UiEventLogger.UiEventEnum {
@@ -320,7 +324,8 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
IWindowManager iWindowManager, IWindowManager iWindowManager,
@Background Executor backgroundExecutor, @Background Executor backgroundExecutor,
UiEventLogger uiEventLogger, UiEventLogger uiEventLogger,
RingerModeTracker ringerModeTracker, SysUiState sysUiState, @Main Handler handler) { RingerModeTracker ringerModeTracker, SysUiState sysUiState, @Main Handler handler,
StatusBar statusBar) {
mContext = context; mContext = context;
mWindowManagerFuncs = windowManagerFuncs; mWindowManagerFuncs = windowManagerFuncs;
mAudioManager = audioManager; mAudioManager = audioManager;
@@ -349,6 +354,7 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
mSysUiState = sysUiState; mSysUiState = sysUiState;
mMainHandler = handler; mMainHandler = handler;
mSmallestScreenWidthDp = mContext.getResources().getConfiguration().smallestScreenWidthDp; mSmallestScreenWidthDp = mContext.getResources().getConfiguration().smallestScreenWidthDp;
mStatusBar = statusBar;
// receive broadcasts // receive broadcasts
IntentFilter filter = new IntentFilter(); IntentFilter filter = new IntentFilter();
@@ -389,6 +395,10 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
return mUiEventLogger; return mUiEventLogger;
} }
protected StatusBar getStatusBar() {
return mStatusBar;
}
/** /**
* Show the global actions dialog (creating if necessary) * Show the global actions dialog (creating if necessary)
* *
@@ -621,7 +631,8 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
mAdapter, mOverflowAdapter, mAdapter, mOverflowAdapter,
mDepthController, mSysuiColorExtractor, mDepthController, mSysuiColorExtractor,
mStatusBarService, mNotificationShadeWindowController, mStatusBarService, mNotificationShadeWindowController,
mSysUiState, this::onRotate, mKeyguardShowing, mPowerAdapter, mUiEventLogger); mSysUiState, this::onRotate, mKeyguardShowing, mPowerAdapter, mUiEventLogger,
mStatusBar);
dialog.setOnDismissListener(this); dialog.setOnDismissListener(this);
dialog.setOnShowListener(this); dialog.setOnShowListener(this);
@@ -2095,16 +2106,61 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
private Dialog mPowerOptionsDialog; private Dialog mPowerOptionsDialog;
protected final Runnable mOnRotateCallback; protected final Runnable mOnRotateCallback;
private UiEventLogger mUiEventLogger; private UiEventLogger mUiEventLogger;
private GestureDetector mGestureDetector;
private StatusBar mStatusBar;
protected ViewGroup mContainer; protected ViewGroup mContainer;
@VisibleForTesting
protected GestureDetector.SimpleOnGestureListener mGestureListener =
new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onDown(MotionEvent e) {
// All gestures begin with this message, so continue listening
return true;
}
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
// Close without opening shade
mUiEventLogger.log(GlobalActionsEvent.GA_CLOSE_TAP_OUTSIDE);
cancel();
return false;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
float distanceY) {
if (distanceY < 0 && distanceY > distanceX
&& e1.getY() <= mStatusBar.getStatusBarHeight()) {
// Downwards scroll from top
openShadeAndDismiss();
return true;
}
return false;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
if (velocityY > 0 && Math.abs(velocityY) > Math.abs(velocityX)
&& e1.getY() <= mStatusBar.getStatusBarHeight()) {
// Downwards fling from top
openShadeAndDismiss();
return true;
}
return false;
}
};
ActionsDialogLite(Context context, int themeRes, MyAdapter adapter, ActionsDialogLite(Context context, int themeRes, MyAdapter adapter,
MyOverflowAdapter overflowAdapter, MyOverflowAdapter overflowAdapter,
NotificationShadeDepthController depthController, NotificationShadeDepthController depthController,
SysuiColorExtractor sysuiColorExtractor, IStatusBarService statusBarService, SysuiColorExtractor sysuiColorExtractor, IStatusBarService statusBarService,
NotificationShadeWindowController notificationShadeWindowController, NotificationShadeWindowController notificationShadeWindowController,
SysUiState sysuiState, Runnable onRotateCallback, boolean keyguardShowing, SysUiState sysuiState, Runnable onRotateCallback, boolean keyguardShowing,
MyPowerOptionsAdapter powerAdapter, UiEventLogger uiEventLogger) { MyPowerOptionsAdapter powerAdapter, UiEventLogger uiEventLogger,
StatusBar statusBar) {
super(context, themeRes); super(context, themeRes);
mContext = context; mContext = context;
mAdapter = adapter; mAdapter = adapter;
@@ -2118,6 +2174,9 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
mOnRotateCallback = onRotateCallback; mOnRotateCallback = onRotateCallback;
mKeyguardShowing = keyguardShowing; mKeyguardShowing = keyguardShowing;
mUiEventLogger = uiEventLogger; mUiEventLogger = uiEventLogger;
mStatusBar = statusBar;
mGestureDetector = new GestureDetector(mContext, mGestureListener);
// Window initialization // Window initialization
Window window = getWindow(); Window window = getWindow();
@@ -2139,6 +2198,23 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
initializeLayout(); initializeLayout();
} }
@Override
public boolean onTouchEvent(MotionEvent event) {
return mGestureDetector.onTouchEvent(event) || super.onTouchEvent(event);
}
private void openShadeAndDismiss() {
mUiEventLogger.log(GlobalActionsEvent.GA_CLOSE_TAP_OUTSIDE);
if (mStatusBar.isKeyguardShowing()) {
// match existing lockscreen behavior to open QS when swiping from status bar
mStatusBar.animateExpandSettingsPanel(null);
} else {
// otherwise, swiping down should expand notification shade
mStatusBar.animateExpandNotificationsPanel();
}
dismiss();
}
private ListPopupWindow createPowerOverflowPopup() { private ListPopupWindow createPowerOverflowPopup() {
GlobalActionsPopupMenu popup = new GlobalActionsPopupMenu( GlobalActionsPopupMenu popup = new GlobalActionsPopupMenu(
new ContextThemeWrapper( new ContextThemeWrapper(
@@ -2187,9 +2263,9 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
mGlobalActionsLayout.setRotationListener(this::onRotate); mGlobalActionsLayout.setRotationListener(this::onRotate);
mGlobalActionsLayout.setAdapter(mAdapter); mGlobalActionsLayout.setAdapter(mAdapter);
mContainer = findViewById(com.android.systemui.R.id.global_actions_container); mContainer = findViewById(com.android.systemui.R.id.global_actions_container);
mContainer.setOnClickListener(v -> { mContainer.setOnTouchListener((v, event) -> {
mUiEventLogger.log(GlobalActionsEvent.GA_CLOSE_TAP_OUTSIDE); mGestureDetector.onTouchEvent(event);
cancel(); return v.onTouchEvent(event);
}); });
View overflowButton = findViewById( View overflowButton = findViewById(

View File

@@ -38,8 +38,9 @@ import android.os.UserManager;
import android.service.dreams.IDreamManager; import android.service.dreams.IDreamManager;
import android.testing.AndroidTestingRunner; import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper; import android.testing.TestableLooper;
import android.view.GestureDetector;
import android.view.IWindowManager; import android.view.IWindowManager;
import android.view.View; import android.view.MotionEvent;
import android.view.WindowManagerPolicyConstants; import android.view.WindowManagerPolicyConstants;
import androidx.test.filters.SmallTest; import androidx.test.filters.SmallTest;
@@ -57,6 +58,7 @@ import com.android.systemui.plugins.GlobalActions;
import com.android.systemui.settings.UserContextProvider; import com.android.systemui.settings.UserContextProvider;
import com.android.systemui.statusbar.NotificationShadeDepthController; import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.telephony.TelephonyListenerManager; import com.android.systemui.telephony.TelephonyListenerManager;
@@ -108,6 +110,7 @@ public class GlobalActionsDialogLiteTest extends SysuiTestCase {
@Mock private SysUiState mSysUiState; @Mock private SysUiState mSysUiState;
@Mock private Handler mHandler; @Mock private Handler mHandler;
@Mock private UserContextProvider mUserContextProvider; @Mock private UserContextProvider mUserContextProvider;
@Mock private StatusBar mStatusBar;
private TestableLooper mTestableLooper; private TestableLooper mTestableLooper;
@@ -148,7 +151,8 @@ public class GlobalActionsDialogLiteTest extends SysuiTestCase {
mUiEventLogger, mUiEventLogger,
mRingerModeTracker, mRingerModeTracker,
mSysUiState, mSysUiState,
mHandler mHandler,
mStatusBar
); );
mGlobalActionsDialogLite.setZeroDialogPressDelayForTesting(); mGlobalActionsDialogLite.setZeroDialogPressDelayForTesting();
@@ -192,7 +196,7 @@ public class GlobalActionsDialogLiteTest extends SysuiTestCase {
} }
@Test @Test
public void testShouldLogOnTapOutside() { public void testSingleTap_logAndDismiss() {
mGlobalActionsDialogLite = spy(mGlobalActionsDialogLite); mGlobalActionsDialogLite = spy(mGlobalActionsDialogLite);
doReturn(4).when(mGlobalActionsDialogLite).getMaxShownPowerItems(); doReturn(4).when(mGlobalActionsDialogLite).getMaxShownPowerItems();
doReturn(true).when(mGlobalActionsDialogLite).shouldDisplayLockdown(any()); doReturn(true).when(mGlobalActionsDialogLite).shouldDisplayLockdown(any());
@@ -205,11 +209,60 @@ public class GlobalActionsDialogLiteTest extends SysuiTestCase {
}; };
doReturn(actions).when(mGlobalActionsDialogLite).getDefaultActions(); doReturn(actions).when(mGlobalActionsDialogLite).getDefaultActions();
GlobalActionsDialogLite.ActionsDialogLite dialog = mGlobalActionsDialogLite.createDialog(); GlobalActionsDialogLite.ActionsDialogLite dialog = mGlobalActionsDialogLite.createDialog();
View container = dialog.findViewById(com.android.systemui.R.id.global_actions_container);
container.callOnClick(); GestureDetector.SimpleOnGestureListener gestureListener = spy(dialog.mGestureListener);
gestureListener.onSingleTapConfirmed(null);
verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_CLOSE_TAP_OUTSIDE); verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_CLOSE_TAP_OUTSIDE);
} }
@Test
public void testSwipeDownLockscreen_logAndOpenQS() {
mGlobalActionsDialogLite = spy(mGlobalActionsDialogLite);
doReturn(4).when(mGlobalActionsDialogLite).getMaxShownPowerItems();
doReturn(true).when(mGlobalActionsDialogLite).shouldDisplayLockdown(any());
doReturn(true).when(mGlobalActionsDialogLite).shouldShowAction(any());
doReturn(true).when(mStatusBar).isKeyguardShowing();
String[] actions = {
GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY,
GlobalActionsDialog.GLOBAL_ACTION_KEY_LOCKDOWN,
GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER,
GlobalActionsDialog.GLOBAL_ACTION_KEY_RESTART,
};
doReturn(actions).when(mGlobalActionsDialogLite).getDefaultActions();
GlobalActionsDialogLite.ActionsDialogLite dialog = mGlobalActionsDialogLite.createDialog();
GestureDetector.SimpleOnGestureListener gestureListener = spy(dialog.mGestureListener);
MotionEvent start = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0);
MotionEvent end = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 500, 0);
gestureListener.onFling(start, end, 0, 1000);
verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_CLOSE_TAP_OUTSIDE);
verify(mStatusBar).animateExpandSettingsPanel(null);
}
@Test
public void testSwipeDown_logAndOpenNotificationShade() {
mGlobalActionsDialogLite = spy(mGlobalActionsDialogLite);
doReturn(4).when(mGlobalActionsDialogLite).getMaxShownPowerItems();
doReturn(true).when(mGlobalActionsDialogLite).shouldDisplayLockdown(any());
doReturn(true).when(mGlobalActionsDialogLite).shouldShowAction(any());
doReturn(false).when(mStatusBar).isKeyguardShowing();
String[] actions = {
GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY,
GlobalActionsDialog.GLOBAL_ACTION_KEY_LOCKDOWN,
GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER,
GlobalActionsDialog.GLOBAL_ACTION_KEY_RESTART,
};
doReturn(actions).when(mGlobalActionsDialogLite).getDefaultActions();
GlobalActionsDialogLite.ActionsDialogLite dialog = mGlobalActionsDialogLite.createDialog();
GestureDetector.SimpleOnGestureListener gestureListener = spy(dialog.mGestureListener);
MotionEvent start = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0);
MotionEvent end = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 500, 0);
gestureListener.onFling(start, end, 0, 1000);
verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_CLOSE_TAP_OUTSIDE);
verify(mStatusBar).animateExpandNotificationsPanel();
}
@Test @Test
public void testShouldLogBugreportPress() throws InterruptedException { public void testShouldLogBugreportPress() throws InterruptedException {
GlobalActionsDialog.BugReportAction bugReportAction = GlobalActionsDialog.BugReportAction bugReportAction =

View File

@@ -65,6 +65,7 @@ import com.android.systemui.plugins.GlobalActionsPanelPlugin;
import com.android.systemui.settings.UserTracker; import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.NotificationShadeDepthController; import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.telephony.TelephonyListenerManager; import com.android.systemui.telephony.TelephonyListenerManager;
@@ -124,6 +125,7 @@ public class GlobalActionsDialogTest extends SysuiTestCase {
@Mock private Handler mHandler; @Mock private Handler mHandler;
@Mock private UserTracker mUserTracker; @Mock private UserTracker mUserTracker;
@Mock private SecureSettings mSecureSettings; @Mock private SecureSettings mSecureSettings;
@Mock private StatusBar mStatusBar;
private TestableLooper mTestableLooper; private TestableLooper mTestableLooper;
@@ -164,7 +166,8 @@ public class GlobalActionsDialogTest extends SysuiTestCase {
mUiEventLogger, mUiEventLogger,
mRingerModeTracker, mRingerModeTracker,
mSysUiState, mSysUiState,
mHandler mHandler,
mStatusBar
); );
mGlobalActionsDialog.setZeroDialogPressDelayForTesting(); mGlobalActionsDialog.setZeroDialogPressDelayForTesting();