Merge changes I08c5006a,I6686b77c into qt-dev
* changes: Handle null OnSettingsClickListeners in ChannelDialogEditorController Close channel dialog when the guts go away
This commit is contained in:
committed by
Android (Google) Code Review
commit
d42cb76a74
@@ -29,6 +29,7 @@ import android.graphics.drawable.Drawable
|
|||||||
import android.graphics.drawable.ColorDrawable
|
import android.graphics.drawable.ColorDrawable
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.view.Gravity
|
import android.view.Gravity
|
||||||
|
import android.view.View
|
||||||
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
|
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
|
||||||
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
|
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
|
||||||
import android.view.Window
|
import android.view.Window
|
||||||
@@ -86,13 +87,17 @@ class ChannelEditorDialogController @Inject constructor(
|
|||||||
internal val groupNameLookup = hashMapOf<String, CharSequence>()
|
internal val groupNameLookup = hashMapOf<String, CharSequence>()
|
||||||
private val channelGroupList = mutableListOf<NotificationChannelGroup>()
|
private val channelGroupList = mutableListOf<NotificationChannelGroup>()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Give the controller all of the information it needs to present the dialog
|
||||||
|
* for a given app. Does a bunch of querying of NoMan, but won't present anything yet
|
||||||
|
*/
|
||||||
fun prepareDialogForApp(
|
fun prepareDialogForApp(
|
||||||
appName: String,
|
appName: String,
|
||||||
packageName: String,
|
packageName: String,
|
||||||
uid: Int,
|
uid: Int,
|
||||||
channels: Set<NotificationChannel>,
|
channels: Set<NotificationChannel>,
|
||||||
appIcon: Drawable,
|
appIcon: Drawable,
|
||||||
onSettingsClickListener: NotificationInfo.OnSettingsClickListener
|
onSettingsClickListener: NotificationInfo.OnSettingsClickListener?
|
||||||
) {
|
) {
|
||||||
this.appName = appName
|
this.appName = appName
|
||||||
this.packageName = packageName
|
this.packageName = packageName
|
||||||
@@ -156,6 +161,13 @@ class ChannelEditorDialogController @Inject constructor(
|
|||||||
dialog.show()
|
dialog.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close the dialog without saving. For external callers
|
||||||
|
*/
|
||||||
|
fun close() {
|
||||||
|
done()
|
||||||
|
}
|
||||||
|
|
||||||
private fun done() {
|
private fun done() {
|
||||||
resetState()
|
resetState()
|
||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
@@ -235,6 +247,11 @@ class ChannelEditorDialogController @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
fun launchSettings(sender: View) {
|
||||||
|
onSettingsClickListener?.onClick(sender, null, appUid!!)
|
||||||
|
}
|
||||||
|
|
||||||
private fun initDialog() {
|
private fun initDialog() {
|
||||||
dialog = Dialog(context)
|
dialog = Dialog(context)
|
||||||
|
|
||||||
@@ -257,7 +274,7 @@ class ChannelEditorDialogController @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
findViewById<TextView>(R.id.see_more_button)?.setOnClickListener {
|
findViewById<TextView>(R.id.see_more_button)?.setOnClickListener {
|
||||||
onSettingsClickListener?.onClick(it, null, appUid!!)
|
launchSettings(it)
|
||||||
done()
|
done()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,12 +41,14 @@ import com.android.internal.logging.MetricsLogger;
|
|||||||
import com.android.internal.logging.nano.MetricsProto;
|
import com.android.internal.logging.nano.MetricsProto;
|
||||||
import com.android.systemui.Dependency;
|
import com.android.systemui.Dependency;
|
||||||
import com.android.systemui.Dumpable;
|
import com.android.systemui.Dumpable;
|
||||||
|
import com.android.systemui.SysUiServiceProvider;
|
||||||
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
|
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
|
||||||
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
||||||
import com.android.systemui.statusbar.NotificationLifetimeExtender;
|
import com.android.systemui.statusbar.NotificationLifetimeExtender;
|
||||||
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
|
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
|
||||||
import com.android.systemui.statusbar.NotificationPresenter;
|
import com.android.systemui.statusbar.NotificationPresenter;
|
||||||
import com.android.systemui.statusbar.StatusBarState;
|
import com.android.systemui.statusbar.StatusBarState;
|
||||||
|
import com.android.systemui.statusbar.StatusBarStateControllerImpl;
|
||||||
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
|
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
|
||||||
import com.android.systemui.statusbar.notification.VisualStabilityManager;
|
import com.android.systemui.statusbar.notification.VisualStabilityManager;
|
||||||
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
||||||
@@ -97,6 +99,8 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
|
|||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
protected String mKeyToRemoveOnGutsClosed;
|
protected String mKeyToRemoveOnGutsClosed;
|
||||||
|
|
||||||
|
private StatusBar mStatusBar;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public NotificationGutsManager(
|
public NotificationGutsManager(
|
||||||
Context context,
|
Context context,
|
||||||
@@ -114,6 +118,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
|
|||||||
mListContainer = listContainer;
|
mListContainer = listContainer;
|
||||||
mCheckSaveListener = checkSave;
|
mCheckSaveListener = checkSave;
|
||||||
mOnSettingsClickListener = onSettingsClick;
|
mOnSettingsClickListener = onSettingsClick;
|
||||||
|
mStatusBar = SysUiServiceProvider.getComponent(mContext, StatusBar.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setNotificationActivityStarter(
|
public void setNotificationActivityStarter(
|
||||||
@@ -376,6 +381,34 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
|
|||||||
int x,
|
int x,
|
||||||
int y,
|
int y,
|
||||||
NotificationMenuRowPlugin.MenuItem menuItem) {
|
NotificationMenuRowPlugin.MenuItem menuItem) {
|
||||||
|
if (menuItem.getGutsView() instanceof NotificationInfo) {
|
||||||
|
if (mStatusBarStateController instanceof StatusBarStateControllerImpl) {
|
||||||
|
((StatusBarStateControllerImpl) mStatusBarStateController)
|
||||||
|
.setLeaveOpenOnKeyguardHide(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
Runnable r = () -> Dependency.get(Dependency.MAIN_HANDLER).post(
|
||||||
|
() -> openGutsInternal(view, x, y, menuItem));
|
||||||
|
|
||||||
|
mStatusBar.executeRunnableDismissingKeyguard(
|
||||||
|
r,
|
||||||
|
null /* cancelAction */,
|
||||||
|
false /* dismissShade */,
|
||||||
|
true /* afterKeyguardGone */,
|
||||||
|
true /* deferred */);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return openGutsInternal(view, x, y, menuItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
boolean openGutsInternal(
|
||||||
|
View view,
|
||||||
|
int x,
|
||||||
|
int y,
|
||||||
|
NotificationMenuRowPlugin.MenuItem menuItem) {
|
||||||
|
|
||||||
if (!(view instanceof ExpandableNotificationRow)) {
|
if (!(view instanceof ExpandableNotificationRow)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -118,6 +118,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
|
|||||||
private int mStartingChannelImportance;
|
private int mStartingChannelImportance;
|
||||||
private boolean mWasShownHighPriority;
|
private boolean mWasShownHighPriority;
|
||||||
private boolean mPressedApply;
|
private boolean mPressedApply;
|
||||||
|
private boolean mPresentingChannelEditorDialog = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The last importance level chosen by the user. Null if the user has not chosen an importance
|
* The last importance level chosen by the user. Null if the user has not chosen an importance
|
||||||
@@ -447,11 +448,15 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
|
|||||||
|
|
||||||
private OnClickListener getTurnOffNotificationsClickListener() {
|
private OnClickListener getTurnOffNotificationsClickListener() {
|
||||||
return ((View view) -> {
|
return ((View view) -> {
|
||||||
if (mChannelEditorDialogController != null) {
|
if (!mPresentingChannelEditorDialog && mChannelEditorDialogController != null) {
|
||||||
|
mPresentingChannelEditorDialog = true;
|
||||||
|
|
||||||
mChannelEditorDialogController.prepareDialogForApp(mAppName, mPackageName, mAppUid,
|
mChannelEditorDialogController.prepareDialogForApp(mAppName, mPackageName, mAppUid,
|
||||||
mUniqueChannelsInRow, mPkgIcon, mOnSettingsClickListener);
|
mUniqueChannelsInRow, mPkgIcon, mOnSettingsClickListener);
|
||||||
mChannelEditorDialogController.setOnFinishListener(
|
mChannelEditorDialogController.setOnFinishListener(() -> {
|
||||||
() -> closeControls(this, false));
|
mPresentingChannelEditorDialog = false;
|
||||||
|
closeControls(this, false);
|
||||||
|
});
|
||||||
mChannelEditorDialogController.show();
|
mChannelEditorDialogController.show();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -772,6 +777,13 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean handleCloseControls(boolean save, boolean force) {
|
public boolean handleCloseControls(boolean save, boolean force) {
|
||||||
|
if (mPresentingChannelEditorDialog && mChannelEditorDialogController != null) {
|
||||||
|
mPresentingChannelEditorDialog = false;
|
||||||
|
// No need for the finish listener because we're closing
|
||||||
|
mChannelEditorDialogController.setOnFinishListener(null);
|
||||||
|
mChannelEditorDialogController.close();
|
||||||
|
}
|
||||||
|
|
||||||
// Save regardless of the importance so we can lock the importance field if the user wants
|
// Save regardless of the importance so we can lock the importance field if the user wants
|
||||||
// to keep getting notifications
|
// to keep getting notifications
|
||||||
if (save) {
|
if (save) {
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ class ChannelEditorDialogControllerTest : SysuiTestCase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testPrepareDialogForApp_retrievesUpto4Channels() {
|
fun testPrepareDialogForApp_retrievesUpTo4Channels() {
|
||||||
val channel3 = NotificationChannel("test_channel_3", "Test channel 3", IMPORTANCE_DEFAULT)
|
val channel3 = NotificationChannel("test_channel_3", "Test channel 3", IMPORTANCE_DEFAULT)
|
||||||
val channel4 = NotificationChannel("test_channel_4", "Test channel 4", IMPORTANCE_DEFAULT)
|
val channel4 = NotificationChannel("test_channel_4", "Test channel 4", IMPORTANCE_DEFAULT)
|
||||||
|
|
||||||
@@ -169,6 +169,16 @@ class ChannelEditorDialogControllerTest : SysuiTestCase() {
|
|||||||
eq(TEST_PACKAGE_NAME), eq(TEST_UID), eq(true))
|
eq(TEST_PACKAGE_NAME), eq(TEST_UID), eq(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testSettingsClickListenerNull_noCrash() {
|
||||||
|
group.channels = listOf(channel1, channel2)
|
||||||
|
controller.prepareDialogForApp(TEST_APP_NAME, TEST_PACKAGE_NAME, TEST_UID,
|
||||||
|
setOf(channel1, channel2), appIcon, null)
|
||||||
|
|
||||||
|
// Pass in any old view, it should never actually be used
|
||||||
|
controller.launchSettings(View(context))
|
||||||
|
}
|
||||||
|
|
||||||
private val clickListener = object : NotificationInfo.OnSettingsClickListener {
|
private val clickListener = object : NotificationInfo.OnSettingsClickListener {
|
||||||
override fun onClick(v: View, c: NotificationChannel, appUid: Int) {
|
override fun onClick(v: View, c: NotificationChannel, appUid: Int) {
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ import com.android.systemui.statusbar.notification.VisualStabilityManager;
|
|||||||
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
||||||
import com.android.systemui.statusbar.notification.row.NotificationGutsManager.OnSettingsClickListener;
|
import com.android.systemui.statusbar.notification.row.NotificationGutsManager.OnSettingsClickListener;
|
||||||
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
|
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
|
||||||
|
import com.android.systemui.statusbar.phone.StatusBar;
|
||||||
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
|
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
|
||||||
import com.android.systemui.util.Assert;
|
import com.android.systemui.util.Assert;
|
||||||
|
|
||||||
@@ -105,6 +106,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
|
|||||||
@Mock private NotificationInfo.CheckSaveListener mCheckSaveListener;
|
@Mock private NotificationInfo.CheckSaveListener mCheckSaveListener;
|
||||||
@Mock private OnSettingsClickListener mOnSettingsClickListener;
|
@Mock private OnSettingsClickListener mOnSettingsClickListener;
|
||||||
@Mock private DeviceProvisionedController mDeviceProvisionedController;
|
@Mock private DeviceProvisionedController mDeviceProvisionedController;
|
||||||
|
@Mock private StatusBar mStatusBar;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
@@ -115,7 +117,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
|
|||||||
mDependency.injectTestDependency(MetricsLogger.class, mMetricsLogger);
|
mDependency.injectTestDependency(MetricsLogger.class, mMetricsLogger);
|
||||||
mDependency.injectTestDependency(VisualStabilityManager.class, mVisualStabilityManager);
|
mDependency.injectTestDependency(VisualStabilityManager.class, mVisualStabilityManager);
|
||||||
mHandler = Handler.createAsync(mTestableLooper.getLooper());
|
mHandler = Handler.createAsync(mTestableLooper.getLooper());
|
||||||
|
mContext.putComponent(StatusBar.class, mStatusBar);
|
||||||
mHelper = new NotificationTestHelper(mContext);
|
mHelper = new NotificationTestHelper(mContext);
|
||||||
|
|
||||||
mGutsManager = new NotificationGutsManager(mContext, mVisualStabilityManager);
|
mGutsManager = new NotificationGutsManager(mContext, mVisualStabilityManager);
|
||||||
@@ -150,7 +152,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
|
|||||||
when(row.getWindowToken()).thenReturn(new Binder());
|
when(row.getWindowToken()).thenReturn(new Binder());
|
||||||
when(row.getGuts()).thenReturn(guts);
|
when(row.getGuts()).thenReturn(guts);
|
||||||
|
|
||||||
assertTrue(mGutsManager.openGuts(row, 0, 0, menuItem));
|
assertTrue(mGutsManager.openGutsInternal(row, 0, 0, menuItem));
|
||||||
assertEquals(View.INVISIBLE, guts.getVisibility());
|
assertEquals(View.INVISIBLE, guts.getVisibility());
|
||||||
mTestableLooper.processAllMessages();
|
mTestableLooper.processAllMessages();
|
||||||
verify(guts).openControls(
|
verify(guts).openControls(
|
||||||
@@ -198,7 +200,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
|
|||||||
when(entry.getRow()).thenReturn(row);
|
when(entry.getRow()).thenReturn(row);
|
||||||
when(entry.getGuts()).thenReturn(guts);
|
when(entry.getGuts()).thenReturn(guts);
|
||||||
|
|
||||||
assertTrue(mGutsManager.openGuts(row, 0, 0, menuItem));
|
assertTrue(mGutsManager.openGutsInternal(row, 0, 0, menuItem));
|
||||||
mTestableLooper.processAllMessages();
|
mTestableLooper.processAllMessages();
|
||||||
verify(guts).openControls(
|
verify(guts).openControls(
|
||||||
eq(true),
|
eq(true),
|
||||||
|
|||||||
Reference in New Issue
Block a user