Migrate GlobalActionsDialogLite to predictive back

As part of the effort to rollout Predictive Back, the old
"just in time" back handlers need to be migrated over to the new
"ahead of time" api (before any animation/feedback can be added).

This is the first change in this API migration, with more to come.

This also adds tests for GlobalActionsDialogLite.

Bug: 238358031
Test: atest GlobalActionsDialogLiteTest
Change-Id: Id8ee4ec97e34e6de63659d30784384e7c9ef9590
This commit is contained in:
Rahul Banerjee
2022-08-18 10:18:51 -07:00
parent fc1f09ff31
commit 1dde50349e
3 changed files with 101 additions and 1 deletions

View File

@@ -90,6 +90,8 @@ import android.widget.ImageView.ScaleType;
import android.widget.LinearLayout;
import android.widget.ListPopupWindow;
import android.widget.TextView;
import android.window.OnBackInvokedCallback;
import android.window.OnBackInvokedDispatcher;
import androidx.annotation.NonNull;
import androidx.lifecycle.Lifecycle;
@@ -155,6 +157,8 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
public static final String SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS = "globalactions";
public static final String SYSTEM_DIALOG_REASON_DREAM = "dream";
private static final boolean DEBUG = false;
private static final String TAG = "GlobalActionsDialogLite";
private static final String INTERACTION_JANK_TAG = "global_actions";
@@ -2177,6 +2181,11 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
protected ViewGroup mContainer;
private final OnBackInvokedCallback mOnBackInvokedCallback = () -> {
logOnBackInvocation();
dismiss();
};
@VisibleForTesting
protected GestureDetector.SimpleOnGestureListener mGestureListener =
new GestureDetector.SimpleOnGestureListener() {
@@ -2221,6 +2230,16 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
}
};
// this exists so that we can point it to a mock during Unit Testing
private OnBackInvokedDispatcher mOverriddenBackDispatcher;
// the following method exists so that a Unit Test can supply a `OnBackInvokedDispatcher`
@VisibleForTesting
void setBackDispatcherOverride(OnBackInvokedDispatcher mockDispatcher) {
mOverriddenBackDispatcher = mockDispatcher;
}
ActionsDialogLite(Context context, int themeRes, MyAdapter adapter,
MyOverflowAdapter overflowAdapter,
SysuiColorExtractor sysuiColorExtractor, IStatusBarService statusBarService,
@@ -2254,6 +2273,22 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
super.onCreate(savedInstanceState);
initializeLayout();
mWindowDimAmount = getWindow().getAttributes().dimAmount;
getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
OnBackInvokedDispatcher.PRIORITY_DEFAULT, mOnBackInvokedCallback);
if (DEBUG) Log.d(TAG, "OnBackInvokedCallback handler registered");
}
@VisibleForTesting
@Override
public OnBackInvokedDispatcher getOnBackInvokedDispatcher() {
if (mOverriddenBackDispatcher != null) return mOverriddenBackDispatcher;
else return super.getOnBackInvokedDispatcher();
}
@Override
public void onDetachedFromWindow() {
getOnBackInvokedDispatcher().unregisterOnBackInvokedCallback(mOnBackInvokedCallback);
if (DEBUG) Log.d(TAG, "OnBackInvokedCallback handler unregistered");
}
@Override
@@ -2453,7 +2488,12 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
@Override
public void onBackPressed() {
super.onBackPressed();
logOnBackInvocation();
}
private void logOnBackInvocation() {
mUiEventLogger.log(GlobalActionsEvent.GA_CLOSE_BACK);
if (DEBUG) Log.d(TAG, "onBack invoked");
}
@Override

View File

@@ -53,7 +53,8 @@
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.REGISTER_WINDOW_MANAGER_LISTENERS" />
<application android:debuggable="true" android:largeHeap="true">
<application android:debuggable="true" android:largeHeap="true"
android:enableOnBackInvokedCallback="true" >
<uses-library android:name="android.test.runner" />
<receiver android:name="com.android.systemui.SliceBroadcastRelayHandlerTest$Receiver"

View File

