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
This commit is contained in:
Evan Laird
2019-04-24 15:10:52 -04:00
parent 52ce3686f9
commit 47dc4546ec
17 changed files with 1019 additions and 77 deletions

View File

@@ -0,0 +1,126 @@
<!--
~ 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
-->
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/half_shelf_dialog"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal|bottom"
android:paddingStart="4dp"
android:paddingEnd="4dp"
>
<LinearLayout
android:id="@+id/half_shelf"
android:layout_width="@dimen/qs_panel_width"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="bottom"
android:layout_gravity="center_horizontal|bottom"
android:background="@drawable/rounded_bg_full" >
<com.android.systemui.statusbar.notification.row.ChannelEditorListView
android:id="@+id/half_shelf_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="bottom"
android:orientation="vertical" >
<com.android.systemui.statusbar.notification.row.AppControlView
android:id="@+id/app_control"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp"
android:orientation="horizontal" >
<ImageView
android:id="@+id/icon"
android:layout_height="48dp"
android:layout_width="48dp"
android:padding="8dp" />
<TextView
android:id="@+id/app_name"
android:layout_height="wrap_content"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_gravity="center"
android:padding="8dp"
android:gravity="center_vertical|start"
android:textSize="15sp"
android:ellipsize="end"
android:maxLines="1"
style="@style/TextAppearance.NotificationInfo.Title" />
<Switch
android:id="@+id/toggle"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_gravity="center_vertical"
android:padding="8dp" />
</com.android.systemui.statusbar.notification.row.AppControlView>
<!-- divider view -->
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/notification_channel_dialog_separator"
/>
<!-- ChannelRows get added dynamically -->
</com.android.systemui.statusbar.notification.row.ChannelEditorListView>
<!-- divider view -->
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/notification_channel_dialog_separator"
/>
<RelativeLayout
android:id="@+id/bottom_actions"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="@dimen/notification_guts_button_spacing"
android:paddingStart="20dp"
android:paddingEnd="20dp" >
<TextView
android:id="@+id/see_more_button"
android:text="@string/see_more_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:gravity="start|center_vertical"
android:minWidth="@dimen/notification_importance_toggle_size"
android:minHeight="@dimen/notification_importance_toggle_size"
android:maxWidth="200dp"
style="@style/TextAppearance.NotificationInfo.Button"/>
<TextView
android:id="@+id/done_button"
android:text="@string/inline_ok_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:gravity="end|center_vertical"
android:maxWidth="125dp"
android:minWidth="@dimen/notification_importance_toggle_size"
android:minHeight="@dimen/notification_importance_toggle_size"
android:layout_alignParentEnd="true"
style="@style/TextAppearance.NotificationInfo.Button"/>
</RelativeLayout>
</LinearLayout>
</FrameLayout>

View File

@@ -0,0 +1,78 @@
<!--
~ 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
-->
<com.android.systemui.statusbar.notification.row.ChannelRow
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/half_shelf_row"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp"
android:orientation="horizontal" >
<ImageView
android:id="@+id/icon"
android:layout_height="48dp"
android:layout_width="48dp"
android:layout_gravity="center_vertical"
android:padding="8dp"
/>
<RelativeLayout
android:id="@+id/description_container"
android:layout_height="wrap_content"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_gravity="center_vertical"
android:gravity="left|center_vertical"
android:orientation="vertical"
>
<TextView
android:id="@+id/channel_name"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:paddingBottom="0dp"
android:paddingStart="8dp"
android:paddingEnd="8dp"
android:gravity="center_vertical|start"
android:textSize="14sp"
android:ellipsize="end"
android:maxLines="1"
style="@style/TextAppearance.NotificationInfo.Title"
/>
<TextView
android:id="@+id/channel_description"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:paddingStart="8dp"
android:paddingEnd="8dp"
android:gravity="center_vertical|start"
android:textSize="14sp"
android:ellipsize="end"
android:maxLines="1"
android:layout_below="@id/channel_name"
style="@style/TextAppearance.NotificationInfo.Secondary"
/>
</RelativeLayout>
<Switch
android:id="@+id/toggle"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_gravity="center_vertical"
android:padding="8dp"
/>
</com.android.systemui.statusbar.notification.row.ChannelRow>

View File

@@ -50,6 +50,7 @@
<color name="notification_guts_button_color">@color/GM2_blue_200</color>
<color name="notification_section_header_label_color">@color/GM2_grey_200</color>
<color name="notification_channel_dialog_separator">@color/GM2_grey_700</color>
<!-- The color of the background in the top part of QSCustomizer -->
<color name="qs_customize_background">@color/GM2_grey_900</color>
@@ -74,4 +75,4 @@
<color name="biometric_dialog_accent">#ff80cbc4</color> <!-- light teal -->
<color name="biometric_dialog_error">#fff28b82</color> <!-- red 300 -->
</resources>
</resources>

View File

