Merge "Inline noti blocking is now in the form of a question"

This commit is contained in:
TreeHugger Robot
2018-01-10 23:49:14 +00:00
committed by Android (Google) Code Review
9 changed files with 547 additions and 800 deletions

View File

@@ -193,10 +193,10 @@
<dimen name="notification_header_background_height">49.5dp</dimen>
<!-- The top padding for the notification header -->
<dimen name="notification_header_padding_top">14dp</dimen>
<dimen name="notification_header_padding_top">16dp</dimen>
<!-- The bottom padding for the notification header -->
<dimen name="notification_header_padding_bottom">13dp</dimen>
<dimen name="notification_header_padding_bottom">16dp</dimen>
<!-- The margin at the bottom of the notification header. -->
<dimen name="notification_header_margin_bottom">5dp</dimen>

View File

@@ -0,0 +1,25 @@
<!--
Copyright (C) 2018 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
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="48.0"
android:viewportHeight="48.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M22,34h4L26,22h-4v12zM24,4C12.95,4 4,12.95 4,24s8.95,20 20,20 20,-8.95 20,-20S35.05,4 24,4zM24,40c-8.82,0 -16,-7.18 -16,-16S15.18,8 24,8s16,7.18 16,16 -7.18,16 -16,16zM22,18h4v-4h-4v4z"/>
</vector>

View File

@@ -23,23 +23,22 @@
android:clickable="true"
android:orientation="vertical"
android:paddingStart="@*android:dimen/notification_content_margin_start"
android:paddingEnd="@*android:dimen/notification_content_margin_end"
android:background="@color/notification_guts_bg_color"
android:theme="@*android:style/Theme.DeviceDefault.Light">
<!-- Package Info -->
<LinearLayout
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="@*android:dimen/notification_header_height"
android:layout_height="@dimen/notification_guts_header_height"
android:clipChildren="false"
android:paddingTop="@*android:dimen/notification_header_padding_top"
android:paddingBottom="@*android:dimen/notification_header_padding_bottom"
android:gravity="center_vertical"
android:orientation="horizontal" >
android:clipToPadding="false"
android:layout_marginTop="@*android:dimen/notification_header_padding_top" >
<ImageView
android:id="@+id/pkgicon"
android:layout_width="@*android:dimen/notification_header_icon_size"
android:layout_height="@*android:dimen/notification_header_icon_size"
android:layout_marginEnd="3dp"/>
android:layout_width="@dimen/notification_guts_header_height"
android:layout_height="@dimen/notification_guts_header_height"
android:layout_marginEnd="3dp" />
<TextView
android:id="@+id/pkgname"
android:layout_width="wrap_content"
@@ -47,7 +46,9 @@
android:textAppearance="@*android:style/TextAppearance.Material.Notification.Info"
android:layout_marginStart="3dp"
android:layout_marginEnd="2dp"
android:singleLine="true"/>
android:singleLine="true"
android:layout_centerVertical="true"
android:layout_toEndOf="@id/pkgicon" />
<TextView
android:id="@+id/pkg_group_divider"
android:layout_width="wrap_content"
@@ -55,7 +56,9 @@
android:textAppearance="@*android:style/TextAppearance.Material.Notification.Info"
android:layout_marginStart="2dp"
android:layout_marginEnd="2dp"
android:text="@*android:string/notification_header_divider_symbol"/>
android:text="@*android:string/notification_header_divider_symbol"
android:layout_centerVertical="true"
android:layout_toEndOf="@id/pkgname" />
<TextView
android:id="@+id/group_name"
android:layout_width="wrap_content"
@@ -64,82 +67,103 @@
android:layout_marginStart="2dp"
android:layout_marginEnd="2dp"
android:ellipsize="end"
android:maxLines="1"/>
</LinearLayout>
android:maxLines="1"
android:layout_centerVertical="true"
android:layout_toEndOf="@id/pkg_group_divider" />
<ImageButton
android:id="@+id/info"
android:src="@drawable/ic_info"
android:tint="?android:attr/colorAccent"
android:layout_width="@dimen/notification_guts_header_height"
android:layout_height="@dimen/notification_guts_header_height"
android:contentDescription="@string/notification_more_settings"
android:background="@drawable/ripple_drawable"
android:layout_alignParentEnd="true" />
</RelativeLayout>
<!-- Channel Info Block -->
<LinearLayout
android:id="@+id/prompt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="20dp"
android:layout_marginEnd="@*android:dimen/notification_content_margin_end"
android:layout_marginBottom="@dimen/notification_guts_button_spacing"
android:layout_marginTop="@*android:dimen/notification_header_padding_top"
android:orientation="vertical">
<!-- Channel Text -->
<!-- Channel Info Block -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
android:orientation="vertical">
<!-- Channel Name -->
<TextView
android:id="@+id/channel_name"
android:layout_width="0dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginBottom="6dp"
style="@style/TextAppearance.NotificationInfo.Primary" />
<!-- Ban Channel Switch -->
<Switch
android:id="@+id/channel_enabled_switch"
<!-- Question prompt -->
<TextView
android:id="@+id/block_prompt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|center_vertical"
android:contentDescription="@string/notification_channel_switch_accessibility"
android:background="@null" />
style="@style/TextAppearance.NotificationInfo.Secondary" />
</LinearLayout>
<!-- Secondary Text - only one shows at a time -->
<TextView
android:id="@+id/channel_disabled"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/notification_channel_disabled"
style="@style/TextAppearance.NotificationInfo.Secondary.Warning" />
<TextView
android:id="@+id/num_channels_desc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/notification_channel_disabled"
style="@style/TextAppearance.NotificationInfo.Secondary" />
<!-- Optional link to app. Only appears if the channel is not disabled -->
<TextView
android:id="@+id/app_settings"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
android:ellipsize="end"
android:maxLines="1"
style="@style/TextAppearance.NotificationInfo.Secondary.Link"/>
</LinearLayout>
<!-- Settings and Done buttons -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="48dp"
android:orientation="horizontal"
android:gravity="end"
android:layout_marginEnd="@*android:dimen/notification_content_margin_end"
android:layout_marginBottom="8dp" >
<TextView
android:id="@+id/more_settings"
android:text="@string/notification_more_settings"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginEnd="8dp"
style="@style/TextAppearance.NotificationInfo.Button"/>
<TextView
android:id="@+id/done"
android:text="@string/notification_done"
android:layout_width="wrap_content"
android:layout_height="match_parent"
style="@style/TextAppearance.NotificationInfo.Button"/>
<!-- Settings and Done buttons -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="@dimen/notification_guts_button_spacing"
android:gravity="end" >
<!-- Optional link to app. Only appears if the channel is not disabled and the app
asked for it -->
<TextView
android:id="@+id/app_settings"
android:text="@string/notification_app_settings"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
android:ellipsize="end"
android:maxLines="1"
style="@style/TextAppearance.NotificationInfo.Button"/>
<TextView
android:id="@+id/block"
android:text="@string/inline_stop_button"
android:layout_width="wrap_content"
android:layout_height="match_parent"
style="@style/TextAppearance.NotificationInfo.Button"/>
<TextView
android:id="@+id/keep"
android:text="@string/inline_keep_button"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginEnd="-8dp"
style="@style/TextAppearance.NotificationInfo.Button"/>
</LinearLayout>
</LinearLayout>
<RelativeLayout
android:id="@+id/confirmation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/notification_guts_button_spacing"
android:layout_marginTop="@*android:dimen/notification_header_padding_top"
android:visibility="gone"
android:orientation="horizontal" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/notification_channel_disabled"
style="@style/TextAppearance.NotificationInfo.Secondary.Warning"/>
<TextView
android:id="@+id/undo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/inline_undo"
android:layout_alignParentEnd="true"
android:layout_marginEnd="-8dp"
style="@style/TextAppearance.NotificationInfo.Button"/>
</RelativeLayout>
</com.android.systemui.statusbar.NotificationInfo>

View File

@@ -148,6 +148,12 @@
<!-- The space around a notification menu item -->
<dimen name="notification_menu_icon_padding">20dp</dimen>
<!-- The veritical space around the buttons in the inline settings -->
<dimen name="notification_guts_button_spacing">20dp</dimen>
<!-- The height of the header in inline settings -->
<dimen name="notification_guts_header_height">24dp</dimen>
<!-- The minimum height for the snackbar shown after the snooze option has been chosen. -->
<dimen name="snooze_snackbar_min_height">56dp</dimen>

