Create notification channel interstitial shelf
From NotificationGuts, tapping "Turn off notifications" will now present
a half-shelf allowing the user to directly block up to 4 channels (the
one given from the notification guts + up to 3 other channels from
that app) or the app itself.
Test: visual (for now)
Bug: 130307442
Fixes: 131432719
Change-Id: I7e82928dfd56b9e25e5bef02607eede55b11d9e3
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 4b6306a..48a7495 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -15,6 +15,7 @@
package com.android.systemui;
import android.annotation.Nullable;
+import android.app.INotificationManager;
import android.content.Context;
import android.content.res.Configuration;
import android.hardware.SensorPrivacyManager;
@@ -68,6 +69,7 @@
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.notification.collection.NotificationData.KeyguardEnvironment;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
+import com.android.systemui.statusbar.notification.row.ChannelEditorDialogController;
import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.phone.AutoHideController;
@@ -298,6 +300,8 @@
@Inject Lazy<SensorPrivacyController> mSensorPrivacyController;
@Inject Lazy<DumpController> mDumpController;
@Inject Lazy<DockManager> mDockManager;
+ @Inject Lazy<ChannelEditorDialogController> mChannelEditorDialogController;
+ @Inject Lazy<INotificationManager> mINotificationManager;
@Inject
public Dependency() {
@@ -473,6 +477,8 @@
mProviders.put(SensorPrivacyController.class, mSensorPrivacyController::get);
mProviders.put(DumpController.class, mDumpController::get);
mProviders.put(DockManager.class, mDockManager::get);
+ mProviders.put(ChannelEditorDialogController.class, mChannelEditorDialogController::get);
+ mProviders.put(INotificationManager.class, mINotificationManager::get);
// TODO(b/118592525): to support multi-display , we start to add something which is
// per-display, while others may be global. I think it's time to add
diff --git a/packages/SystemUI/src/com/android/systemui/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/DependencyProvider.java
index f649976..321206f 100644
--- a/packages/SystemUI/src/com/android/systemui/DependencyProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/DependencyProvider.java
@@ -22,6 +22,7 @@
import static com.android.systemui.Dependency.TIME_TICK_HANDLER_NAME;
import android.annotation.Nullable;
+import android.app.INotificationManager;
import android.content.Context;
import android.hardware.SensorPrivacyManager;
import android.hardware.display.NightDisplayListener;
@@ -132,6 +133,14 @@
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
}
+ /** */
+ @Singleton
+ @Provides
+ public INotificationManager provideINotificationManager() {
+ return INotificationManager.Stub.asInterface(
+ ServiceManager.getService(Context.NOTIFICATION_SERVICE));
+ }
+
@Singleton
@Provides
// Single instance of DisplayMetrics, gets updated by StatusBar, but can be used
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt
new file mode 100644
index 0000000..a065f67
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt
@@ -0,0 +1,267 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.notification.row
+
+import android.app.Dialog
+import android.app.INotificationManager
+import android.app.NotificationChannel
+import android.app.NotificationChannel.DEFAULT_CHANNEL_ID
+import android.app.NotificationChannelGroup
+import android.app.NotificationManager.IMPORTANCE_NONE
+import android.content.Context
+import android.graphics.Color
+import android.graphics.PixelFormat
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.ColorDrawable
+import android.util.Log
+import android.view.Gravity
+import android.view.ViewGroup.LayoutParams.MATCH_PARENT
+import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
+import android.view.Window
+import android.view.WindowManager
+import android.widget.TextView
+import com.android.internal.annotations.VisibleForTesting
+
+import com.android.systemui.R
+
+import javax.inject.Inject
+import javax.inject.Singleton
+
+const val TAG = "ChannelDialogController"
+
+@Singleton
+class ChannelEditorDialogController @Inject constructor(
+ c: Context,
+ private val noMan: INotificationManager
+) {
+ val context: Context = c.applicationContext
+
+ lateinit var dialog: Dialog
+
+ private var appIcon: Drawable? = null
+ private var appUid: Int? = null
+ private var packageName: String? = null
+ private var appName: String? = null
+ private var onSettingsClickListener: NotificationInfo.OnSettingsClickListener? = null
+
+ // Channels handed to us from NotificationInfo
+ @VisibleForTesting
+ internal val providedChannels = mutableListOf<NotificationChannel>()
+
+ // Map from NotificationChannel to importance
+ private val edits = mutableMapOf<NotificationChannel, Int>()
+ var appNotificationsEnabled = true
+
+ // Keep a mapping of NotificationChannel.getGroup() to the actual group name for display
+ @VisibleForTesting
+ internal val groupNameLookup = hashMapOf<String, CharSequence>()
+ private val channelGroupList = mutableListOf<NotificationChannelGroup>()
+
+ fun prepareDialogForApp(
+ appName: String,
+ packageName: String,
+ uid: Int,
+ channels: Set<NotificationChannel>,
+ appIcon: Drawable,
+ onSettingsClickListener: NotificationInfo.OnSettingsClickListener
+ ) {
+ this.appName = appName
+ this.packageName = packageName
+ this.appUid = uid
+ this.appIcon = appIcon
+ this.appNotificationsEnabled = checkAreAppNotificationsOn()
+ this.onSettingsClickListener = onSettingsClickListener
+
+ channelGroupList.clear()
+ channelGroupList.addAll(fetchNotificationChannelGroups())
+ buildGroupNameLookup()
+ padToFourChannels(channels)
+ }
+
+ private fun buildGroupNameLookup() {
+ channelGroupList.forEach { group ->
+ if (group.id != null) {
+ groupNameLookup[group.id] = group.name
+ }
+ }
+ }
+
+ private fun padToFourChannels(channels: Set<NotificationChannel>) {
+ providedChannels.clear()
+ // First, add all of the given channels
+ providedChannels.addAll(channels.asSequence().take(4))
+
+ // Then pad to 4 if we haven't been given that many
+ providedChannels.addAll(getDisplayableChannels(channelGroupList.asSequence())
+ .filterNot { providedChannels.contains(it) }
+ .distinct()
+ .take(4 - providedChannels.size))
+
+ // If we only got one channel and it has the default miscellaneous tag, then we actually
+ // are looking at an app with a targetSdk <= O, and it doesn't make much sense to show the
+ // channel
+ if (providedChannels.size == 1 && DEFAULT_CHANNEL_ID == providedChannels[0].id) {
+ providedChannels.clear()
+ }
+ }
+
+ private fun getDisplayableChannels(
+ groupList: Sequence<NotificationChannelGroup>
+ ): Sequence<NotificationChannel> {
+
+ val channels = groupList
+ .flatMap { group ->
+ group.channels.asSequence().filterNot { channel ->
+ channel.isImportanceLockedByOEM
+ || channel.importance == IMPORTANCE_NONE
+ || channel.isImportanceLockedByCriticalDeviceFunction
+ }
+ }
+
+ // TODO: sort these by avgSentWeekly, but for now let's just do alphabetical (why not)
+ return channels.sortedWith(compareBy { it.name?.toString() ?: it.id })
+ }
+
+ fun show() {
+ initDialog()
+ dialog.show()
+ }
+
+ private fun done() {
+ resetState()
+ dialog.dismiss()
+ }
+
+ private fun resetState() {
+ appIcon = null
+ appUid = null
+ packageName = null
+ appName = null
+
+ edits.clear()
+ providedChannels.clear()
+ groupNameLookup.clear()
+ }
+
+ fun groupNameForId(groupId: String?): CharSequence {
+ return groupNameLookup[groupId] ?: ""
+ }
+
+ fun proposeEditForChannel(channel: NotificationChannel, edit: Int) {
+ if (channel.importance == edit) {
+ edits.remove(channel)
+ } else {
+ edits[channel] = edit
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private fun fetchNotificationChannelGroups(): List<NotificationChannelGroup> {
+ return try {
+ noMan.getNotificationChannelGroupsForPackage(packageName!!, appUid!!, false)
+ .list as? List<NotificationChannelGroup> ?: listOf()
+ } catch (e: Exception) {
+ Log.e(TAG, "Error fetching channel groups", e)
+ listOf()
+ }
+ }
+
+ private fun checkAreAppNotificationsOn(): Boolean {
+ return try {
+ noMan.areNotificationsEnabledForPackage(packageName!!, appUid!!)
+ } catch (e: Exception) {
+ Log.e(TAG, "Error calling NoMan", e)
+ false
+ }
+ }
+
+ private fun applyAppNotificationsOn(b: Boolean) {
+ try {
+ noMan.setNotificationsEnabledForPackage(packageName!!, appUid!!, b)
+ } catch (e: Exception) {
+ Log.e(TAG, "Error calling NoMan", e)
+ }
+ }
+
+ private fun setChannelImportance(channel: NotificationChannel, importance: Int) {
+ try {
+ channel.importance = importance
+ noMan.updateNotificationChannelForPackage(packageName!!, appUid!!, channel)
+ } catch (e: Exception) {
+ Log.e(TAG, "Unable to update notification importance", e)
+ }
+ }
+
+ @VisibleForTesting
+ fun apply() {
+ for ((channel, importance) in edits) {
+ if (channel.importance != importance) {
+ setChannelImportance(channel, importance)
+ }
+ }
+
+ if (appNotificationsEnabled != checkAreAppNotificationsOn()) {
+ applyAppNotificationsOn(appNotificationsEnabled)
+ }
+ }
+
+ private fun initDialog() {
+ dialog = Dialog(context)
+
+ dialog.window?.requestFeature(Window.FEATURE_NO_TITLE)
+ dialog.apply {
+ setContentView(R.layout.notif_half_shelf)
+ setCanceledOnTouchOutside(true)
+ findViewById<ChannelEditorListView>(R.id.half_shelf_container).apply {
+ controller = this@ChannelEditorDialogController
+ appIcon = this@ChannelEditorDialogController.appIcon
+ appName = this@ChannelEditorDialogController.appName
+ channels = providedChannels
+ }
+
+ findViewById<TextView>(R.id.done_button)?.setOnClickListener {
+ apply()
+ done()
+ }
+
+ findViewById<TextView>(R.id.see_more_button)?.setOnClickListener {
+ onSettingsClickListener?.onClick(it, null, appUid!!)
+ dismiss()
+ }
+
+ window?.apply {
+ setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
+ addFlags(wmFlags)
+ setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL)
+ setWindowAnimations(com.android.internal.R.style.Animation_InputMethod)
+
+ attributes = attributes.apply {
+ format = PixelFormat.TRANSLUCENT
+ title = ChannelEditorDialogController::class.java.simpleName
+ gravity = Gravity.BOTTOM or Gravity.CENTER_HORIZONTAL
+ width = MATCH_PARENT
+ height = WRAP_CONTENT
+ }
+ }
+ }
+ }
+
+ private val wmFlags = (WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS
+ or WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+ or WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
+ or WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorListView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorListView.kt
new file mode 100644
index 0000000..7fea30c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorListView.kt
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.notification.row
+
+import android.app.NotificationChannel
+import android.app.NotificationManager.IMPORTANCE_DEFAULT
+import android.app.NotificationManager.IMPORTANCE_NONE
+import android.app.NotificationManager.IMPORTANCE_UNSPECIFIED
+import android.content.Context
+import android.graphics.drawable.Drawable
+import android.text.TextUtils
+import android.transition.AutoTransition
+import android.transition.TransitionManager
+import android.util.AttributeSet
+import android.view.LayoutInflater
+import android.view.View
+import android.widget.ImageView
+import android.widget.LinearLayout
+import android.widget.Switch
+import android.widget.TextView
+
+import com.android.systemui.R
+
+/**
+ * Half-shelf for notification channel controls
+ */
+class ChannelEditorListView(c: Context, attrs: AttributeSet) : LinearLayout(c, attrs) {
+ lateinit var controller: ChannelEditorDialogController
+ var appIcon: Drawable? = null
+ var appName: String? = null
+ var channels = mutableListOf<NotificationChannel>()
+ set(newValue) {
+ field = newValue
+ updateRows()
+ }
+
+ // The first row is for the entire app
+ private lateinit var appControlRow: AppControlView
+
+ override fun onFinishInflate() {
+ super.onFinishInflate()
+
+ appControlRow = findViewById(R.id.app_control)
+ }
+
+ private fun updateRows() {
+ val enabled = controller.appNotificationsEnabled
+
+ val transition = AutoTransition()
+ transition.duration = 200
+ TransitionManager.beginDelayedTransition(this, transition)
+
+ // Remove any rows
+ val n = childCount
+ for (i in n.downTo(0)) {
+ val child = getChildAt(i)
+ if (child is ChannelRow) {
+ removeView(child)
+ }
+ }
+
+ updateAppControlRow(enabled)
+
+ if (enabled) {
+ val inflater = LayoutInflater.from(context)
+ for (channel in channels) {
+ addChannelRow(channel, inflater)
+ }
+ }
+ }
+
+ private fun addChannelRow(channel: NotificationChannel, inflater: LayoutInflater) {
+ val row = inflater.inflate(R.layout.notif_half_shelf_row, null) as ChannelRow
+ row.controller = controller
+ row.channel = channel
+ addView(row)
+ }
+
+ private fun updateAppControlRow(enabled: Boolean) {
+ appControlRow.iconView.setImageDrawable(appIcon)
+ appControlRow.channelName.text = context.resources
+ .getString(R.string.notification_channel_dialog_title, appName)
+ appControlRow.switch.isChecked = enabled
+ appControlRow.switch.setOnCheckedChangeListener { _, b ->
+ controller.appNotificationsEnabled = b
+ updateRows()
+ }
+ }
+}
+
+class AppControlView(c: Context, attrs: AttributeSet) : LinearLayout(c, attrs) {
+ lateinit var iconView: ImageView
+ lateinit var channelName: TextView
+ lateinit var switch: Switch
+
+ override fun onFinishInflate() {
+ iconView = findViewById(R.id.icon)
+ channelName = findViewById(R.id.app_name)
+ switch = findViewById(R.id.toggle)
+ }
+}
+
+class ChannelRow(c: Context, attrs: AttributeSet) : LinearLayout(c, attrs) {
+
+ lateinit var controller: ChannelEditorDialogController
+ private lateinit var iconView: ImageView
+ private lateinit var channelName: TextView
+ private lateinit var channelDescription: TextView
+ private lateinit var switch: Switch
+ var gentle = false
+
+ var channel: NotificationChannel? = null
+ set(newValue) {
+ field = newValue
+ updateImportance()
+ updateViews()
+ }
+
+ override fun onFinishInflate() {
+ iconView = findViewById(R.id.icon)
+ channelName = findViewById(R.id.channel_name)
+ channelDescription = findViewById(R.id.channel_description)
+ switch = findViewById(R.id.toggle)
+ switch.setOnCheckedChangeListener { _, b ->
+ channel?.let {
+ controller.proposeEditForChannel(it, if (b) it.importance else IMPORTANCE_NONE)
+ }
+ }
+ }
+
+ private fun updateViews() {
+ val nc = channel ?: return
+
+ iconView.setImageDrawable(
+ if (gentle)
+ context.getDrawable(R.drawable.ic_notification_gentle)
+ else context.getDrawable(R.drawable.ic_notification_interruptive))
+
+ channelName.text = nc.name ?: "(missing)"
+
+ nc.group?.let { groupId ->
+ channelDescription.text = controller.groupNameForId(groupId)
+ }
+
+ if (nc.group == null || TextUtils.isEmpty(channelDescription.text)) {
+ channelDescription.visibility = View.GONE
+ } else {
+ channelDescription.visibility = View.VISIBLE
+ }
+
+ switch.isChecked = nc.importance != IMPORTANCE_NONE
+ }
+
+ private fun updateImportance() {
+ val importance = channel?.importance ?: 0
+ gentle = importance != IMPORTANCE_UNSPECIFIED && importance < IMPORTANCE_DEFAULT
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 24c7b291..b3ca88f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -2398,6 +2398,14 @@
* it's a summary notification).
*/
public int getNumUniqueChannels() {
+ return getUniqueChannels().size();
+ }
+
+ /**
+ * Returns the channels covered by the notification row (including its children if
+ * it's a summary notification).
+ */
+ public ArraySet<NotificationChannel> getUniqueChannels() {
ArraySet<NotificationChannel> channels = new ArraySet<>();
channels.add(mEntry.channel);
@@ -2417,7 +2425,8 @@
}
}
}
- return channels.size();
+
+ return channels;
}
public void updateChildrenHeaderAppearance() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
index faa7898..f15d6b7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
@@ -18,7 +18,6 @@
import static android.app.AppOpsManager.OP_CAMERA;
import static android.app.AppOpsManager.OP_RECORD_AUDIO;
import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW;
-import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE;
import android.app.INotificationManager;
import android.app.NotificationChannel;
@@ -26,6 +25,7 @@
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
+import android.os.Bundle;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.provider.Settings;
@@ -125,13 +125,18 @@
* Sends an intent to open the notification settings for a particular package and optional
* channel.
*/
+ public static final String EXTRA_SHOW_FRAGMENT_ARGUMENTS = ":settings:show_fragment_args";
private void startAppNotificationSettingsActivity(String packageName, final int appUid,
final NotificationChannel channel, ExpandableNotificationRow row) {
final Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
intent.putExtra(Settings.EXTRA_APP_PACKAGE, packageName);
intent.putExtra(Settings.EXTRA_APP_UID, appUid);
+
if (channel != null) {
+ final Bundle args = new Bundle();
intent.putExtra(EXTRA_FRAGMENT_ARG_KEY, channel.getId());
+ args.putString(EXTRA_FRAGMENT_ARG_KEY, channel.getId());
+ intent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, args);
}
mNotificationActivityStarter.startNotificationGutsIntent(intent, appUid, row);
}
@@ -301,7 +306,7 @@
iNotificationManager,
packageName,
row.getEntry().channel,
- row.getNumUniqueChannels(),
+ row.getUniqueChannels(),
sbn,
mCheckSaveListener,
onSettingsClick,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
index d49f168..942f566 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
@@ -63,6 +63,7 @@
import com.android.systemui.statusbar.notification.logging.NotificationCounters;
import java.util.List;
+import java.util.Set;
/**
* The guts of a notification revealed when performing a long press. This also houses the blocking
@@ -96,12 +97,14 @@
private INotificationManager mINotificationManager;
private PackageManager mPm;
private MetricsLogger mMetricsLogger;
+ private ChannelEditorDialogController mChannelEditorDialogController;
private String mPackageName;
private String mAppName;
private int mAppUid;
private String mDelegatePkg;
private int mNumUniqueChannelsInRow;
+ private Set<NotificationChannel> mUniqueChannelsInRow;
private NotificationChannel mSingleNotificationChannel;
private int mStartingChannelImportance;
private boolean mWasShownHighPriority;
@@ -126,6 +129,7 @@
private NotificationGuts mGutsContainer;
private Drawable mSelectedBackground;
private Drawable mUnselectedBackground;
+ private Drawable mPkgIcon;
/** Whether this view is being shown as part of the blocking helper. */
private boolean mIsForBlockingHelper;
@@ -233,7 +237,7 @@
final INotificationManager iNotificationManager,
final String pkg,
final NotificationChannel notificationChannel,
- final int numUniqueChannelsInRow,
+ final Set<NotificationChannel> uniqueChannelsInRow,
final StatusBarNotification sbn,
final CheckSaveListener checkSaveListener,
final OnSettingsClickListener onSettingsClick,
@@ -244,7 +248,7 @@
boolean wasShownHighPriority)
throws RemoteException {
bindNotification(pm, iNotificationManager, pkg, notificationChannel,
- numUniqueChannelsInRow, sbn, checkSaveListener, onSettingsClick,
+ uniqueChannelsInRow, sbn, checkSaveListener, onSettingsClick,
onAppSettingsClick, isDeviceProvisioned, isNonblockable,
false /* isBlockingHelper */,
importance, wasShownHighPriority);
@@ -255,7 +259,7 @@
INotificationManager iNotificationManager,
String pkg,
NotificationChannel notificationChannel,
- int numUniqueChannelsInRow,
+ Set<NotificationChannel> uniqueChannelsInRow,
StatusBarNotification sbn,
CheckSaveListener checkSaveListener,
OnSettingsClickListener onSettingsClick,
@@ -268,8 +272,10 @@
throws RemoteException {
mINotificationManager = iNotificationManager;
mMetricsLogger = Dependency.get(MetricsLogger.class);
+ mChannelEditorDialogController = Dependency.get(ChannelEditorDialogController.class);
mPackageName = pkg;
- mNumUniqueChannelsInRow = numUniqueChannelsInRow;
+ mUniqueChannelsInRow = uniqueChannelsInRow;
+ mNumUniqueChannelsInRow = uniqueChannelsInRow.size();
mSbn = sbn;
mPm = pm;
mAppSettingsClickListener = onAppSettingsClick;
@@ -355,7 +361,7 @@
}
View turnOffButton = findViewById(R.id.turn_off_notifications);
- turnOffButton.setOnClickListener(getSettingsOnClickListener());
+ turnOffButton.setOnClickListener(getTurnOffNotificationsClickListener());
turnOffButton.setVisibility(turnOffButton.hasOnClickListeners() && !mIsNonblockable
? VISIBLE : GONE);
@@ -379,7 +385,7 @@
private void bindHeader() {
// Package name
- Drawable pkgicon = null;
+ mPkgIcon = null;
ApplicationInfo info;
try {
info = mPm.getApplicationInfo(
@@ -390,13 +396,13 @@
| PackageManager.MATCH_DIRECT_BOOT_AWARE);
if (info != null) {
mAppName = String.valueOf(mPm.getApplicationLabel(info));
- pkgicon = mPm.getApplicationIcon(info);
+ mPkgIcon = mPm.getApplicationIcon(info);
}
} catch (PackageManager.NameNotFoundException e) {
// app is gone, just show package name and generic icon
- pkgicon = mPm.getDefaultActivityIcon();
+ mPkgIcon = mPm.getDefaultActivityIcon();
}
- ((ImageView) findViewById(R.id.pkgicon)).setImageDrawable(pkgicon);
+ ((ImageView) findViewById(R.id.pkgicon)).setImageDrawable(mPkgIcon);
((TextView) findViewById(R.id.pkgname)).setText(mAppName);
// Delegate
@@ -437,6 +443,16 @@
return null;
}
+ private OnClickListener getTurnOffNotificationsClickListener() {
+ return ((View view) -> {
+ if (mChannelEditorDialogController != null) {
+ mChannelEditorDialogController.prepareDialogForApp(mAppName, mPackageName, mAppUid,
+ mUniqueChannelsInRow, mPkgIcon, mOnSettingsClickListener);
+ mChannelEditorDialogController.show();
+ }
+ });
+ }
+
private void bindChannelDetails() throws RemoteException {
bindName();
bindGroup();