[DO NOT MERGE] Add animation for Dnd dialog am: 9ac796de8d

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

Change-Id: I68609c1e4fbe0ddcb6fb0b6f6b9df02075179684
This commit is contained in:
Fabian Kozynski
2021-11-22 20:31:39 +00:00
committed by Automerger Merge Worker
4 changed files with 112 additions and 23 deletions

View File

@@ -19,7 +19,6 @@ package com.android.settingslib.notification;
import android.app.ActivityManager; import android.app.ActivityManager;
import android.app.AlarmManager; import android.app.AlarmManager;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.Dialog;
import android.app.NotificationManager; import android.app.NotificationManager;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
@@ -85,6 +84,7 @@ public class EnableZenModeDialog {
@VisibleForTesting @VisibleForTesting
protected Context mContext; protected Context mContext;
private final int mThemeResId;
@VisibleForTesting @VisibleForTesting
protected TextView mZenAlarmWarning; protected TextView mZenAlarmWarning;
@VisibleForTesting @VisibleForTesting
@@ -97,10 +97,15 @@ public class EnableZenModeDialog {
protected LayoutInflater mLayoutInflater; protected LayoutInflater mLayoutInflater;
public EnableZenModeDialog(Context context) { public EnableZenModeDialog(Context context) {
mContext = context; this(context, 0);
} }
public Dialog createDialog() { public EnableZenModeDialog(Context context, int themeResId) {
mContext = context;
mThemeResId = themeResId;
}
public AlertDialog createDialog() {
mNotificationManager = (NotificationManager) mContext. mNotificationManager = (NotificationManager) mContext.
getSystemService(Context.NOTIFICATION_SERVICE); getSystemService(Context.NOTIFICATION_SERVICE);
mForeverId = Condition.newId(mContext).appendPath("forever").build(); mForeverId = Condition.newId(mContext).appendPath("forever").build();
@@ -108,7 +113,7 @@ public class EnableZenModeDialog {
mUserId = mContext.getUserId(); mUserId = mContext.getUserId();
mAttached = false; mAttached = false;
final AlertDialog.Builder builder = new AlertDialog.Builder(mContext) final AlertDialog.Builder builder = new AlertDialog.Builder(mContext, mThemeResId)
.setTitle(R.string.zen_mode_settings_turn_on_dialog_title) .setTitle(R.string.zen_mode_settings_turn_on_dialog_title)
.setNegativeButton(R.string.cancel, null) .setNegativeButton(R.string.cancel, null)
.setPositiveButton(R.string.zen_mode_enable_dialog_turn_on, .setPositiveButton(R.string.zen_mode_enable_dialog_turn_on,

View File

@@ -19,6 +19,7 @@ package com.android.systemui.qs.tiles;
import static android.provider.Settings.Global.ZEN_MODE_ALARMS; import static android.provider.Settings.Global.ZEN_MODE_ALARMS;
import static android.provider.Settings.Global.ZEN_MODE_OFF; import static android.provider.Settings.Global.ZEN_MODE_OFF;
import android.app.AlertDialog;
import android.app.Dialog; import android.app.Dialog;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
@@ -41,7 +42,6 @@ import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.View.OnAttachStateChangeListener; import android.view.View.OnAttachStateChangeListener;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.Switch; import android.widget.Switch;
import android.widget.Toast; import android.widget.Toast;
@@ -53,6 +53,7 @@ import com.android.settingslib.notification.EnableZenModeDialog;
import com.android.systemui.Prefs; import com.android.systemui.Prefs;
import com.android.systemui.R; import com.android.systemui.R;
import com.android.systemui.SysUIToast; import com.android.systemui.SysUIToast;
import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.ActivityStarter;
@@ -84,6 +85,7 @@ public class DndTile extends QSTileImpl<BooleanState> {
private final DndDetailAdapter mDetailAdapter; private final DndDetailAdapter mDetailAdapter;
private final SharedPreferences mSharedPreferences; private final SharedPreferences mSharedPreferences;
private final SecureSetting mSettingZenDuration; private final SecureSetting mSettingZenDuration;
private final DialogLaunchAnimator mDialogLaunchAnimator;
private boolean mListening; private boolean mListening;
private boolean mShowingDetail; private boolean mShowingDetail;
@@ -100,7 +102,8 @@ public class DndTile extends QSTileImpl<BooleanState> {
QSLogger qsLogger, QSLogger qsLogger,
ZenModeController zenModeController, ZenModeController zenModeController,
@Main SharedPreferences sharedPreferences, @Main SharedPreferences sharedPreferences,
SecureSettings secureSettings SecureSettings secureSettings,
DialogLaunchAnimator dialogLaunchAnimator
) { ) {
super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
statusBarStateController, activityStarter, qsLogger); statusBarStateController, activityStarter, qsLogger);
@@ -108,6 +111,7 @@ public class DndTile extends QSTileImpl<BooleanState> {
mSharedPreferences = sharedPreferences; mSharedPreferences = sharedPreferences;
mDetailAdapter = new DndDetailAdapter(); mDetailAdapter = new DndDetailAdapter();
mController.observe(getLifecycle(), mZenCallback); mController.observe(getLifecycle(), mZenCallback);
mDialogLaunchAnimator = dialogLaunchAnimator;
mSettingZenDuration = new SecureSetting(secureSettings, mUiHandler, mSettingZenDuration = new SecureSetting(secureSettings, mUiHandler,
Settings.Secure.ZEN_DURATION, getHost().getUserId()) { Settings.Secure.ZEN_DURATION, getHost().getUserId()) {
@Override @Override
@@ -117,8 +121,6 @@ public class DndTile extends QSTileImpl<BooleanState> {
}; };
} }
public static void setVisible(Context context, boolean visible) { public static void setVisible(Context context, boolean visible) {
Prefs.putBoolean(context, Prefs.Key.DND_TILE_VISIBLE, visible); Prefs.putBoolean(context, Prefs.Key.DND_TILE_VISIBLE, visible);
} }
@@ -187,14 +189,17 @@ public class DndTile extends QSTileImpl<BooleanState> {
switch (zenDuration) { switch (zenDuration) {
case Settings.Secure.ZEN_DURATION_PROMPT: case Settings.Secure.ZEN_DURATION_PROMPT:
mUiHandler.post(() -> { mUiHandler.post(() -> {
Dialog mDialog = new EnableZenModeDialog(mContext).createDialog(); Dialog dialog = makeZenModeDialog();
mDialog.getWindow().setType( if (view != null) {
WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); final Dialog hostDialog =
SystemUIDialog.setShowForAllUsers(mDialog, true); mDialogLaunchAnimator.showFromView(dialog, view, false);
SystemUIDialog.registerDismissListener(mDialog); setDialogListeners(dialog, hostDialog);
SystemUIDialog.setWindowOnTop(mDialog); } else {
mUiHandler.post(() -> mDialog.show()); // If we are not launching with animator, register default
mHost.collapsePanels(); // dismiss listener
SystemUIDialog.registerDismissListener(dialog);
dialog.show();
}
}); });
break; break;
case Settings.Secure.ZEN_DURATION_FOREVER: case Settings.Secure.ZEN_DURATION_FOREVER:
@@ -209,6 +214,20 @@ public class DndTile extends QSTileImpl<BooleanState> {
} }
} }
private Dialog makeZenModeDialog() {
AlertDialog dialog = new EnableZenModeDialog(mContext, R.style.Theme_SystemUI_Dialog)
.createDialog();
SystemUIDialog.applyFlags(dialog);
SystemUIDialog.setShowForAllUsers(dialog, true);
return dialog;
}
private void setDialogListeners(Dialog zenModeDialog, Dialog hostDialog) {
// Zen mode dialog is never hidden.
SystemUIDialog.registerDismissListener(zenModeDialog, hostDialog::dismiss);
zenModeDialog.setOnCancelListener(dialog -> hostDialog.cancel());
}
@Override @Override
protected void handleSecondaryClick(@Nullable View view) { protected void handleSecondaryClick(@Nullable View view) {
if (mController.isVolumeRestricted()) { if (mController.isVolumeRestricted()) {

View File

@@ -36,6 +36,8 @@ import android.view.WindowInsets.Type;
import android.view.WindowManager; import android.view.WindowManager;
import android.view.WindowManager.LayoutParams; import android.view.WindowManager.LayoutParams;
import androidx.annotation.Nullable;
import com.android.systemui.Dependency; import com.android.systemui.Dependency;
import com.android.systemui.R; import com.android.systemui.R;
import com.android.systemui.animation.DialogListener; import com.android.systemui.animation.DialogListener;
@@ -303,13 +305,32 @@ public class SystemUIDialog extends AlertDialog implements ListenableDialog,
* the screen off / close system dialogs broadcast. * the screen off / close system dialogs broadcast.
* <p> * <p>
* <strong>Note:</strong> Don't call dialog.setOnDismissListener() after * <strong>Note:</strong> Don't call dialog.setOnDismissListener() after
* calling this because it causes a leak of BroadcastReceiver. * calling this because it causes a leak of BroadcastReceiver. Instead, call the version that
* takes an extra Runnable as a parameter.
* *
* @param dialog The dialog to be associated with the listener. * @param dialog The dialog to be associated with the listener.
*/ */
public static void registerDismissListener(Dialog dialog) { public static void registerDismissListener(Dialog dialog) {
registerDismissListener(dialog, null);
}
/**
* Registers a listener that dismisses the given dialog when it receives
* the screen off / close system dialogs broadcast.
* <p>
* <strong>Note:</strong> Don't call dialog.setOnDismissListener() after
* calling this because it causes a leak of BroadcastReceiver.
*
* @param dialog The dialog to be associated with the listener.
* @param dismissAction An action to run when the dialog is dismissed.
*/
public static void registerDismissListener(Dialog dialog, @Nullable Runnable dismissAction) {
DismissReceiver dismissReceiver = new DismissReceiver(dialog); DismissReceiver dismissReceiver = new DismissReceiver(dialog);
dialog.setOnDismissListener(d -> dismissReceiver.unregister()); dialog.setOnDismissListener(d -> {
dismissReceiver.unregister();
if (dismissAction != null) dismissAction.run();
});
dismissReceiver.register(); dismissReceiver.register();
} }

View File

@@ -16,22 +16,28 @@
package com.android.systemui.qs.tiles package com.android.systemui.qs.tiles
import android.app.Dialog
import android.content.ContextWrapper import android.content.ContextWrapper
import android.content.SharedPreferences import android.content.SharedPreferences
import android.os.Handler import android.os.Handler
import android.provider.Settings import android.provider.Settings
import android.provider.Settings.Global.ZEN_MODE_OFF
import android.testing.AndroidTestingRunner import android.testing.AndroidTestingRunner
import android.testing.TestableLooper import android.testing.TestableLooper
import android.view.View
import androidx.test.filters.SmallTest import androidx.test.filters.SmallTest
import com.android.internal.logging.MetricsLogger import com.android.internal.logging.MetricsLogger
import com.android.internal.logging.UiEventLogger import com.android.internal.logging.UiEventLogger
import com.android.systemui.SysuiTestCase import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.DialogLaunchAnimator
import com.android.systemui.classifier.FalsingManagerFake import com.android.systemui.classifier.FalsingManagerFake
import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.qs.QSHost import com.android.systemui.qs.QSHost
import com.android.systemui.qs.logging.QSLogger import com.android.systemui.qs.logging.QSLogger
import com.android.systemui.statusbar.policy.ZenModeController import com.android.systemui.statusbar.policy.ZenModeController
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.settings.FakeSettings import com.android.systemui.util.settings.FakeSettings
import com.android.systemui.util.settings.SecureSettings import com.android.systemui.util.settings.SecureSettings
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
@@ -40,9 +46,12 @@ import org.junit.Before
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.mockito.Mock import org.mockito.Mock
import org.mockito.Mockito import org.mockito.Mockito.anyBoolean
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations import org.mockito.MockitoAnnotations
import java.io.File import java.io.File
import org.mockito.Mockito.`when` as whenever
@SmallTest @SmallTest
@RunWith(AndroidTestingRunner::class) @RunWith(AndroidTestingRunner::class)
@@ -70,6 +79,10 @@ class DndTileTest : SysuiTestCase() {
private lateinit var zenModeController: ZenModeController private lateinit var zenModeController: ZenModeController
@Mock @Mock
private lateinit var sharedPreferences: SharedPreferences private lateinit var sharedPreferences: SharedPreferences
@Mock
private lateinit var dialogLaunchAnimator: DialogLaunchAnimator
@Mock
private lateinit var hostDialog: Dialog
private lateinit var secureSettings: SecureSettings private lateinit var secureSettings: SecureSettings
private lateinit var testableLooper: TestableLooper private lateinit var testableLooper: TestableLooper
@@ -81,15 +94,17 @@ class DndTileTest : SysuiTestCase() {
testableLooper = TestableLooper.get(this) testableLooper = TestableLooper.get(this)
secureSettings = FakeSettings() secureSettings = FakeSettings()
Mockito.`when`(qsHost.userId).thenReturn(DEFAULT_USER) whenever(qsHost.userId).thenReturn(DEFAULT_USER)
Mockito.`when`(qsHost.uiEventLogger).thenReturn(uiEventLogger) whenever(qsHost.uiEventLogger).thenReturn(uiEventLogger)
whenever(dialogLaunchAnimator.showFromView(any(), any(), anyBoolean()))
.thenReturn(hostDialog)
val wrappedContext = object : ContextWrapper(context) { val wrappedContext = object : ContextWrapper(context) {
override fun getSharedPreferences(file: File?, mode: Int): SharedPreferences { override fun getSharedPreferences(file: File?, mode: Int): SharedPreferences {
return sharedPreferences return sharedPreferences
} }
} }
Mockito.`when`(qsHost.context).thenReturn(wrappedContext) whenever(qsHost.context).thenReturn(wrappedContext)
tile = DndTile( tile = DndTile(
qsHost, qsHost,
@@ -102,7 +117,8 @@ class DndTileTest : SysuiTestCase() {
qsLogger, qsLogger,
zenModeController, zenModeController,
sharedPreferences, sharedPreferences,
secureSettings secureSettings,
dialogLaunchAnimator
) )
} }
@@ -147,4 +163,32 @@ class DndTileTest : SysuiTestCase() {
assertThat(tile.state.forceExpandIcon).isTrue() assertThat(tile.state.forceExpandIcon).isTrue()
} }
@Test
fun testLaunchDialogFromViewWhenPrompt() {
whenever(zenModeController.zen).thenReturn(ZEN_MODE_OFF)
secureSettings.putIntForUser(KEY, Settings.Secure.ZEN_DURATION_PROMPT, DEFAULT_USER)
testableLooper.processAllMessages()
val view = View(context)
tile.handleClick(view)
testableLooper.processAllMessages()
verify(dialogLaunchAnimator).showFromView(any(), eq(view), anyBoolean())
}
@Test
fun testNoLaunchDialogWhenNotPrompt() {
whenever(zenModeController.zen).thenReturn(ZEN_MODE_OFF)
secureSettings.putIntForUser(KEY, 60, DEFAULT_USER)
testableLooper.processAllMessages()
val view = View(context)
tile.handleClick(view)
testableLooper.processAllMessages()
verify(dialogLaunchAnimator, never()).showFromView(any(), any(), anyBoolean())
}
} }