@@ -98,6 +98,8 @@
<color name="notification_guts_button_color">@color/GM2_blue_700</color>
<color name="notification_section_header_label_color">@color/GM2_grey_900</color>
<!-- The divider view for the notification channel editor half-shelf -->
<color name="notification_channel_dialog_separator">@color/GM2_grey_200</color>
<color name="assist_orb_color">#ffffff</color>

View File

@@ -1688,6 +1688,12 @@
<!-- Notification: Control panel: Label for the app that posted this notification, if it's not the package that the notification was posted for -->
<string name="notification_delegate_header">Proxied notification</string>
<!-- [CHAR LIMIT=40 Notification: Label for the inline channel blocking view -->
<string name="notification_channel_dialog_title">All <xliff:g id="app_name" example="YouTube">%1$s</xliff:g> notifications</string>
<!-- [CHAR LIMIT=20 Notification: "See more" button -->
<string name="see_more_title">See more</string>
<!-- Notification Inline controls: describes what the app is doing in the background [CHAR_LIMIT=NONE] -->
<string name="appops_camera">This app is using the camera.</string>
<!-- Notification Inline controls: describes what the app is doing in the background [CHAR_LIMIT=NONE] -->

View File

@@ -450,6 +450,12 @@
<item name="android:alpha">0.54</item>
</style>
<style name="TextAppearance.NotificationInfo.Title">
<item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
<item name="android:textColor">@color/notification_primary_text_color</item>
<item name="android:textStyle">bold</item>
</style>
<style name="TextAppearance.NotificationInfo.Button">
<item name="android:fontFamily">@*android:string/config_bodyFontFamilyMedium</item>
<item name="android:textSize">16sp</item>

View File

@@ -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.NotificationInterruptionState
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 @@ public class Dependency extends SystemUI {
@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 @@ public class Dependency extends SystemUI {
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

View File

@@ -22,6 +22,7 @@ import static com.android.systemui.Dependency.MAIN_HANDLER_NAME;
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 @@ public class DependencyProvider {
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

View File

@@ -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)
}

View File

@@ -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
}
}

View File

@@ -2398,6 +2398,14 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
* 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 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
}
}
return channels.size();
return channels;
}
public void updateChildrenHeaderAppearance() {

View File

@@ -18,7 +18,6 @@ package com.android.systemui.statusbar.notification.row;
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.Context;
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 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
* 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 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
iNotificationManager,
packageName,
row.getEntry().channel,
row.getNumUniqueChannels(),
row.getUniqueChannels(),
sbn,
mCheckSaveListener,
onSettingsClick,

View File

@@ -63,6 +63,7 @@ import com.android.systemui.R;
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 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
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 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
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 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
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 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
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 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
INotificationManager iNotificationManager,
String pkg,
NotificationChannel notificationChannel,
int numUniqueChannelsInRow,
Set<NotificationChannel> uniqueChannelsInRow,
StatusBarNotification sbn,
CheckSaveListener checkSaveListener,
OnSettingsClickListener onSettingsClick,
@@ -268,8 +272,10 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
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 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
}
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 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
private void bindHeader() {
// Package name
Drawable pkgicon = null;
mPkgIcon = null;
ApplicationInfo info;
try {
info = mPm.getApplicationInfo(
@@ -390,13 +396,13 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
| 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 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
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();

View File

@@ -0,0 +1,190 @@
/*
* 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.INotificationManager
import android.app.NotificationChannel
import android.app.NotificationChannelGroup
import android.app.NotificationManager.IMPORTANCE_DEFAULT
import android.app.NotificationManager.IMPORTANCE_NONE
import android.content.pm.ParceledListSlice
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.print.PrintManager.PRINT_SPOOLER_PACKAGE_NAME
import androidx.test.filters.SmallTest
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.View
import com.android.systemui.SysuiTestCase
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.runner.RunWith
import org.junit.Test
import org.mockito.ArgumentMatchers.anyBoolean
import org.mockito.ArgumentMatchers.eq
import org.mockito.Mock
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
@SmallTest
@RunWith(AndroidTestingRunner::class)
@TestableLooper.RunWithLooper
class ChannelEditorDialogControllerTest : SysuiTestCase() {
private lateinit var controller: ChannelEditorDialogController
private lateinit var channel1: NotificationChannel
private lateinit var channel2: NotificationChannel
private lateinit var channelDefault: NotificationChannel
private lateinit var group: NotificationChannelGroup
private val appIcon = ColorDrawable(Color.MAGENTA)
@Mock
private lateinit var mockNoMan: INotificationManager
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
controller = ChannelEditorDialogController(mContext, mockNoMan)
channel1 = NotificationChannel(TEST_CHANNEL, TEST_CHANNEL_NAME, IMPORTANCE_DEFAULT)
channel2 = NotificationChannel(TEST_CHANNEL2, TEST_CHANNEL_NAME2, IMPORTANCE_DEFAULT)
channelDefault = NotificationChannel(
NotificationChannel.DEFAULT_CHANNEL_ID, TEST_CHANNEL_NAME, IMPORTANCE_DEFAULT)
group = NotificationChannelGroup(TEST_GROUP_ID, TEST_GROUP_NAME)
`when`(mockNoMan.getNotificationChannelGroupsForPackage(
eq(TEST_PACKAGE_NAME), eq(TEST_UID), anyBoolean()))
.thenReturn(ParceledListSlice(listOf(group)))
`when`(mockNoMan.areNotificationsEnabledForPackage(eq(TEST_PACKAGE_NAME), eq(TEST_UID)))
.thenReturn(true)
}
@Test
fun testPrepareDialogForApp_noExtraChannels() {
group.channels = listOf(channel1, channel2)
controller.prepareDialogForApp(TEST_APP_NAME, TEST_PACKAGE_NAME, TEST_UID,
setOf(channel1, channel2), appIcon, clickListener)
assertEquals(2, controller.providedChannels.size)
}
@Test
fun testPrepareDialogForApp_onlyDefaultChannel() {
group.addChannel(channelDefault)
controller.prepareDialogForApp(TEST_APP_NAME, TEST_PACKAGE_NAME, TEST_UID,
setOf(channelDefault), appIcon, clickListener)
assertEquals("No channels should be shown when there is only the miscellaneous channel",
0, controller.providedChannels.size)
}
@Test
fun testPrepareDialogForApp_noProvidedChannels_noException() {
group.channels = listOf()
controller.prepareDialogForApp(TEST_APP_NAME, TEST_PACKAGE_NAME, TEST_UID,
setOf(), appIcon, clickListener)
}
@Test
fun testPrepareDialogForApp_retrievesUpto4Channels() {
val channel3 = NotificationChannel("test_channel_3", "Test channel 3", IMPORTANCE_DEFAULT)
val channel4 = NotificationChannel("test_channel_4", "Test channel 4", IMPORTANCE_DEFAULT)
group.channels = listOf(channel1, channel2, channel3, channel4)
controller.prepareDialogForApp(TEST_APP_NAME, TEST_PACKAGE_NAME, TEST_UID,
setOf(channel1), appIcon, clickListener)
assertEquals("ChannelEditorDialog should fetch enough channels to show 4",
4, controller.providedChannels.size)
}
@Test
fun testApply_demoteChannel() {
group.channels = listOf(channel1, channel2)
controller.prepareDialogForApp(TEST_APP_NAME, TEST_PACKAGE_NAME, TEST_UID,
setOf(channel1, channel2), appIcon, clickListener)
// propose an adjustment of channel1
controller.proposeEditForChannel(channel1, IMPORTANCE_NONE)
controller.apply()
assertEquals("Proposed edits should take effect after apply",
IMPORTANCE_NONE, channel1.importance)
// Channel 2 shouldn't have changed
assertEquals("Proposed edits should take effect after apply",
IMPORTANCE_DEFAULT, channel2.importance)
}
@Test
fun testApply_demoteApp() {
group.channels = listOf(channel1, channel2)
controller.prepareDialogForApp(TEST_APP_NAME, TEST_PACKAGE_NAME, TEST_UID,
setOf(channel1, channel2), appIcon, clickListener)
controller.appNotificationsEnabled = false
controller.apply()
verify(mockNoMan, times(1)).setNotificationsEnabledForPackage(
eq(TEST_PACKAGE_NAME), eq(TEST_UID), eq(false))
}
@Test
fun testApply_promoteApp() {
// App starts out disabled
`when`(mockNoMan.areNotificationsEnabledForPackage(eq(TEST_PACKAGE_NAME), eq(TEST_UID)))
.thenReturn(false)
controller.prepareDialogForApp(TEST_APP_NAME, TEST_PACKAGE_NAME, TEST_UID,
setOf(channel1, channel2), appIcon, clickListener)
controller.appNotificationsEnabled = true
controller.apply()
verify(mockNoMan, times(1)).setNotificationsEnabledForPackage(
eq(TEST_PACKAGE_NAME), eq(TEST_UID), eq(true))
}
private val clickListener = object : NotificationInfo.OnSettingsClickListener {
override fun onClick(v: View, c: NotificationChannel, appUid: Int) {
}
}
companion object {
const val TEST_APP_NAME = "Test App Name"
const val TEST_PACKAGE_NAME = "test_package"
const val TEST_SYSTEM_PACKAGE_NAME = PRINT_SPOOLER_PACKAGE_NAME
const val TEST_UID = 1
const val MULTIPLE_CHANNEL_COUNT = 2
const val TEST_CHANNEL = "test_channel"
const val TEST_CHANNEL_NAME = "Test Channel Name"
const val TEST_CHANNEL2 = "test_channel2"
const val TEST_CHANNEL_NAME2 = "Test Channel Name2"
const val TEST_GROUP_ID = "test_group_id"
const val TEST_GROUP_NAME = "Test Group Name"
}
}

View File

@@ -31,6 +31,7 @@ import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anySet;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
@@ -317,7 +318,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
any(INotificationManager.class),
eq(statusBarNotification.getPackageName()),
any(NotificationChannel.class),
anyInt(),
anySet(),
eq(statusBarNotification),
any(NotificationInfo.CheckSaveListener.class),
any(NotificationInfo.OnSettingsClickListener.class),
@@ -345,7 +346,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
any(INotificationManager.class),
eq(statusBarNotification.getPackageName()),
any(NotificationChannel.class),
anyInt(),
anySet(),
eq(statusBarNotification),
any(NotificationInfo.CheckSaveListener.class),
any(NotificationInfo.OnSettingsClickListener.class),
@@ -375,7 +376,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
any(INotificationManager.class),
eq(statusBarNotification.getPackageName()),
any(NotificationChannel.class),
anyInt(),
anySet(),
eq(statusBarNotification),
any(NotificationInfo.CheckSaveListener.class),
any(NotificationInfo.OnSettingsClickListener.class),
@@ -404,7 +405,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
any(INotificationManager.class),
eq(statusBarNotification.getPackageName()),
any(NotificationChannel.class),
anyInt(),
anySet(),
eq(statusBarNotification),
any(NotificationInfo.CheckSaveListener.class),
any(NotificationInfo.OnSettingsClickListener.class),
@@ -432,7 +433,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
any(INotificationManager.class),
eq(statusBarNotification.getPackageName()),
any(NotificationChannel.class),
anyInt(),
anySet(),
eq(statusBarNotification),
any(NotificationInfo.CheckSaveListener.class),
any(NotificationInfo.OnSettingsClickListener.class),

View File

@@ -20,7 +20,6 @@ import static android.app.NotificationChannel.USER_LOCKED_IMPORTANCE;
import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
import static android.app.NotificationManager.IMPORTANCE_LOW;
import static android.app.NotificationManager.IMPORTANCE_MIN;
import static android.app.NotificationManager.IMPORTANCE_NONE;
import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
import static android.print.PrintManager.PRINT_SPOOLER_PACKAGE_NAME;
import static android.provider.Settings.Secure.NOTIFICATION_NEW_INTERRUPTION_MODEL;
@@ -54,7 +53,6 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.metrics.LogMaker;
import android.os.IBinder;
import android.os.UserHandle;
import android.provider.Settings;
@@ -70,7 +68,6 @@ import android.widget.ImageView;
import android.widget.TextView;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.Dependency;
import com.android.systemui.R;
@@ -86,6 +83,8 @@ import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
@SmallTest
@@ -103,6 +102,8 @@ public class NotificationInfoTest extends SysuiTestCase {
private NotificationInfo mNotificationInfo;
private NotificationChannel mNotificationChannel;
private NotificationChannel mDefaultNotificationChannel;
private Set<NotificationChannel> mNotificationChannelSet = new HashSet<>();
private Set<NotificationChannel> mDefaultNotificationChannelSet = new HashSet<>();
private StatusBarNotification mSbn;
@Rule
@@ -153,9 +154,11 @@ public class NotificationInfoTest extends SysuiTestCase {
// Some test channels.
mNotificationChannel = new NotificationChannel(
TEST_CHANNEL, TEST_CHANNEL_NAME, IMPORTANCE_LOW);
mNotificationChannelSet.add(mNotificationChannel);
mDefaultNotificationChannel = new NotificationChannel(
NotificationChannel.DEFAULT_CHANNEL_ID, TEST_CHANNEL_NAME,
IMPORTANCE_LOW);
mDefaultNotificationChannelSet.add(mDefaultNotificationChannel);
mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID, 0,
new Notification(), UserHandle.CURRENT, null, 0);
@@ -191,7 +194,7 @@ public class NotificationInfoTest extends SysuiTestCase {
public void testBindNotification_SetsTextApplicationName() throws Exception {
when(mMockPackageManager.getApplicationLabel(any())).thenReturn("App Name");
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn,
TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn,
null, null, null,
true, false,
IMPORTANCE_DEFAULT, true);
@@ -206,7 +209,8 @@ public class NotificationInfoTest extends SysuiTestCase {
when(mMockPackageManager.getApplicationIcon(any(ApplicationInfo.class)))
.thenReturn(iconDrawable);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn,
null, null, null, true, false,
IMPORTANCE_DEFAULT, true);
final ImageView iconView = mNotificationInfo.findViewById(R.id.pkgicon);
assertEquals(iconDrawable, iconView.getDrawable());
@@ -215,7 +219,8 @@ public class NotificationInfoTest extends SysuiTestCase {
@Test
public void testBindNotification_noDelegate() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn,
null, null, null, true, false,
IMPORTANCE_DEFAULT, true);
final TextView nameView = mNotificationInfo.findViewById(R.id.delegate_name);
assertEquals(GONE, nameView.getVisibility());
@@ -234,7 +239,8 @@ public class NotificationInfoTest extends SysuiTestCase {
when(mMockPackageManager.getApplicationLabel(any())).thenReturn("Other");
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, null, null,
null, true, false,
IMPORTANCE_DEFAULT, true);
final TextView nameView = mNotificationInfo.findViewById(R.id.delegate_name);
assertEquals(VISIBLE, nameView.getVisibility());
@@ -246,7 +252,8 @@ public class NotificationInfoTest extends SysuiTestCase {
@Test
public void testBindNotification_GroupNameHiddenIfNoGroup() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, null, null,
null, true, false,
IMPORTANCE_DEFAULT, true);
final TextView groupNameView = mNotificationInfo.findViewById(R.id.group_name);
assertEquals(GONE, groupNameView.getVisibility());
@@ -261,7 +268,8 @@ public class NotificationInfoTest extends SysuiTestCase {
eq("test_group_id"), eq(TEST_PACKAGE_NAME), eq(TEST_UID)))
.thenReturn(notificationChannelGroup);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, null, null,
null, true, false,
IMPORTANCE_DEFAULT, true);
final TextView groupNameView = mNotificationInfo.findViewById(R.id.group_name);
assertEquals(View.VISIBLE, groupNameView.getVisibility());
@@ -271,7 +279,8 @@ public class NotificationInfoTest extends SysuiTestCase {
@Test
public void testBindNotification_SetsTextChannelName() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, null, null,
null, true, false,
IMPORTANCE_DEFAULT, true);
final TextView textView = mNotificationInfo.findViewById(R.id.channel_name);
assertEquals(TEST_CHANNEL_NAME, textView.getText());
@@ -280,8 +289,8 @@ public class NotificationInfoTest extends SysuiTestCase {
@Test
public void testBindNotification_DefaultChannelDoesNotUseChannelName() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mDefaultNotificationChannel, 1, mSbn, null, null, null, true,
false, IMPORTANCE_DEFAULT, true);
TEST_PACKAGE_NAME, mDefaultNotificationChannel, mDefaultNotificationChannelSet,
mSbn, null, null, null, true, false, IMPORTANCE_DEFAULT, true);
final TextView textView = mNotificationInfo.findViewById(R.id.channel_name);
assertEquals(GONE, textView.getVisibility());
}
@@ -293,7 +302,8 @@ public class NotificationInfoTest extends SysuiTestCase {
when(mMockINotificationManager.getNumNotificationChannelsForPackage(
eq(TEST_PACKAGE_NAME), eq(TEST_UID), anyBoolean())).thenReturn(10);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mDefaultNotificationChannel, 1, mSbn, null, null, null, true,
TEST_PACKAGE_NAME, mDefaultNotificationChannel, mDefaultNotificationChannelSet,
mSbn, null, null, null, true,
false, IMPORTANCE_DEFAULT, true);
final TextView textView = mNotificationInfo.findViewById(R.id.channel_name);
assertEquals(VISIBLE, textView.getVisibility());
@@ -302,7 +312,8 @@ public class NotificationInfoTest extends SysuiTestCase {
@Test
public void testBindNotification_UnblockablePackageUsesChannelName() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true,
TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, null, null,
null, true, true,
IMPORTANCE_DEFAULT, true);
final TextView textView = mNotificationInfo.findViewById(R.id.channel_name);
assertEquals(VISIBLE, textView.getVisibility());
@@ -311,7 +322,7 @@ public class NotificationInfoTest extends SysuiTestCase {
@Test
public void testBindNotification_BlockLink_BlockingHelper() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, mock(
TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, null, mock(
NotificationInfo.OnSettingsClickListener.class), null, true, false,
true /* isBlockingHelper */, IMPORTANCE_DEFAULT, true);
final View block =
@@ -326,7 +337,7 @@ public class NotificationInfoTest extends SysuiTestCase {
public void testBindNotification_SetsOnClickListenerForSettings() throws Exception {
final CountDownLatch latch = new CountDownLatch(1);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null,
TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, null,
(View v, NotificationChannel c, int appUid) -> {
assertEquals(mNotificationChannel, c);
latch.countDown();
@@ -341,7 +352,8 @@ public class NotificationInfoTest extends SysuiTestCase {
@Test
public void testBindNotification_SettingsButtonInvisibleWhenNoClickListener() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, null, null,
null, true, false,
IMPORTANCE_DEFAULT, true);
final View settingsButton = mNotificationInfo.findViewById(R.id.info);
assertTrue(settingsButton.getVisibility() != View.VISIBLE);
@@ -351,7 +363,7 @@ public class NotificationInfoTest extends SysuiTestCase {
public void testBindNotification_SettingsButtonInvisibleWhenDeviceUnprovisioned()
throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null,
TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, null,
(View v, NotificationChannel c, int appUid) -> {
assertEquals(mNotificationChannel, c);
}, null, false, false, IMPORTANCE_DEFAULT, true);
@@ -362,10 +374,11 @@ public class NotificationInfoTest extends SysuiTestCase {
@Test
public void testBindNotification_SettingsButtonReappearsAfterSecondBind() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, null, null,
null, true, false,
IMPORTANCE_DEFAULT, true);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null,
TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, null,
(View v, NotificationChannel c, int appUid) -> {
}, null, true, false, IMPORTANCE_DEFAULT, true);
final View settingsButton = mNotificationInfo.findViewById(R.id.info);
@@ -375,7 +388,7 @@ public class NotificationInfoTest extends SysuiTestCase {
@Test
public void testBindNotificationLogging_notBlockingHelper() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn,
TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn,
null, null, null,
true, false,
IMPORTANCE_DEFAULT, true);
@@ -389,7 +402,7 @@ public class NotificationInfoTest extends SysuiTestCase {
@Test
public void testBindNotificationLogging_BlockingHelper() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn,
TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn,
null, null, null,
false, true,
true,
@@ -404,7 +417,7 @@ public class NotificationInfoTest extends SysuiTestCase {
@Test
public void testLogBlockingHelperCounter_logsForBlockingHelper() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn,
TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn,
null, null, null,
false, true,
true,
@@ -417,7 +430,8 @@ public class NotificationInfoTest extends SysuiTestCase {
public void testOnClickListenerPassesNullChannelForBundle() throws Exception {
final CountDownLatch latch = new CountDownLatch(1);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, MULTIPLE_CHANNEL_COUNT, mSbn, null,
TEST_PACKAGE_NAME, mNotificationChannel,
createMultipleChannelSet(MULTIPLE_CHANNEL_COUNT), mSbn, null,
(View v, NotificationChannel c, int appUid) -> {
assertEquals(null, c);
latch.countDown();
@@ -433,7 +447,8 @@ public class NotificationInfoTest extends SysuiTestCase {
public void testBindNotification_ChannelNameInvisibleWhenBundleFromDifferentChannels()
throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, MULTIPLE_CHANNEL_COUNT, mSbn, null, null,
TEST_PACKAGE_NAME, mNotificationChannel,
createMultipleChannelSet(MULTIPLE_CHANNEL_COUNT), mSbn, null, null,
null, true, false, IMPORTANCE_DEFAULT, true);
final TextView channelNameView =
mNotificationInfo.findViewById(R.id.channel_name);
@@ -444,7 +459,8 @@ public class NotificationInfoTest extends SysuiTestCase {
@UiThreadTest
public void testStopInvisibleIfBundleFromDifferentChannels() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, MULTIPLE_CHANNEL_COUNT, mSbn, null, null,
TEST_PACKAGE_NAME, mNotificationChannel,
createMultipleChannelSet(MULTIPLE_CHANNEL_COUNT), mSbn, null, null,
null, true, false, IMPORTANCE_DEFAULT, true);
assertEquals(GONE, mNotificationInfo.findViewById(
R.id.interruptiveness_settings).getVisibility());
@@ -455,7 +471,8 @@ public class NotificationInfoTest extends SysuiTestCase {
@Test
public void testBindNotification_whenAppUnblockable() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true,
TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, null, null,
null, true, true,
IMPORTANCE_DEFAULT, true);
final TextView view = mNotificationInfo.findViewById(R.id.non_configurable_text);
assertEquals(View.VISIBLE, view.getVisibility());
@@ -468,7 +485,8 @@ public class NotificationInfoTest extends SysuiTestCase {
@Test
public void testBindNotification_DoesNotUpdateNotificationChannel() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, null, null,
null, true, false,
IMPORTANCE_DEFAULT, true);
mTestableLooper.processAllMessages();
verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
@@ -479,7 +497,8 @@ public class NotificationInfoTest extends SysuiTestCase {
public void testDoesNotUpdateNotificationChannelAfterImportanceChanged() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, null, null,
null, true, false,
IMPORTANCE_LOW, false);
mNotificationInfo.findViewById(R.id.alert).performClick();
@@ -493,7 +512,8 @@ public class NotificationInfoTest extends SysuiTestCase {
throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_DEFAULT);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, null, null,
null, true, false,
IMPORTANCE_DEFAULT, true);
mNotificationInfo.findViewById(R.id.silence).performClick();
@@ -507,7 +527,8 @@ public class NotificationInfoTest extends SysuiTestCase {
throws Exception {
int originalImportance = mNotificationChannel.getImportance();
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, null, null,
null, true, false,
IMPORTANCE_DEFAULT, true);
mNotificationInfo.handleCloseControls(true, false);
@@ -522,7 +543,8 @@ public class NotificationInfoTest extends SysuiTestCase {
throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_UNSPECIFIED);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, null, null,
null, true, false,
IMPORTANCE_UNSPECIFIED, true);
mNotificationInfo.handleCloseControls(true, false);
@@ -541,7 +563,8 @@ public class NotificationInfoTest extends SysuiTestCase {
mNotificationChannel.setImportance(IMPORTANCE_DEFAULT);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel /* notificationChannel */,
10 /* numUniqueChannelsInRow */, mSbn, listener /* checkSaveListener */,
createMultipleChannelSet(10) /* numUniqueChannelsInRow */, mSbn,
listener /* checkSaveListener */,
null /* onSettingsClick */, null /* onAppSettingsClick */, true /* provisioned */,
false /* isNonblockable */, true /* isForBlockingHelper */,
IMPORTANCE_DEFAULT, true);
@@ -570,7 +593,8 @@ public class NotificationInfoTest extends SysuiTestCase {
mNotificationChannel.setImportance(IMPORTANCE_DEFAULT);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel /* notificationChannel */,
10 /* numUniqueChannelsInRow */, mSbn, listener /* checkSaveListener */,
createMultipleChannelSet(10) /* numUniqueChannelsInRow */, mSbn,
listener /* checkSaveListener */,
null /* onSettingsClick */, null /* onAppSettingsClick */,
false /* isNonblockable */, true /* isForBlockingHelper */,
true, IMPORTANCE_DEFAULT, true);
@@ -589,7 +613,8 @@ public class NotificationInfoTest extends SysuiTestCase {
mNotificationChannel.setImportance(IMPORTANCE_DEFAULT);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel /* notificationChannel */,
10 /* numUniqueChannelsInRow */, mSbn, listener /* checkSaveListener */,
createMultipleChannelSet(10) /* numUniqueChannelsInRow */, mSbn,
listener /* checkSaveListener */,
null /* onSettingsClick */, null /* onAppSettingsClick */,
true /* provisioned */,
false /* isNonblockable */, true /* isForBlockingHelper */,
@@ -608,7 +633,7 @@ public class NotificationInfoTest extends SysuiTestCase {
mMockINotificationManager,
TEST_PACKAGE_NAME,
mNotificationChannel,
1 /* numChannels */,
mNotificationChannelSet /* numChannels */,
mSbn,
null /* checkSaveListener */,
null /* onSettingsClick */,
@@ -635,7 +660,7 @@ public class NotificationInfoTest extends SysuiTestCase {
mMockINotificationManager,
TEST_PACKAGE_NAME,
mNotificationChannel,
1 /* numChannels */,
mNotificationChannelSet /* numChannels */,
mSbn,
null /* checkSaveListener */,
null /* onSettingsClick */,
@@ -664,7 +689,8 @@ public class NotificationInfoTest extends SysuiTestCase {
public void testKeepUpdatesNotificationChannel_blockingHelper() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true,
TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, null, null,
null, true, true,
IMPORTANCE_LOW, false);
mNotificationInfo.findViewById(R.id.keep_showing).performClick();
@@ -683,7 +709,8 @@ public class NotificationInfoTest extends SysuiTestCase {
public void testNoActionsUpdatesNotificationChannel_blockingHelper() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_DEFAULT);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true,
TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, null, null,
null, true, true,
IMPORTANCE_DEFAULT, true);
mNotificationInfo.handleCloseControls(true, false);
@@ -701,7 +728,8 @@ public class NotificationInfoTest extends SysuiTestCase {
public void testSilenceCallsUpdateNotificationChannel() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_DEFAULT);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, null, null,
null, true, false,
IMPORTANCE_DEFAULT, true);
mNotificationInfo.findViewById(R.id.silence).performClick();
@@ -722,7 +750,8 @@ public class NotificationInfoTest extends SysuiTestCase {
public void testUnSilenceCallsUpdateNotificationChannel() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, null, null,
null, true, false,
IMPORTANCE_LOW, false);
mNotificationInfo.findViewById(R.id.alert).performClick();
@@ -744,7 +773,8 @@ public class NotificationInfoTest extends SysuiTestCase {
throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_UNSPECIFIED);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, null, null,
null, true, false,
IMPORTANCE_UNSPECIFIED, true);
mNotificationInfo.findViewById(R.id.silence).performClick();
@@ -766,7 +796,8 @@ public class NotificationInfoTest extends SysuiTestCase {
throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_MIN);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, null, null,
null, true, false,
IMPORTANCE_MIN, false);
assertEquals(mContext.getString(R.string.inline_done_button),
@@ -782,7 +813,7 @@ public class NotificationInfoTest extends SysuiTestCase {
ArgumentCaptor.forClass(NotificationChannel.class);
verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
anyString(), eq(TEST_UID), updated.capture());
assertTrue((updated.getValue().getUserLockedFields()& USER_LOCKED_IMPORTANCE) != 0);
assertTrue((updated.getValue().getUserLockedFields() & USER_LOCKED_IMPORTANCE) != 0);
assertEquals(IMPORTANCE_MIN, updated.getValue().getImportance());
}
@@ -791,7 +822,8 @@ public class NotificationInfoTest extends SysuiTestCase {
throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_MIN);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, null, null,
null, true, false,
IMPORTANCE_MIN, false);
assertEquals(mContext.getString(R.string.inline_done_button),
@@ -807,7 +839,7 @@ public class NotificationInfoTest extends SysuiTestCase {
ArgumentCaptor.forClass(NotificationChannel.class);
verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
anyString(), eq(TEST_UID), updated.capture());
assertTrue((updated.getValue().getUserLockedFields()& USER_LOCKED_IMPORTANCE) != 0);
assertTrue((updated.getValue().getUserLockedFields() & USER_LOCKED_IMPORTANCE) != 0);
assertEquals(IMPORTANCE_DEFAULT, updated.getValue().getImportance());
}
@@ -816,7 +848,8 @@ public class NotificationInfoTest extends SysuiTestCase {
throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, null, null,
null, true, false,
IMPORTANCE_LOW, false);
assertEquals(mContext.getString(R.string.inline_done_button),
@@ -834,7 +867,8 @@ public class NotificationInfoTest extends SysuiTestCase {
throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, null, null,
null, true, false,
IMPORTANCE_LOW, false);
mNotificationInfo.findViewById(R.id.alert).performClick();
@@ -855,7 +889,8 @@ public class NotificationInfoTest extends SysuiTestCase {
public void testCloseControlsDoesNotUpdateIfSaveIsFalse() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn, null, null,
null, true, false,
IMPORTANCE_LOW, false);
mNotificationInfo.findViewById(R.id.alert).performClick();
@@ -871,7 +906,7 @@ public class NotificationInfoTest extends SysuiTestCase {
public void testCloseControlsUpdatesWhenCheckSaveListenerUsesCallback() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn,
TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn,
(Runnable saveImportance, StatusBarNotification sbn) -> {
saveImportance.run();
}, null, null, true, false, IMPORTANCE_LOW, false
@@ -894,7 +929,7 @@ public class NotificationInfoTest extends SysuiTestCase {
public void testCloseControls_withoutHittingApply() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn,
TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn,
(Runnable saveImportance, StatusBarNotification sbn) -> {
saveImportance.run();
}, null, null, true, false, IMPORTANCE_LOW, false
@@ -910,7 +945,7 @@ public class NotificationInfoTest extends SysuiTestCase {
assertFalse(mNotificationInfo.willBeRemoved());
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn,
TEST_PACKAGE_NAME, mNotificationChannel, mNotificationChannelSet, mSbn,
(Runnable saveImportance, StatusBarNotification sbn) -> {
saveImportance.run();
}, null, null, true, false, IMPORTANCE_LOW, false
@@ -918,4 +953,21 @@ public class NotificationInfoTest extends SysuiTestCase {
assertFalse(mNotificationInfo.willBeRemoved());
}
private Set<NotificationChannel> createMultipleChannelSet(int howMany) {
Set<NotificationChannel> multiChannelSet = new HashSet<>();
for (int i = 0; i < howMany; i++) {
if (i == 0) {
multiChannelSet.add(mNotificationChannel);
continue;
}
NotificationChannel channel = new NotificationChannel(
TEST_CHANNEL, TEST_CHANNEL_NAME + i, IMPORTANCE_LOW);
multiChannelSet.add(channel);
}
return multiChannelSet;
}
}

View File

@@ -121,8 +121,6 @@ import android.app.backup.BackupManager;
import android.app.role.OnRoleHoldersChangedListener;
import android.app.role.RoleManager;
import android.app.usage.UsageEvents;
import android.app.usage.UsageStats;
import android.app.usage.UsageStatsManager;
import android.app.usage.UsageStatsManagerInternal;
import android.companion.ICompanionDeviceManager;
import android.content.BroadcastReceiver;
@@ -183,7 +181,6 @@ import android.service.notification.NotificationRankingUpdate;
import android.service.notification.NotificationRecordProto;
import android.service.notification.NotificationServiceDumpProto;
import android.service.notification.NotificationStats;
import android.service.notification.NotifyingApp;
import android.service.notification.SnoozeCriterion;
import android.service.notification.StatusBarNotification;
import android.service.notification.ZenModeConfig;
@@ -260,8 +257,6 @@ import java.nio.charset.StandardCharsets;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
@@ -2467,7 +2462,8 @@ public class NotificationManagerService extends SystemService {
*/
@Override
public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
checkCallerIsSystemOrSameApp(pkg);
enforceSystemOrSystemUIOrSamePackage(pkg,
"Caller not system or systemui or same package");
if (UserHandle.getCallingUserId() != UserHandle.getUserId(uid)) {
getContext().enforceCallingPermission(
android.Manifest.permission.INTERACT_ACROSS_USERS,
@@ -2793,7 +2789,7 @@ public class NotificationManagerService extends SystemService {
@Override
public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroupsForPackage(
String pkg, int uid, boolean includeDeleted) {
checkCallerIsSystem();
enforceSystemOrSystemUI("getNotificationChannelGroupsForPackage");
return mPreferencesHelper.getNotificationChannelGroups(
pkg, uid, includeDeleted, true, false);
}