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:
126
packages/SystemUI/res/layout/notif_half_shelf.xml
Normal file
126
packages/SystemUI/res/layout/notif_half_shelf.xml
Normal 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>
|
||||
78
packages/SystemUI/res/layout/notif_half_shelf_row.xml
Normal file
78
packages/SystemUI/res/layout/notif_half_shelf_row.xml
Normal 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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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] -->
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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() {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -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),
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user