View File

@@ -1445,38 +1445,22 @@
<string name="notification_header_default_channel">Notifications</string>
<!-- Notification Inline Controls: Shown when a channel's notifications are currently blocked -->
<string name="notification_channel_disabled">You won\'t get these notifications anymore</string>
<string name="notification_channel_disabled">You won\'t see these notifications anymore</string>
<!-- Notification: Control panel: Label that shows how many channels are included in this bundle
of notifications. Replaces the channel name and only appears when there is more than one channel. -->
<string name="notification_num_channels"> <xliff:g id="number">%d</xliff:g> notification categories</string>
<!-- Notification Inline controls: continue receiving notifications prompt, channel level -->
<string name="inline_keep_showing">Keep showing these notifications?</string>
<!-- Notification: Control panel: Label that shows when an app has not upgraded to use channels.
Hints that the user's only option is to block all of the app's notifications. -->
<string name="notification_default_channel_desc">This app doesn\'t have notification categories</string>
<!-- Notification inline controls: block notifications button -->
<string name="inline_stop_button">Stop notifications</string>
<!-- Notification inline controls: keep getting notifications button -->
<string name="inline_keep_button">Keep showing</string>
<!-- Notification Inline controls: continue receiving notifications prompt, app level -->
<string name="inline_keep_showing_app">Keep showing notifications from this app?</string>
<!-- Notification: Control panel: Label that displays when the app's notifications cannot be blocked. -->
<string name="notification_unblockable_desc">Notifications from this app can\'t be turned off</string>
<!-- Notification: Control panel: Label that shows how many channels this application has
defined, describing the current notification channel as "1 out of n notification categories from this app". -->
<plurals name="notification_num_channels_desc">
<item quantity="one">1 out of <xliff:g id="number">%s</xliff:g> notification category from this app</item>
<item quantity="other">1 out of <xliff:g id="number">%s</xliff:g> notification categories from this app</item>
</plurals>
<!-- Notification: Control panel: For bundles of notifications, this label that lists the
channels used by the contained notifications. The first two channels are listed by name,
followed by "and N others"
Example: "Friend requests, Friend confirmations"
Example: "Friend requests, Friend confirmations, and 1 other"
Example: "Friend requests, Friend confirmations, and 2 others"
-->
<string name="notification_channels_list_desc_2"><xliff:g id="channel_name_1">%1$s</xliff:g>, <xliff:g id="channel_name_2">%2$s</xliff:g></string>
<plurals name="notification_channels_list_desc_2_and_others">
<item quantity="one"><xliff:g id="channel_name_1">%1$s</xliff:g>, <xliff:g id="channel_name_2">%2$s</xliff:g>, and <xliff:g id="number">%3$d</xliff:g> other</item>
<item quantity="other"><xliff:g id="channel_name_1">%1$s</xliff:g>, <xliff:g id="channel_name_2">%2$s</xliff:g>, and <xliff:g id="number">%3$d</xliff:g> others</item>
</plurals>
<string name="notification_unblockable_desc">These notifications can\'t be turned off</string>
<!-- Notification: Control panel: Accessibility description for expanded inline controls view, used
to control settings about notifications related to the current notification. -->
@@ -1487,17 +1471,16 @@
<!-- Notification: Control panel: Accessibility description for switch that is used to enable
or disable notifications from this channel -->
<string name="notification_channel_switch_accessibility">Allow notifications from this channel</string>
<!-- Notification: Control panel: Label for button that launches notification settings. Used
when this app has defined more than a single channel for notifications. -->
<string name="notification_all_categories">All Categories</string>
<!-- Notification: Control panel: Label for button that launches notification settings. Used
when this app has only defined a single channel for notifications. -->
<string name="notification_more_settings">More settings</string>
<!-- Notification: Control panel: Label for a link that launches notification settings in the
app that sent the notification. -->
<string name="notification_app_settings">Customize: <xliff:g id="sub_category" example="Work chats">%1$s</xliff:g></string>
<string name="notification_app_settings">Customize</string>
<!-- Notification: Control panel: Label for button that dismisses control panel. [CHAR LIMIT=NONE] -->
<string name="notification_done">Done</string>
<!-- Notification: inline controls: undo block button -->
<string name="inline_undo">Undo</string>
<!-- Notification: Menu row: Content description for menu items. [CHAR LIMIT=NONE] -->
<string name="notification_menu_accessibility"><xliff:g id="app_name" example="YouTube">%1$s</xliff:g> <xliff:g id="menu_description" example="notification controls">%2$s</xliff:g></string>

View File

@@ -229,10 +229,9 @@ public class NotificationGutsManager implements Dumpable {
}
}
try {
info.bindNotification(pmUser, iNotificationManager, pkg, new ArrayList(channels),
row.getEntry().channel.getImportance(), sbn, onSettingsClick,
onAppSettingsClick, onDoneClick, mCheckSaveListener,
mNonBlockablePkgs);
info.bindNotification(pmUser, iNotificationManager, pkg, row.getEntry().channel,
channels.size(), sbn, mCheckSaveListener, onSettingsClick,
onAppSettingsClick, mNonBlockablePkgs);
} catch (RemoteException e) {
Log.e(TAG, e.toString());
}

View File