@@ -42,8 +42,11 @@ import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.GestureDetector;
import android.view.IWindowManager;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.WindowManagerPolicyConstants;
import android.window.OnBackInvokedCallback;
import android.window.OnBackInvokedDispatcher;
import androidx.test.filters.SmallTest;
@@ -73,6 +76,8 @@ import com.android.systemui.util.settings.SecureSettings;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -117,6 +122,8 @@ public class GlobalActionsDialogLiteTest extends SysuiTestCase {
@Mock private CentralSurfaces mCentralSurfaces;
@Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@Mock private DialogLaunchAnimator mDialogLaunchAnimator;
@Mock private OnBackInvokedDispatcher mOnBackInvokedDispatcher;
@Captor private ArgumentCaptor<OnBackInvokedCallback> mOnBackInvokedCallback;
private TestableLooper mTestableLooper;
@@ -202,6 +209,58 @@ public class GlobalActionsDialogLiteTest extends SysuiTestCase {
verifyLogPosted(GlobalActionsDialogLite.GlobalActionsEvent.GA_CLOSE_BACK);
}
@Test
public void testPredictiveBackCallbackRegisteredAndUnregistered() {
mGlobalActionsDialogLite = spy(mGlobalActionsDialogLite);
doReturn(4).when(mGlobalActionsDialogLite).getMaxShownPowerItems();
doReturn(true).when(mGlobalActionsDialogLite).shouldDisplayLockdown(any());
doReturn(true).when(mGlobalActionsDialogLite).shouldShowAction(any());
String[] actions = {
GlobalActionsDialogLite.GLOBAL_ACTION_KEY_EMERGENCY,
GlobalActionsDialogLite.GLOBAL_ACTION_KEY_LOCKDOWN,
GlobalActionsDialogLite.GLOBAL_ACTION_KEY_POWER,
GlobalActionsDialogLite.GLOBAL_ACTION_KEY_RESTART,
};
doReturn(actions).when(mGlobalActionsDialogLite).getDefaultActions();
GlobalActionsDialogLite.ActionsDialogLite dialog = mGlobalActionsDialogLite.createDialog();
dialog.setBackDispatcherOverride(mOnBackInvokedDispatcher);
dialog.create();
mTestableLooper.processAllMessages();
verify(mOnBackInvokedDispatcher).registerOnBackInvokedCallback(
eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT), any());
dialog.onDetachedFromWindow();
mTestableLooper.processAllMessages();
verify(mOnBackInvokedDispatcher).unregisterOnBackInvokedCallback(any());
}
@Test
public void testPredictiveBackInvocationDismissesDialog() {
mGlobalActionsDialogLite = spy(mGlobalActionsDialogLite);
doReturn(4).when(mGlobalActionsDialogLite).getMaxShownPowerItems();
doReturn(true).when(mGlobalActionsDialogLite).shouldDisplayLockdown(any());
doReturn(true).when(mGlobalActionsDialogLite).shouldShowAction(any());
String[] actions = {
GlobalActionsDialogLite.GLOBAL_ACTION_KEY_EMERGENCY,
GlobalActionsDialogLite.GLOBAL_ACTION_KEY_LOCKDOWN,
GlobalActionsDialogLite.GLOBAL_ACTION_KEY_POWER,
GlobalActionsDialogLite.GLOBAL_ACTION_KEY_RESTART,
};
doReturn(actions).when(mGlobalActionsDialogLite).getDefaultActions();
GlobalActionsDialogLite.ActionsDialogLite dialog = mGlobalActionsDialogLite.createDialog();
dialog.create();
dialog.show();
mTestableLooper.processAllMessages();
dialog.getWindow().injectInputEvent(
new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK));
dialog.getWindow().injectInputEvent(
new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK));
mTestableLooper.processAllMessages();
verifyLogPosted(GlobalActionsDialogLite.GlobalActionsEvent.GA_CLOSE_BACK);
assertThat(dialog.isShowing()).isFalse();
}
@Test
public void testSingleTap_logAndDismiss() {
mGlobalActionsDialogLite = spy(mGlobalActionsDialogLite);