@@ -18,6 +18,10 @@ package com.android.systemui.statusbar;
import static android.app.NotificationManager.IMPORTANCE_NONE;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.app.INotificationManager;
import android.app.Notification;
import android.app.NotificationChannel;
@@ -38,12 +42,12 @@ import android.view.View;
import android.view.accessibility.AccessibilityEvent;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Switch;
import android.widget.TextView;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settingslib.Utils;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import java.lang.IllegalArgumentException;
@@ -57,25 +61,37 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
private static final String TAG = "InfoGuts";
private INotificationManager mINotificationManager;
private PackageManager mPm;
private String mPkg;
private String mAppName;
private int mAppUid;
private List<NotificationChannel> mNotificationChannels;
private int mNumNotificationChannels;
private NotificationChannel mSingleNotificationChannel;
private boolean mIsSingleDefaultChannel;
private StatusBarNotification mSbn;
private int mStartingUserImportance;
private int mChosenImportance;
private boolean mIsSingleDefaultChannel;
private boolean mNonblockable;
private StatusBarNotification mSbn;
private AnimatorSet mExpandAnimation;
private TextView mNumChannelsView;
private View mChannelDisabledView;
private TextView mSettingsLinkView;
private Switch mChannelEnabledSwitch;
private CheckSaveListener mCheckSaveListener;
private OnSettingsClickListener mOnSettingsClickListener;
private OnAppSettingsClickListener mAppSettingsClickListener;
private PackageManager mPm;
private NotificationGuts mGutsContainer;
private OnClickListener mOnKeepShowing = v -> {
closeControls(v);
};
private OnClickListener mOnStopNotifications = v -> {
swapContent(false);
};
private OnClickListener mOnUndo = v -> {
swapContent(true);
};
public NotificationInfo(Context context, AttributeSet attrs) {
super(context, attrs);
}
@@ -98,141 +114,93 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
public void bindNotification(final PackageManager pm,
final INotificationManager iNotificationManager,
final String pkg,
final List<NotificationChannel> notificationChannels,
int startingUserImportance,
final NotificationChannel notificationChannel,
final int numChannels,
final StatusBarNotification sbn,
OnSettingsClickListener onSettingsClick,
OnAppSettingsClickListener onAppSettingsClick,
OnClickListener onDoneClick,
CheckSaveListener checkSaveListener,
final CheckSaveListener checkSaveListener,
final OnSettingsClickListener onSettingsClick,
final OnAppSettingsClickListener onAppSettingsClick,
final Set<String> nonBlockablePkgs)
throws RemoteException {
mINotificationManager = iNotificationManager;
mPkg = pkg;
mNotificationChannels = notificationChannels;
mCheckSaveListener = checkSaveListener;
mNumNotificationChannels = numChannels;
mSbn = sbn;
mPm = pm;
mAppSettingsClickListener = onAppSettingsClick;
mStartingUserImportance = startingUserImportance;
mAppName = mPkg;
Drawable pkgicon = null;
CharSequence channelNameText = "";
ApplicationInfo info = null;
try {
info = pm.getApplicationInfo(mPkg,
PackageManager.MATCH_UNINSTALLED_PACKAGES
| PackageManager.MATCH_DISABLED_COMPONENTS
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE
| PackageManager.MATCH_DIRECT_BOOT_AWARE);
if (info != null) {
mAppUid = sbn.getUid();
mAppName = String.valueOf(pm.getApplicationLabel(info));
pkgicon = pm.getApplicationIcon(info);
}
} catch (PackageManager.NameNotFoundException e) {
// app is gone, just show package name and generic icon
pkgicon = pm.getDefaultActivityIcon();
}
((ImageView) findViewById(R.id.pkgicon)).setImageDrawable(pkgicon);
mCheckSaveListener = checkSaveListener;
mOnSettingsClickListener = onSettingsClick;
mSingleNotificationChannel = notificationChannel;
mStartingUserImportance = mChosenImportance = mSingleNotificationChannel.getImportance();
int numTotalChannels = iNotificationManager.getNumNotificationChannelsForPackage(
int numTotalChannels = mINotificationManager.getNumNotificationChannelsForPackage(
pkg, mAppUid, false /* includeDeleted */);
if (mNotificationChannels.isEmpty()) {
if (mNumNotificationChannels == 0) {
throw new IllegalArgumentException("bindNotification requires at least one channel");
} else {
if (mNotificationChannels.size() == 1) {
mSingleNotificationChannel = mNotificationChannels.get(0);
// Special behavior for the Default channel if no other channels have been defined.
mIsSingleDefaultChannel =
(mSingleNotificationChannel.getId()
.equals(NotificationChannel.DEFAULT_CHANNEL_ID) &&
numTotalChannels <= 1);
} else {
mSingleNotificationChannel = null;
mIsSingleDefaultChannel = false;
}
// Special behavior for the Default channel if no other channels have been defined.
mIsSingleDefaultChannel = mNumNotificationChannels == 1
&& mSingleNotificationChannel.getId()
.equals(NotificationChannel.DEFAULT_CHANNEL_ID)
&& numTotalChannels <= 1;
}
boolean nonBlockable = false;
try {
final PackageInfo pkgInfo = pm.getPackageInfo(pkg, PackageManager.GET_SIGNATURES);
if (Utils.isSystemPackage(getResources(), pm, pkgInfo)) {
final int numChannels = mNotificationChannels.size();
for (int i = 0; i < numChannels; i++) {
final NotificationChannel notificationChannel = mNotificationChannels.get(i);
// If any of the system channels is not blockable, the bundle is nonblockable
if (!notificationChannel.isBlockableSystem()) {
nonBlockable = true;
break;
}
if (mSingleNotificationChannel != null
&& !mSingleNotificationChannel.isBlockableSystem()) {
mNonblockable = true;
}
}
} catch (PackageManager.NameNotFoundException e) {
// unlikely.
}
if (nonBlockablePkgs != null) {
nonBlockable |= nonBlockablePkgs.contains(pkg);
mNonblockable |= nonBlockablePkgs.contains(pkg);
}
mNonblockable |= (mNumNotificationChannels > 1);
String channelsDescText;
mNumChannelsView = findViewById(R.id.num_channels_desc);
if (nonBlockable) {
channelsDescText = mContext.getString(R.string.notification_unblockable_desc);
} else if (mIsSingleDefaultChannel) {
channelsDescText = mContext.getString(R.string.notification_default_channel_desc);
} else {
switch (mNotificationChannels.size()) {
case 1:
channelsDescText = String.format(mContext.getResources().getQuantityString(
R.plurals.notification_num_channels_desc, numTotalChannels),
numTotalChannels);
break;
case 2:
channelsDescText = mContext.getString(
R.string.notification_channels_list_desc_2,
mNotificationChannels.get(0).getName(),
mNotificationChannels.get(1).getName());
break;
default:
final int numOthers = mNotificationChannels.size() - 2;
channelsDescText = String.format(
mContext.getResources().getQuantityString(
R.plurals.notification_channels_list_desc_2_and_others,
numOthers),
mNotificationChannels.get(0).getName(),
mNotificationChannels.get(1).getName(),
numOthers);
bindHeader();
bindPrompt();
bindButtons();
}
private void bindHeader() throws RemoteException {
// Package name
Drawable pkgicon = null;
ApplicationInfo info;
try {
info = mPm.getApplicationInfo(mPkg,
PackageManager.MATCH_UNINSTALLED_PACKAGES
| PackageManager.MATCH_DISABLED_COMPONENTS
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE
| PackageManager.MATCH_DIRECT_BOOT_AWARE);
if (info != null) {
mAppUid = mSbn.getUid();
mAppName = String.valueOf(mPm.getApplicationLabel(info));
pkgicon = mPm.getApplicationIcon(info);
}
} catch (PackageManager.NameNotFoundException e) {
// app is gone, just show package name and generic icon
pkgicon = mPm.getDefaultActivityIcon();
}
mNumChannelsView.setText(channelsDescText);
if (mSingleNotificationChannel == null) {
// Multiple channels don't use a channel name for the title.
channelNameText = mContext.getString(R.string.notification_num_channels,
mNotificationChannels.size());
} else if (mIsSingleDefaultChannel || nonBlockable) {
// If this is the default channel or the app is unblockable,
// don't use our channel-specific text.
channelNameText = mContext.getString(R.string.notification_header_default_channel);
} else {
channelNameText = mSingleNotificationChannel.getName();
}
((ImageView) findViewById(R.id.pkgicon)).setImageDrawable(pkgicon);
((TextView) findViewById(R.id.pkgname)).setText(mAppName);
((TextView) findViewById(R.id.channel_name)).setText(channelNameText);
// Set group information if this channel has an associated group.
CharSequence groupName = null;
if (mSingleNotificationChannel != null && mSingleNotificationChannel.getGroup() != null) {
final NotificationChannelGroup notificationChannelGroup =
iNotificationManager.getNotificationChannelGroupForPackage(
mSingleNotificationChannel.getGroup(), pkg, mAppUid);
mINotificationManager.getNotificationChannelGroupForPackage(
mSingleNotificationChannel.getGroup(), mPkg, mAppUid);
if (notificationChannelGroup != null) {
groupName = notificationChannelGroup.getName();
}
}
TextView groupNameView = ((TextView) findViewById(R.id.group_name));
TextView groupDividerView = ((TextView) findViewById(R.id.pkg_group_divider));
TextView groupNameView = findViewById(R.id.group_name);
TextView groupDividerView = findViewById(R.id.pkg_group_divider);
if (groupName != null) {
groupNameView.setText(groupName);
groupNameView.setVisibility(View.VISIBLE);
@@ -242,53 +210,55 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
groupDividerView.setVisibility(View.GONE);
}
bindButtons(nonBlockable);
// Top-level importance group
mChannelDisabledView = findViewById(R.id.channel_disabled);
updateSecondaryText();
// Settings button.
final TextView settingsButton = (TextView) findViewById(R.id.more_settings);
if (mAppUid >= 0 && onSettingsClick != null) {
final View settingsButton = findViewById(R.id.info);
if (mAppUid >= 0 && mOnSettingsClickListener != null) {
settingsButton.setVisibility(View.VISIBLE);
final int appUidF = mAppUid;
settingsButton.setOnClickListener(
(View view) -> {
onSettingsClick.onClick(view, mSingleNotificationChannel, appUidF);
mOnSettingsClickListener.onClick(view,
mNumNotificationChannels > 1 ? null : mSingleNotificationChannel,
appUidF);
});
if (numTotalChannels <= 1 || nonBlockable) {
settingsButton.setText(R.string.notification_more_settings);
} else {
settingsButton.setText(R.string.notification_all_categories);
}
} else {
settingsButton.setVisibility(View.GONE);
}
}
// Done button.
final TextView doneButton = (TextView) findViewById(R.id.done);
doneButton.setText(R.string.notification_done);
doneButton.setOnClickListener(onDoneClick);
private void bindPrompt() {
final TextView channelName = findViewById(R.id.channel_name);
final TextView blockPrompt = findViewById(R.id.block_prompt);
if (mNonblockable) {
if (mIsSingleDefaultChannel || mNumNotificationChannels > 1) {
channelName.setVisibility(View.GONE);
} else {
channelName.setText(mSingleNotificationChannel.getName());
}
// Optional settings link
updateAppSettingsLink();
blockPrompt.setText(R.string.notification_unblockable_desc);
} else {
if (mIsSingleDefaultChannel || mNumNotificationChannels > 1) {
channelName.setVisibility(View.GONE);
blockPrompt.setText(R.string.inline_keep_showing_app);
} else {
channelName.setText(mSingleNotificationChannel.getName());
blockPrompt.setText(R.string.inline_keep_showing);
}
}
}
private boolean hasImportanceChanged() {
return mSingleNotificationChannel != null &&
mChannelEnabledSwitch != null &&
mStartingUserImportance != getSelectedImportance();
return mSingleNotificationChannel != null && mStartingUserImportance != mChosenImportance;
}
private void saveImportance() {
if (!hasImportanceChanged()) {
if (mNonblockable || !hasImportanceChanged()) {
return;
}
final int selectedImportance = getSelectedImportance();
MetricsLogger.action(mContext, MetricsEvent.ACTION_SAVE_IMPORTANCE,
selectedImportance - mStartingUserImportance);
mSingleNotificationChannel.setImportance(selectedImportance);
mChosenImportance - mStartingUserImportance);
mSingleNotificationChannel.setImportance(mChosenImportance);
mSingleNotificationChannel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
try {
mINotificationManager.updateNotificationChannelForPackage(
@@ -298,30 +268,78 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
}
}
private int getSelectedImportance() {
if (!mChannelEnabledSwitch.isChecked()) {
return IMPORTANCE_NONE;
private void bindButtons() {
View block = findViewById(R.id.block);
block.setOnClickListener(mOnStopNotifications);
TextView keep = findViewById(R.id.keep);
keep.setOnClickListener(mOnKeepShowing);
findViewById(R.id.undo).setOnClickListener(mOnUndo);
if (mNonblockable) {
keep.setText(R.string.notification_done);
block.setVisibility(GONE);
}
// app settings link
TextView settingsLinkView = findViewById(R.id.app_settings);
Intent settingsIntent = getAppSettingsIntent(mPm, mPkg, mSingleNotificationChannel,
mSbn.getId(), mSbn.getTag());
if (settingsIntent != null
&& !TextUtils.isEmpty(mSbn.getNotification().getSettingsText())) {
settingsLinkView.setVisibility(View.VISIBLE);
settingsLinkView.setText(mContext.getString(R.string.notification_app_settings,
mSbn.getNotification().getSettingsText()));
settingsLinkView.setOnClickListener((View view) -> {
mAppSettingsClickListener.onClick(view, settingsIntent);
});
} else {
return mStartingUserImportance;
settingsLinkView.setVisibility(View.GONE);
}
}
private void bindButtons(final boolean nonBlockable) {
// Enabled Switch
mChannelEnabledSwitch = (Switch) findViewById(R.id.channel_enabled_switch);
mChannelEnabledSwitch.setChecked(
mStartingUserImportance != IMPORTANCE_NONE);
final boolean visible = !nonBlockable && mSingleNotificationChannel != null;
mChannelEnabledSwitch.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
private void swapContent(boolean showPrompt) {
if (mExpandAnimation != null) {
mExpandAnimation.cancel();
}
// Callback when checked.
mChannelEnabledSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> {
if (mGutsContainer != null) {
mGutsContainer.resetFalsingCheck();
if (showPrompt) {
mChosenImportance = mStartingUserImportance;
} else {
mChosenImportance = IMPORTANCE_NONE;
}
View prompt = findViewById(R.id.prompt);
View confirmation = findViewById(R.id.confirmation);
ObjectAnimator promptAnim = ObjectAnimator.ofFloat(prompt, View.ALPHA,
prompt.getAlpha(), showPrompt ? 1f : 0f);
promptAnim.setInterpolator(showPrompt ? Interpolators.ALPHA_IN : Interpolators.ALPHA_OUT);
ObjectAnimator confirmAnim = ObjectAnimator.ofFloat(confirmation, View.ALPHA,
confirmation.getAlpha(), showPrompt ? 0f : 1f);
confirmAnim.setInterpolator(showPrompt ? Interpolators.ALPHA_OUT : Interpolators.ALPHA_IN);
prompt.setVisibility(showPrompt ? VISIBLE : GONE);
confirmation.setVisibility(showPrompt ? GONE : VISIBLE);
mExpandAnimation = new AnimatorSet();
mExpandAnimation.playTogether(promptAnim, confirmAnim);
mExpandAnimation.setDuration(150);
mExpandAnimation.addListener(new AnimatorListenerAdapter() {
boolean cancelled = false;
@Override
public void onAnimationCancel(Animator animation) {
cancelled = true;
}
@Override
public void onAnimationEnd(Animator animation) {
if (!cancelled) {
prompt.setVisibility(showPrompt ? VISIBLE : GONE);
confirmation.setVisibility(showPrompt ? GONE : VISIBLE);
}
}
updateSecondaryText();
updateAppSettingsLink();
});
mExpandAnimation.start();
}
@Override
@@ -339,35 +357,6 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
}
}
private void updateSecondaryText() {
final boolean disabled = mSingleNotificationChannel != null &&
getSelectedImportance() == IMPORTANCE_NONE;
if (disabled) {
mChannelDisabledView.setVisibility(View.VISIBLE);
mNumChannelsView.setVisibility(View.GONE);
} else {
mChannelDisabledView.setVisibility(View.GONE);
mNumChannelsView.setVisibility(mIsSingleDefaultChannel ? View.INVISIBLE : View.VISIBLE);
}
}
private void updateAppSettingsLink() {
mSettingsLinkView = findViewById(R.id.app_settings);
Intent settingsIntent = getAppSettingsIntent(mPm, mPkg, mSingleNotificationChannel,
mSbn.getId(), mSbn.getTag());
if (settingsIntent != null && getSelectedImportance() != IMPORTANCE_NONE
&& !TextUtils.isEmpty(mSbn.getNotification().getSettingsText())) {
mSettingsLinkView.setVisibility(View.VISIBLE);
mSettingsLinkView.setText(mContext.getString(R.string.notification_app_settings,
mSbn.getNotification().getSettingsText()));
mSettingsLinkView.setOnClickListener((View view) -> {
mAppSettingsClickListener.onClick(view, settingsIntent);
});
} else {
mSettingsLinkView.setVisibility(View.GONE);
}
}
private Intent getAppSettingsIntent(PackageManager pm, String packageName,
NotificationChannel channel, int id, String tag) {
Intent intent = new Intent(Intent.ACTION_MAIN)
@@ -390,6 +379,18 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
return intent;
}
private void closeControls(View v) {
int[] parentLoc = new int[2];
int[] targetLoc = new int[2];
mGutsContainer.getLocationOnScreen(parentLoc);
v.getLocationOnScreen(targetLoc);
final int centerX = v.getWidth() / 2;
final int centerY = v.getHeight() / 2;
final int x = targetLoc[0] - parentLoc[0] + centerX;
final int y = targetLoc[1] - parentLoc[1] + centerY;
mGutsContainer.closeControls(x, y, false /* save */, false /* force */);
}
@Override
public void setGutsParent(NotificationGuts guts) {
mGutsContainer = guts;
@@ -397,7 +398,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
@Override
public boolean willBeRemoved() {
return mChannelEnabledSwitch != null && !mChannelEnabledSwitch.isChecked();
return hasImportanceChanged();
}
@Override

View File

@@ -16,11 +16,13 @@
package com.android.systemui.statusbar;
import static android.app.NotificationManager.IMPORTANCE_LOW;
import static android.print.PrintManager.PRINT_SPOOLER_PACKAGE_NAME;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;
import static org.mockito.Mockito.any;
@@ -50,11 +52,11 @@ import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.PollingCheck;
import android.testing.UiThreadTest;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.Switch;
import android.widget.TextView;
import com.android.systemui.R;
@@ -66,7 +68,6 @@ import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;
@@ -117,50 +118,31 @@ public class NotificationInfoTest extends SysuiTestCase {
// Some test channels.
mNotificationChannel = new NotificationChannel(
TEST_CHANNEL, TEST_CHANNEL_NAME, NotificationManager.IMPORTANCE_LOW);
TEST_CHANNEL, TEST_CHANNEL_NAME, IMPORTANCE_LOW);
mDefaultNotificationChannel = new NotificationChannel(
NotificationChannel.DEFAULT_CHANNEL_ID, TEST_CHANNEL_NAME,
NotificationManager.IMPORTANCE_LOW);
IMPORTANCE_LOW);
mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID, 0,
new Notification(), UserHandle.CURRENT, null, 0);
}
private CharSequence getStringById(int resId) {
return mContext.getString(resId);
// TODO: if tests are taking too long replace this with something that makes the animation
// finish instantly.
private void waitForUndoButton() {
PollingCheck.waitFor(1000,
() -> VISIBLE == mNotificationInfo.findViewById(R.id.confirmation).getVisibility());
}
private CharSequence getNumChannelsDescString(int numChannels) {
return String.format(
mContext.getResources().getQuantityString(
R.plurals.notification_num_channels_desc, numChannels),
numChannels);
}
private CharSequence getChannelsListDescString(NotificationChannel... channels) {
if (channels.length == 2) {
return mContext.getString(R.string.notification_channels_list_desc_2,
channels[0].getName(), channels[1].getName());
} else {
final int numOthers = channels.length - 2;
return String.format(
mContext.getResources().getQuantityString(
R.plurals.notification_channels_list_desc_2_and_others, numOthers),
channels[0].getName(), channels[1].getName(), numOthers);
}
}
private CharSequence getNumChannelsString(int numChannels) {
return mContext.getString(R.string.notification_num_channels, numChannels);
private void waitForStopButton() {
PollingCheck.waitFor(1000,
() -> VISIBLE == mNotificationInfo.findViewById(R.id.prompt).getVisibility());
}
@Test
public void testBindNotification_SetsTextApplicationName() throws Exception {
when(mMockPackageManager.getApplicationLabel(any())).thenReturn("App Name");
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
mNotificationChannel.getImportance(), mSbn, null, null, null,
null, null);
final TextView textView = (TextView) mNotificationInfo.findViewById(R.id.pkgname);
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
final TextView textView = mNotificationInfo.findViewById(R.id.pkgname);
assertTrue(textView.getText().toString().contains("App Name"));
}
@@ -170,24 +152,19 @@ public class NotificationInfoTest extends SysuiTestCase {
when(mMockPackageManager.getApplicationIcon(any(ApplicationInfo.class)))
.thenReturn(iconDrawable);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
mNotificationChannel.getImportance(), mSbn, null, null, null,
null, null);
final ImageView iconView = (ImageView) mNotificationInfo.findViewById(R.id.pkgicon);
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
final ImageView iconView = mNotificationInfo.findViewById(R.id.pkgicon);
assertEquals(iconDrawable, iconView.getDrawable());
}
@Test
public void testBindNotification_GroupNameHiddenIfNoGroup() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
mNotificationChannel.getImportance(), mSbn, null, null, null,
null, null);
final TextView groupNameView = (TextView) mNotificationInfo.findViewById(R.id.group_name);
assertEquals(View.GONE, groupNameView.getVisibility());
final TextView groupDividerView =
(TextView) mNotificationInfo.findViewById(R.id.pkg_group_divider);
assertEquals(View.GONE, groupDividerView.getVisibility());
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
final TextView groupNameView = mNotificationInfo.findViewById(R.id.group_name);
assertEquals(GONE, groupNameView.getVisibility());
final TextView groupDividerView = mNotificationInfo.findViewById(R.id.pkg_group_divider);
assertEquals(GONE, groupDividerView.getVisibility());
}
@Test
@@ -199,75 +176,50 @@ 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, Arrays.asList(mNotificationChannel),
mNotificationChannel.getImportance(), mSbn, null, null, null,
null, null);
final TextView groupNameView = (TextView) mNotificationInfo.findViewById(R.id.group_name);
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
final TextView groupNameView = mNotificationInfo.findViewById(R.id.group_name);
assertEquals(View.VISIBLE, groupNameView.getVisibility());
assertEquals("Test Group Name", groupNameView.getText());
final TextView groupDividerView =
(TextView) mNotificationInfo.findViewById(R.id.pkg_group_divider);
final TextView groupDividerView = mNotificationInfo.findViewById(R.id.pkg_group_divider);
assertEquals(View.VISIBLE, groupDividerView.getVisibility());
}
@Test
public void testBindNotification_SetsTextChannelName() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
mNotificationChannel.getImportance(), mSbn, null, null, null,
null, null);
final TextView textView = (TextView) mNotificationInfo.findViewById(R.id.channel_name);
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
final TextView textView = mNotificationInfo.findViewById(R.id.channel_name);
assertEquals(TEST_CHANNEL_NAME, textView.getText());
}
@Test
public void testBindNotification_DefaultChannelDoesNotUseChannelName() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, Arrays.asList(mDefaultNotificationChannel),
mNotificationChannel.getImportance(), mSbn, null, null, null,
null, null);
final TextView textView = (TextView) mNotificationInfo.findViewById(R.id.channel_name);
assertEquals(mContext.getString(R.string.notification_header_default_channel),
textView.getText());
TEST_PACKAGE_NAME, mDefaultNotificationChannel, 1, mSbn, null, null, null, null);
final TextView textView = mNotificationInfo.findViewById(R.id.channel_name);
assertEquals(GONE, textView.getVisibility());
}
@Test
public void testBindNotification_UnblockablePackageDoesNotUseChannelName() throws Exception {
public void testBindNotification_UnblockablePackageUsesChannelName() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
mNotificationChannel.getImportance(), mSbn, null, null, null,
null, Collections.singleton(TEST_PACKAGE_NAME));
final TextView textView = (TextView) mNotificationInfo.findViewById(R.id.channel_name);
assertEquals(mContext.getString(R.string.notification_header_default_channel),
textView.getText());
}
@Test
public void testBindNotification_DefaultChannelUsesNameWhenMoreThanOneChannelExists()
throws Exception {
when(mMockINotificationManager.getNumNotificationChannelsForPackage(
eq(TEST_PACKAGE_NAME), eq(TEST_UID), anyBoolean())).thenReturn(2);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, Arrays.asList(mDefaultNotificationChannel),
mNotificationChannel.getImportance(), mSbn, null, null, null,
null, null);
final TextView textView = (TextView) mNotificationInfo.findViewById(R.id.channel_name);
assertEquals(mDefaultNotificationChannel.getName(), textView.getText());
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null,
Collections.singleton(TEST_PACKAGE_NAME));
final TextView textView = mNotificationInfo.findViewById(R.id.channel_name);
assertEquals(VISIBLE, textView.getVisibility());
}
@Test
public void testBindNotification_SetsOnClickListenerForSettings() throws Exception {
final CountDownLatch latch = new CountDownLatch(1);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
mNotificationChannel.getImportance(), mSbn,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null,
(View v, NotificationChannel c, int appUid) -> {
assertEquals(mNotificationChannel, c);
latch.countDown();
}, null, null, null, null);
}, null, null);
final TextView settingsButton =
(TextView) mNotificationInfo.findViewById(R.id.more_settings);
final View settingsButton = mNotificationInfo.findViewById(R.id.info);
settingsButton.performClick();
// Verify that listener was triggered.
assertEquals(0, latch.getCount());
@@ -276,24 +228,20 @@ public class NotificationInfoTest extends SysuiTestCase {
@Test
public void testBindNotification_SettingsButtonInvisibleWhenNoClickListener() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
mNotificationChannel.getImportance(), mSbn, null, null, null, null, null);
final TextView settingsButton =
(TextView) mNotificationInfo.findViewById(R.id.more_settings);
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
final View settingsButton = mNotificationInfo.findViewById(R.id.info);
assertTrue(settingsButton.getVisibility() != View.VISIBLE);
}
@Test
public void testBindNotification_SettingsButtonReappersAfterSecondBind() throws Exception {
public void testBindNotification_SettingsButtonReappearsAfterSecondBind() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
mNotificationChannel.getImportance(), mSbn, null, null, null, null, null);
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
mNotificationChannel.getImportance(), mSbn,
(View v, NotificationChannel c, int appUid) -> {}, null, null, null, null);
final TextView settingsButton =
(TextView) mNotificationInfo.findViewById(R.id.more_settings);
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null,
(View v, NotificationChannel c, int appUid) -> {
}, null, null);
final View settingsButton = mNotificationInfo.findViewById(R.id.info);
assertEquals(View.VISIBLE, settingsButton.getVisibility());
}
@@ -301,279 +249,63 @@ public class NotificationInfoTest extends SysuiTestCase {
public void testOnClickListenerPassesNullChannelForBundle() throws Exception {
final CountDownLatch latch = new CountDownLatch(1);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME,
Arrays.asList(mNotificationChannel, mDefaultNotificationChannel),
mNotificationChannel.getImportance(), mSbn,
TEST_PACKAGE_NAME, mNotificationChannel, 2, mSbn, null,
(View v, NotificationChannel c, int appUid) -> {
assertEquals(null, c);
latch.countDown();
}, null, null, null, null);
}, null, null);
final TextView settingsButton =
(TextView) mNotificationInfo.findViewById(R.id.more_settings);
settingsButton.performClick();
mNotificationInfo.findViewById(R.id.info).performClick();
// Verify that listener was triggered.
assertEquals(0, latch.getCount());
}
@Test
public void testBindNotification_SettingsTextWithOneChannel() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
mNotificationChannel.getImportance(), mSbn,
(View v, NotificationChannel c, int appUid) -> {
}, null, null, null, null);
final TextView settingsButton =
(TextView) mNotificationInfo.findViewById(R.id.more_settings);
assertEquals(getStringById(R.string.notification_more_settings), settingsButton.getText());
}
@Test
public void testBindNotification_SettingsTextWithMultipleChannels() throws Exception {
when(mMockINotificationManager.getNumNotificationChannelsForPackage(
eq(TEST_PACKAGE_NAME), eq(TEST_UID), anyBoolean())).thenReturn(2);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
mNotificationChannel.getImportance(), mSbn,
(View v, NotificationChannel c, int appUid) -> {
}, null, null, null, null);
final TextView settingsButton =
(TextView) mNotificationInfo.findViewById(R.id.more_settings);
assertEquals(getStringById(R.string.notification_all_categories), settingsButton.getText());
}
@Test
public void testBindNotification_SettingsTextWithMultipleChannelsForUnblockableApp()
throws Exception {
when(mMockINotificationManager.getNumNotificationChannelsForPackage(
eq(TEST_PACKAGE_NAME), eq(TEST_UID), anyBoolean())).thenReturn(2);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
mNotificationChannel.getImportance(), mSbn,
(View v, NotificationChannel c, int appUid) -> {
}, null, null, null, Collections.singleton(TEST_PACKAGE_NAME));
final TextView settingsButton =
(TextView) mNotificationInfo.findViewById(R.id.more_settings);
assertEquals(getStringById(R.string.notification_more_settings), settingsButton.getText());
}
@Test
public void testBindNotification_SetsOnClickListenerForDone() throws Exception {
final CountDownLatch latch = new CountDownLatch(1);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
mNotificationChannel.getImportance(), mSbn, null,
null, (View v) -> {
latch.countDown();
},
null, null);
final TextView doneButton = (TextView) mNotificationInfo.findViewById(R.id.done);
doneButton.performClick();
// Verify that listener was triggered.
assertEquals(0, latch.getCount());
}
@Test
public void testBindNotification_NumChannelsTextHiddenWhenDefaultChannel() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, Arrays.asList(mDefaultNotificationChannel),
mNotificationChannel.getImportance(), mSbn, null, null,
null, null, null);
final TextView numChannelsView =
(TextView) mNotificationInfo.findViewById(R.id.num_channels_desc);
assertEquals(View.INVISIBLE, numChannelsView.getVisibility());
}
@Test
public void testBindNotification_NumChannelsTextDisplaysWhenMoreThanOneChannelExists()
throws Exception {
when(mMockINotificationManager.getNumNotificationChannelsForPackage(
eq(TEST_PACKAGE_NAME), eq(TEST_UID), anyBoolean())).thenReturn(2);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, Arrays.asList(mDefaultNotificationChannel),
mNotificationChannel.getImportance(), mSbn, null, null,
null, null, null);
final TextView numChannelsView =
(TextView) mNotificationInfo.findViewById(R.id.num_channels_desc);
assertEquals(numChannelsView.getVisibility(), View.VISIBLE);
assertEquals(getNumChannelsDescString(2), numChannelsView.getText());
}
@Test
public void testBindNotification_NumChannelsTextDisplaysWhenNotDefaultChannel()
throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
mNotificationChannel.getImportance(), mSbn, null, null, null,
null, null);
final TextView numChannelsView =
(TextView) mNotificationInfo.findViewById(R.id.num_channels_desc);
assertEquals(numChannelsView.getVisibility(), View.VISIBLE);
assertEquals(getNumChannelsDescString(1), numChannelsView.getText());
}
@Test
public void testBindNotification_NumChannelsTextScalesWithNumberOfChannels()
throws Exception {
when(mMockINotificationManager.getNumNotificationChannelsForPackage(
eq(TEST_PACKAGE_NAME), eq(TEST_UID), anyBoolean())).thenReturn(2);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
mNotificationChannel.getImportance(), mSbn, null, null, null,
null, null);
final TextView numChannelsView =
(TextView) mNotificationInfo.findViewById(R.id.num_channels_desc);
assertEquals(getNumChannelsDescString(2), numChannelsView.getText());
}
@Test
@UiThreadTest
public void testBindNotification_NumChannelsTextListsChannelsWhenTwoInBundle()
public void testBindNotification_ChannelNameInvisibleWhenBundleFromDifferentChannels()
throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel, mDefaultNotificationChannel),
mNotificationChannel.getImportance(), mSbn, null, null, null, null, null);
final TextView numChannelsView =
(TextView) mNotificationInfo.findViewById(R.id.num_channels_desc);
assertEquals(getChannelsListDescString(mNotificationChannel, mDefaultNotificationChannel),
numChannelsView.getText());
}
@Test
@UiThreadTest
public void testBindNotification_NumChannelsTextListsChannelsWhenThreeInBundle()
throws Exception {
NotificationChannel thirdChannel = new NotificationChannel(
"third_channel", "third_channel", NotificationManager.IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME,
Arrays.asList(mNotificationChannel, mDefaultNotificationChannel, thirdChannel),
mNotificationChannel.getImportance(), mSbn, null, null, null, null, null);
final TextView numChannelsView =
(TextView) mNotificationInfo.findViewById(R.id.num_channels_desc);
assertEquals(
getChannelsListDescString(mNotificationChannel, mDefaultNotificationChannel,
thirdChannel),
numChannelsView.getText());
}
@Test
@UiThreadTest
public void testBindNotification_NumChannelsTextListsChannelsWhenFourInBundle()
throws Exception {
NotificationChannel thirdChannel = new NotificationChannel(
"third_channel", "third_channel", NotificationManager.IMPORTANCE_LOW);
NotificationChannel fourthChannel = new NotificationChannel(
"fourth_channel", "fourth_channel", NotificationManager.IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME,
Arrays.asList(mNotificationChannel, mDefaultNotificationChannel, thirdChannel,
fourthChannel), mNotificationChannel.getImportance(), mSbn, null, null,
null, null, null);
final TextView numChannelsView =
(TextView) mNotificationInfo.findViewById(R.id.num_channels_desc);
assertEquals(
getChannelsListDescString(mNotificationChannel, mDefaultNotificationChannel,
thirdChannel, fourthChannel),
numChannelsView.getText());
}
@Test
@UiThreadTest
public void testBindNotification_ChannelNameChangesWhenBundleFromDifferentChannels()
throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel, mDefaultNotificationChannel),
mNotificationChannel.getImportance(), mSbn, null, null, null, null, null);
TEST_PACKAGE_NAME, mNotificationChannel, 2, mSbn, null, null, null, null);
final TextView channelNameView =
(TextView) mNotificationInfo.findViewById(R.id.channel_name);
assertEquals(getNumChannelsString(2), channelNameView.getText());
mNotificationInfo.findViewById(R.id.channel_name);
assertEquals(GONE, channelNameView.getVisibility());
}
@Test
@UiThreadTest
public void testEnabledSwitchInvisibleIfBundleFromDifferentChannels() throws Exception {
public void testStopInvisibleIfBundleFromDifferentChannels() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel, mDefaultNotificationChannel),
mNotificationChannel.getImportance(), mSbn, null, null, null, null, null);
Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch);
assertEquals(View.INVISIBLE, enabledSwitch.getVisibility());
}
@Test
public void testbindNotification_ChannelDisabledTextGoneWhenNotDisabled() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
mNotificationChannel.getImportance(), mSbn, null, null, null, null, null);
final TextView channelDisabledView =
(TextView) mNotificationInfo.findViewById(R.id.channel_disabled);
assertEquals(channelDisabledView.getVisibility(), View.GONE);
}
@Test
public void testbindNotification_ChannelDisabledTextVisibleWhenDisabled() throws Exception {
mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_NONE);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
mNotificationChannel.getImportance(), mSbn, null, null, null,
null, null);
final TextView channelDisabledView =
(TextView) mNotificationInfo.findViewById(R.id.channel_disabled);
assertEquals(channelDisabledView.getVisibility(), View.VISIBLE);
// Replaces the numChannelsView
final TextView numChannelsView =
(TextView) mNotificationInfo.findViewById(R.id.num_channels_desc);
assertEquals(numChannelsView.getVisibility(), View.GONE);
TEST_PACKAGE_NAME, mNotificationChannel, 2, mSbn, null, null, null, null);
final TextView blockView = mNotificationInfo.findViewById(R.id.block);
assertEquals(GONE, blockView.getVisibility());
}
@Test
public void testbindNotification_UnblockableTextVisibleWhenAppUnblockable() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
mNotificationChannel.getImportance(), mSbn, null, null, null,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null,
null, Collections.singleton(TEST_PACKAGE_NAME));
final TextView numChannelsView =
(TextView) mNotificationInfo.findViewById(R.id.num_channels_desc);
assertEquals(View.VISIBLE, numChannelsView.getVisibility());
final TextView view = mNotificationInfo.findViewById(R.id.block_prompt);
assertEquals(View.VISIBLE, view.getVisibility());
assertEquals(mContext.getString(R.string.notification_unblockable_desc),
numChannelsView.getText());
}
@Test
@UiThreadTest
public void testBindNotification_ChannelDisabledTextShowsForDefaultChannel()
throws Exception {
mDefaultNotificationChannel.setImportance(NotificationManager.IMPORTANCE_NONE);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, Arrays.asList(mDefaultNotificationChannel),
mDefaultNotificationChannel.getImportance(), mSbn, null, null,
null, null, null);
final TextView channelDisabledView =
(TextView) mNotificationInfo.findViewById(R.id.channel_disabled);
assertEquals(View.VISIBLE, channelDisabledView.getVisibility());
view.getText());
}
@Test
public void testBindNotification_DoesNotUpdateNotificationChannel() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
mNotificationChannel.getImportance(), mSbn, null, null, null,
null, null);
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
anyString(), eq(TEST_UID), any());
}
@Test
public void testDoesNotUpdateNotificationChannelAfterImportanceChanged() throws Exception {
mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
mNotificationChannel.getImportance(), mSbn, null, null, null,
null, null);
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch);
enabledSwitch.setChecked(false);
mNotificationInfo.findViewById(R.id.block).performClick();
verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
anyString(), eq(TEST_UID), any());
}
@@ -582,9 +314,7 @@ public class NotificationInfoTest extends SysuiTestCase {
public void testHandleCloseControls_DoesNotUpdateNotificationChannelIfUnchanged()
throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
mNotificationChannel.getImportance(), mSbn, null, null, null,
null, null);
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
mNotificationInfo.handleCloseControls(true, false);
verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
@@ -596,124 +326,33 @@ public class NotificationInfoTest extends SysuiTestCase {
throws Exception {
mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_UNSPECIFIED);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
mNotificationChannel.getImportance(), mSbn, null, null, null,
null, null);
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
mNotificationInfo.handleCloseControls(true, false);
verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
anyString(), eq(TEST_UID), any());
}
@Test
public void testEnabledSwitchOnByDefault() throws Exception {
mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
mNotificationChannel.getImportance(), mSbn, null, null, null,
null, null);
Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch);
assertTrue(enabledSwitch.isChecked());
}
@Test
public void testEnabledButtonOffWhenAlreadyBanned() throws Exception {
mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_NONE);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
mNotificationChannel.getImportance(), mSbn, null, null, null,
null, null);
Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch);
assertFalse(enabledSwitch.isChecked());
}
@Test
public void testEnabledSwitchVisibleByDefault() throws Exception {
mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
mNotificationChannel.getImportance(), mSbn, null, null, null,
null, null);
Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch);
assertEquals(View.VISIBLE, enabledSwitch.getVisibility());
}
@Test
public void testEnabledSwitchInvisibleIfNonBlockable() throws Exception {
mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
mNotificationChannel.getImportance(), mSbn, null, null, null,
null, Collections.singleton(TEST_PACKAGE_NAME));
Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch);
assertEquals(View.INVISIBLE, enabledSwitch.getVisibility());
}
@Test
public void testEnabledSwitchInvisibleIfNonBlockableSystemChannel() throws Exception {
mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
mNotificationChannel.setBlockableSystem(false);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_SYSTEM_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
mNotificationChannel.getImportance(), mSbn, null, null, null,
null, null);
Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch);
assertEquals(View.INVISIBLE, enabledSwitch.getVisibility());
}
@Test
public void testEnabledSwitchVisibleIfBlockableSystemChannel() throws Exception {
mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
mNotificationChannel.setBlockableSystem(true);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_SYSTEM_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
mNotificationChannel.getImportance(), mSbn, null, null, null,
null, null);
Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch);
assertEquals(View.VISIBLE, enabledSwitch.getVisibility());
}
@Test
public void testEnabledSwitchInvisibleIfMultiChannelSummary() throws Exception {
mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
mNotificationChannel.setBlockableSystem(true);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel, mDefaultNotificationChannel),
mNotificationChannel.getImportance(), mSbn, null, null, null,
null, Collections.singleton(TEST_PACKAGE_NAME));
Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch);
assertEquals(View.INVISIBLE, enabledSwitch.getVisibility());
}
@Test
public void testNonBlockableAppDoesNotBecomeBlocked() throws Exception {
mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
mNotificationChannel.getImportance(), mSbn, null, null, null,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null,
null, Collections.singleton(TEST_PACKAGE_NAME));
mNotificationInfo.handleCloseControls(true, false);
mNotificationInfo.findViewById(R.id.block).performClick();
waitForUndoButton();
verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
anyString(), eq(TEST_UID), any());
}
@Test
public void testEnabledSwitchChangedCallsUpdateNotificationChannel() throws Exception {
mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
public void testBlockChangedCallsUpdateNotificationChannel() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
mNotificationChannel.getImportance(), mSbn, null, null, null,
null, Collections.singleton(TEST_PACKAGE_NAME));
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
Switch enabledSwitch = mNotificationInfo.findViewById(R.id.channel_enabled_switch);
enabledSwitch.setChecked(false);
mNotificationInfo.findViewById(R.id.block).performClick();
waitForUndoButton();
mNotificationInfo.handleCloseControls(true, false);
ArgumentCaptor<NotificationChannel> updated =
@@ -725,15 +364,35 @@ public class NotificationInfoTest extends SysuiTestCase {
}
@Test
public void testCloseControlsDoesNotUpdateIfSaveIsFalse() throws Exception {
mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
public void testBlockUndoDoesNotCallUpdateNotificationChannel() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
mNotificationChannel.getImportance(), mSbn, null, null, null,
null, Collections.singleton(TEST_PACKAGE_NAME));
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null,
Collections.singleton(TEST_PACKAGE_NAME));
Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch);
enabledSwitch.setChecked(false);
mNotificationInfo.findViewById(R.id.block).performClick();
waitForUndoButton();
mNotificationInfo.findViewById(R.id.undo).performClick();
waitForStopButton();
mNotificationInfo.handleCloseControls(true, false);
ArgumentCaptor<NotificationChannel> updated =
ArgumentCaptor.forClass(NotificationChannel.class);
verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
anyString(), eq(TEST_UID), updated.capture());
assertEquals(IMPORTANCE_LOW, mNotificationChannel.getImportance());
}
@Test
public void testCloseControlsDoesNotUpdateIfSaveIsFalse() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null,
Collections.singleton(TEST_PACKAGE_NAME));
mNotificationInfo.findViewById(R.id.block).performClick();
waitForUndoButton();
mNotificationInfo.handleCloseControls(false, false);
verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
eq(TEST_PACKAGE_NAME), eq(TEST_UID), eq(mNotificationChannel));
@@ -741,16 +400,14 @@ public class NotificationInfoTest extends SysuiTestCase {
@Test
public void testCloseControlsDoesNotUpdateIfCheckSaveListenerIsNoOp() throws Exception {
mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
mNotificationChannel.getImportance(), mSbn, null, null, null,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn,
(Runnable saveImportance, StatusBarNotification sbn) -> {
},
Collections.singleton(TEST_PACKAGE_NAME));
}, null, null, Collections.singleton(TEST_PACKAGE_NAME));
Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch);
enabledSwitch.setChecked(false);
mNotificationInfo.findViewById(R.id.block).performClick();
waitForUndoButton();
mNotificationInfo.handleCloseControls(true, false);
verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
eq(TEST_PACKAGE_NAME), eq(TEST_UID), eq(mNotificationChannel));
@@ -758,17 +415,15 @@ public class NotificationInfoTest extends SysuiTestCase {
@Test
public void testCloseControlsUpdatesWhenCheckSaveListenerUsesCallback() throws Exception {
mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
mNotificationChannel.getImportance(), mSbn, null, null, null,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn,
(Runnable saveImportance, StatusBarNotification sbn) -> {
saveImportance.run();
},
Collections.singleton(TEST_PACKAGE_NAME));
}, null, null, null);
Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch);
enabledSwitch.setChecked(false);
mNotificationInfo.findViewById(R.id.block).performClick();
waitForUndoButton();
mNotificationInfo.handleCloseControls(true, false);
verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
eq(TEST_PACKAGE_NAME), eq(TEST_UID), eq(mNotificationChannel));
@@ -785,22 +440,19 @@ public class NotificationInfoTest extends SysuiTestCase {
List<ResolveInfo> ris = new ArrayList<>();
ris.add(ri);
when(mMockPackageManager.queryIntentActivities(any(), anyInt())).thenReturn(ris);
mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
mNotificationChannel.setImportance(IMPORTANCE_LOW);
Notification n = new Notification.Builder(mContext, mNotificationChannel.getId())
.setSettingsText(settingsText).build();
StatusBarNotification sbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME,
0, null, 0, 0, n, UserHandle.CURRENT, null, 0);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
mNotificationChannel.getImportance(), sbn, null,
TEST_PACKAGE_NAME, mNotificationChannel, 1, sbn, null, null,
(View v, Intent intent) -> {
latch.countDown();
}, null, null, null);
}, null);
final TextView settingsLink = mNotificationInfo.findViewById(R.id.app_settings);
assertEquals(View.VISIBLE, settingsLink.getVisibility());
assertTrue(settingsLink.getText().toString().length() > settingsText.length());
assertTrue(settingsLink.getText().toString().contains(settingsText));
settingsLink.performClick();
assertEquals(0, latch.getCount());
}
@@ -816,17 +468,17 @@ public class NotificationInfoTest extends SysuiTestCase {
List<ResolveInfo> ris = new ArrayList<>();
ris.add(ri);
when(mMockPackageManager.queryIntentActivities(any(), anyInt())).thenReturn(ris);
mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
mNotificationChannel.setImportance(IMPORTANCE_LOW);
Notification n = new Notification.Builder(mContext, mNotificationChannel.getId())
.setSettingsText(settingsText).build();
StatusBarNotification sbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME,
0, null, 0, 0, n, UserHandle.CURRENT, null, 0);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel, mDefaultNotificationChannel),
mNotificationChannel.getImportance(), sbn, null, (View v, Intent intent) -> {
TEST_PACKAGE_NAME, mNotificationChannel, 2, sbn, null, null,
(View v, Intent intent) -> {
latch.countDown();
}, null, null, null);
}, null);
final TextView settingsLink = mNotificationInfo.findViewById(R.id.app_settings);
assertEquals(View.VISIBLE, settingsLink.getVisibility());
settingsLink.performClick();
@@ -837,18 +489,16 @@ public class NotificationInfoTest extends SysuiTestCase {
public void testNoSettingsLink_noHandlingActivity() throws Exception {
final String settingsText = "work chats";
when(mMockPackageManager.queryIntentActivities(any(), anyInt())).thenReturn(null);
mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
mNotificationChannel.setImportance(IMPORTANCE_LOW);
Notification n = new Notification.Builder(mContext, mNotificationChannel.getId())
.setSettingsText(settingsText).build();
StatusBarNotification sbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME,
0, null, 0, 0, n, UserHandle.CURRENT, null, 0);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
mNotificationChannel.getImportance(), sbn, null, null, null,
null, null);
TEST_PACKAGE_NAME, mNotificationChannel, 2, sbn, null, null, null, null);
final TextView settingsLink = mNotificationInfo.findViewById(R.id.app_settings);
assertEquals(View.GONE, settingsLink.getVisibility());
assertEquals(GONE, settingsLink.getVisibility());
}
@Test
@@ -860,52 +510,17 @@ public class NotificationInfoTest extends SysuiTestCase {
List<ResolveInfo> ris = new ArrayList<>();
ris.add(ri);
when(mMockPackageManager.queryIntentActivities(any(), anyInt())).thenReturn(ris);
mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
mNotificationChannel.setImportance(IMPORTANCE_LOW);
Notification n = new Notification.Builder(mContext, mNotificationChannel.getId()).build();
StatusBarNotification sbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME,
0, null, 0, 0, n, UserHandle.CURRENT, null, 0);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
mNotificationChannel.getImportance(), sbn, null, null, null,
null, null);
TEST_PACKAGE_NAME, mNotificationChannel, 1, sbn, null, null, null, null);
final TextView settingsLink = mNotificationInfo.findViewById(R.id.app_settings);
assertEquals(View.GONE, settingsLink.getVisibility());
assertEquals(GONE, settingsLink.getVisibility());
}
@Test
public void testNoSettingsLink_afterBlockingChannel() throws Exception {
final String settingsText = "work chats";
final ResolveInfo ri = new ResolveInfo();
ri.activityInfo = new ActivityInfo();
ri.activityInfo.packageName = TEST_PACKAGE_NAME;
ri.activityInfo.name = "something";
List<ResolveInfo> ris = new ArrayList<>();
ris.add(ri);
when(mMockPackageManager.queryIntentActivities(any(), anyInt())).thenReturn(ris);
mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
Notification n = new Notification.Builder(mContext, mNotificationChannel.getId())
.setSettingsText(settingsText).build();
StatusBarNotification sbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME,
0, null, 0, 0, n, UserHandle.CURRENT, null, 0);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
mNotificationChannel.getImportance(), sbn, null, null, null,
null, null);
final TextView settingsLink = mNotificationInfo.findViewById(R.id.app_settings);
assertEquals(View.VISIBLE, settingsLink.getVisibility());
// Block channel
Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch);
enabledSwitch.setChecked(false);
assertEquals(View.GONE, settingsLink.getVisibility());
//unblock
enabledSwitch.setChecked(true);
assertEquals(View.VISIBLE, settingsLink.getVisibility());
}
@Test
public void testWillBeRemovedReturnsFalseBeforeBind() throws Exception {

View File

@@ -0,0 +1,94 @@
/*
* Copyright (C) 2018 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 android.testing;
import junit.framework.Assert;
import java.util.concurrent.Callable;
public abstract class PollingCheck {
private static final long TIME_SLICE = 50;
private long mTimeout = 3000;
public static interface PollingCheckCondition {
boolean canProceed();
}
public PollingCheck() {
}
public PollingCheck(long timeout) {
mTimeout = timeout;
}
protected abstract boolean check();
public void run() {
if (check()) {
return;
}
long timeout = mTimeout;
while (timeout > 0) {
try {
Thread.sleep(TIME_SLICE);
} catch (InterruptedException e) {
Assert.fail("unexpected InterruptedException");
}
if (check()) {
return;
}
timeout -= TIME_SLICE;
}
Assert.fail("unexpected timeout");
}
public static void check(CharSequence message, long timeout, Callable<Boolean> condition)
throws Exception {
while (timeout > 0) {
if (condition.call()) {
return;
}
Thread.sleep(TIME_SLICE);
timeout -= TIME_SLICE;
}
Assert.fail(message.toString());
}
public static void waitFor(final PollingCheckCondition condition) {
new PollingCheck() {
@Override
protected boolean check() {
return condition.canProceed();
}
}.run();
}
public static void waitFor(long timeout, final PollingCheckCondition condition) {
new PollingCheck(timeout) {
@Override
protected boolean check() {
return condition.canProceed();
}
}.run();
}
}