diff options
-rw-r--r-- | api/current.txt | 4 | ||||
-rw-r--r-- | api/system-current.txt | 4 | ||||
-rw-r--r-- | api/test-current.txt | 4 | ||||
-rw-r--r-- | core/java/android/app/Notification.java | 60 | ||||
-rw-r--r-- | packages/SystemUI/res/layout/notification_info.xml | 9 | ||||
-rw-r--r-- | packages/SystemUI/res/values/strings.xml | 3 | ||||
-rw-r--r-- | packages/SystemUI/res/values/styles.xml | 4 | ||||
-rw-r--r-- | packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java | 106 | ||||
-rw-r--r-- | packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java | 17 | ||||
-rw-r--r-- | packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java | 293 |
10 files changed, 420 insertions, 84 deletions
diff --git a/api/current.txt b/api/current.txt index c154fc9c2823..55221011ddfd 100644 --- a/api/current.txt +++ b/api/current.txt @@ -5117,6 +5117,7 @@ package android.app { method public java.lang.String getChannel(); method public java.lang.String getGroup(); method public android.graphics.drawable.Icon getLargeIcon(); + method public java.lang.CharSequence getSettingsText(); method public java.lang.String getShortcutId(); method public android.graphics.drawable.Icon getSmallIcon(); method public java.lang.String getSortKey(); @@ -5161,6 +5162,8 @@ package android.app { field public static final java.lang.String EXTRA_LARGE_ICON_BIG = "android.largeIcon.big"; field public static final java.lang.String EXTRA_MEDIA_SESSION = "android.mediaSession"; field public static final java.lang.String EXTRA_MESSAGES = "android.messages"; + field public static final java.lang.String EXTRA_NOTIFICATION_ID = "android.intent.extra.NOTIFICATION_ID"; + field public static final java.lang.String EXTRA_NOTIFICATION_TAG = "android.intent.extra.NOTIFICATION_TAG"; field public static final java.lang.String EXTRA_PEOPLE = "android.people"; field public static final java.lang.String EXTRA_PICTURE = "android.picture"; field public static final java.lang.String EXTRA_PROGRESS = "android.progress"; @@ -5346,6 +5349,7 @@ package android.app { method public android.app.Notification.Builder setProgress(int, int, boolean); method public android.app.Notification.Builder setPublicVersion(android.app.Notification); method public android.app.Notification.Builder setRemoteInputHistory(java.lang.CharSequence[]); + method public android.app.Notification.Builder setSettingsText(java.lang.CharSequence); method public android.app.Notification.Builder setShortcutId(java.lang.String); method public android.app.Notification.Builder setShowWhen(boolean); method public android.app.Notification.Builder setSmallIcon(int); diff --git a/api/system-current.txt b/api/system-current.txt index 2441d9cbc337..1306f6d65d08 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -5290,6 +5290,7 @@ package android.app { method public java.lang.String getGroup(); method public android.graphics.drawable.Icon getLargeIcon(); method public static java.lang.Class<? extends android.app.Notification.Style> getNotificationStyleClass(java.lang.String); + method public java.lang.CharSequence getSettingsText(); method public java.lang.String getShortcutId(); method public android.graphics.drawable.Icon getSmallIcon(); method public java.lang.String getSortKey(); @@ -5335,6 +5336,8 @@ package android.app { field public static final java.lang.String EXTRA_LARGE_ICON_BIG = "android.largeIcon.big"; field public static final java.lang.String EXTRA_MEDIA_SESSION = "android.mediaSession"; field public static final java.lang.String EXTRA_MESSAGES = "android.messages"; + field public static final java.lang.String EXTRA_NOTIFICATION_ID = "android.intent.extra.NOTIFICATION_ID"; + field public static final java.lang.String EXTRA_NOTIFICATION_TAG = "android.intent.extra.NOTIFICATION_TAG"; field public static final java.lang.String EXTRA_PEOPLE = "android.people"; field public static final java.lang.String EXTRA_PICTURE = "android.picture"; field public static final java.lang.String EXTRA_PROGRESS = "android.progress"; @@ -5522,6 +5525,7 @@ package android.app { method public android.app.Notification.Builder setProgress(int, int, boolean); method public android.app.Notification.Builder setPublicVersion(android.app.Notification); method public android.app.Notification.Builder setRemoteInputHistory(java.lang.CharSequence[]); + method public android.app.Notification.Builder setSettingsText(java.lang.CharSequence); method public android.app.Notification.Builder setShortcutId(java.lang.String); method public android.app.Notification.Builder setShowWhen(boolean); method public android.app.Notification.Builder setSmallIcon(int); diff --git a/api/test-current.txt b/api/test-current.txt index 02c8c0397ffb..ac381d63cdb0 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -5129,6 +5129,7 @@ package android.app { method public java.lang.String getChannel(); method public java.lang.String getGroup(); method public android.graphics.drawable.Icon getLargeIcon(); + method public java.lang.CharSequence getSettingsText(); method public java.lang.String getShortcutId(); method public android.graphics.drawable.Icon getSmallIcon(); method public java.lang.String getSortKey(); @@ -5173,6 +5174,8 @@ package android.app { field public static final java.lang.String EXTRA_LARGE_ICON_BIG = "android.largeIcon.big"; field public static final java.lang.String EXTRA_MEDIA_SESSION = "android.mediaSession"; field public static final java.lang.String EXTRA_MESSAGES = "android.messages"; + field public static final java.lang.String EXTRA_NOTIFICATION_ID = "android.intent.extra.NOTIFICATION_ID"; + field public static final java.lang.String EXTRA_NOTIFICATION_TAG = "android.intent.extra.NOTIFICATION_TAG"; field public static final java.lang.String EXTRA_PEOPLE = "android.people"; field public static final java.lang.String EXTRA_PICTURE = "android.picture"; field public static final java.lang.String EXTRA_PROGRESS = "android.progress"; @@ -5358,6 +5361,7 @@ package android.app { method public android.app.Notification.Builder setProgress(int, int, boolean); method public android.app.Notification.Builder setPublicVersion(android.app.Notification); method public android.app.Notification.Builder setRemoteInputHistory(java.lang.CharSequence[]); + method public android.app.Notification.Builder setSettingsText(java.lang.CharSequence); method public android.app.Notification.Builder setShortcutId(java.lang.String); method public android.app.Notification.Builder setShowWhen(boolean); method public android.app.Notification.Builder setSmallIcon(int); diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 161dd2583134..6d7486b5311e 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -103,8 +103,7 @@ public class Notification implements Parcelable /** * An activity that provides a user interface for adjusting notification preferences for its - * containing application. Optional but recommended for apps that post - * {@link android.app.Notification Notifications}. + * containing application. */ @SdkConstant(SdkConstantType.INTENT_CATEGORY) public static final String INTENT_CATEGORY_NOTIFICATION_PREFERENCES @@ -113,11 +112,25 @@ public class Notification implements Parcelable /** * Optional extra for {@link #INTENT_CATEGORY_NOTIFICATION_PREFERENCES}. If provided, will * contain a {@link NotificationChannel#getId() channel id} that can be used to narrow down - * what in app notifications settings should be shown. + * what settings should be shown in the target app. */ public static final String EXTRA_CHANNEL_ID = "android.intent.extra.CHANNEL_ID"; /** + * Optional extra for {@link #INTENT_CATEGORY_NOTIFICATION_PREFERENCES}. If provided, will + * contain the tag provided to {@link NotificationManager#notify(String, int, Notification)} + * that can be used to narrow down what settings should be shown in the target app. + */ + public static final String EXTRA_NOTIFICATION_TAG = "android.intent.extra.NOTIFICATION_TAG"; + + /** + * Optional extra for {@link #INTENT_CATEGORY_NOTIFICATION_PREFERENCES}. If provided, will + * contain the id provided to {@link NotificationManager#notify(String, int, Notification)} + * that can be used to narrow down what settings should be shown in the target app. + */ + public static final String EXTRA_NOTIFICATION_ID = "android.intent.extra.NOTIFICATION_ID"; + + /** * Use all default values (where applicable). */ public static final int DEFAULT_ALL = ~0; @@ -1082,6 +1095,7 @@ public class Notification implements Parcelable private long mTimeout; private String mShortcutId; + private CharSequence mSettingsText; /** * If this notification is being shown as a badge, always show as a number. @@ -1851,6 +1865,10 @@ public class Notification implements Parcelable } mBadgeIcon = parcel.readInt(); + + if (parcel.readInt() != 0) { + mSettingsText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel); + } } @Override @@ -1960,6 +1978,9 @@ public class Notification implements Parcelable that.mChannelId = this.mChannelId; that.mTimeout = this.mTimeout; + that.mShortcutId = this.mShortcutId; + that.mBadgeIcon = this.mBadgeIcon; + that.mSettingsText = this.mSettingsText; if (!heavy) { that.lightenPayload(); // will clean out extras @@ -2229,6 +2250,13 @@ public class Notification implements Parcelable } parcel.writeInt(mBadgeIcon); + + if (mSettingsText != null) { + parcel.writeInt(1); + TextUtils.writeToParcel(mSettingsText, parcel, flags); + } else { + parcel.writeInt(0); + } } /** @@ -2458,6 +2486,14 @@ public class Notification implements Parcelable return mShortcutId; } + + /** + * Returns the settings text provided to {@link Builder#setSettingsText(CharSequence)}. + */ + public CharSequence getSettingsText() { + return mSettingsText; + } + /** * The small icon representing this notification in the status bar and content view. * @@ -2887,6 +2923,24 @@ public class Notification implements Parcelable } /** + * Provides text that will appear as a link to your application's settings. + * + * <p>This text does not appear within notification {@link Style templates} but may + * appear when the user uses an affordance to learn more about the notification. + * Additionally, this text will not appear unless you provide a valid link target by + * handling {@link #INTENT_CATEGORY_NOTIFICATION_PREFERENCES}. + * + * <p>This text is meant to be concise description about what the user can customize + * when they click on this link. The recommended maximum length is 40 characters. + * @param text + * @return + */ + public Builder setSettingsText(CharSequence text) { + mN.mSettingsText = safeCharSequence(text); + return this; + } + + /** * Set the remote input history. * * This should be set to the most recent inputs that have been sent diff --git a/packages/SystemUI/res/layout/notification_info.xml b/packages/SystemUI/res/layout/notification_info.xml index 195eb9bafdab..ff22ffb319fb 100644 --- a/packages/SystemUI/res/layout/notification_info.xml +++ b/packages/SystemUI/res/layout/notification_info.xml @@ -97,6 +97,15 @@ 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> <!-- Ban Channel Switch --> <Switch diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index a8cf3daec41e..43aeaa3c9314 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -1472,6 +1472,9 @@ <!-- 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> <!-- Notification: Control panel: Label for button that dismisses control panel. [CHAR LIMIT=NONE] --> <string name="notification_done">Done</string> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index d6abda6bd4c9..c9479b8b41f7 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -370,6 +370,10 @@ <item name="android:textColor">?android:attr/colorError</item> </style> + <style name="TextAppearance.NotificationInfo.Secondary.Link"> + <item name="android:textColor">?android:attr/colorAccent</item> + </style> + <style name="TextAppearance.NotificationInfo.Button"> <item name="android:fontFamily">sans-serif-medium</item> <item name="android:textSize">14sp</item> diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java index 8298f35bbcca..b4b1cd3409f6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java @@ -16,45 +16,34 @@ package com.android.systemui.statusbar; -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; +import static android.app.NotificationManager.IMPORTANCE_NONE; + import android.app.INotificationManager; +import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationChannelGroup; -import android.app.NotificationManager; import android.content.Context; +import android.content.Intent; +import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; -import android.content.pm.ParceledListSlice; -import android.content.res.ColorStateList; -import android.content.res.TypedArray; -import android.graphics.Canvas; +import android.content.pm.ResolveInfo; import android.graphics.drawable.Drawable; -import android.os.Handler; import android.os.RemoteException; -import android.os.ServiceManager; -import android.service.notification.NotificationListenerService; +import android.service.notification.StatusBarNotification; +import android.text.TextUtils; import android.util.AttributeSet; -import android.util.Log; import android.view.View; -import android.view.ViewAnimationUtils; -import android.view.ViewGroup; -import android.view.View.OnClickListener; -import android.widget.CompoundButton; import android.widget.ImageView; import android.widget.LinearLayout; -import android.widget.SeekBar; 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 com.android.systemui.statusbar.NotificationGuts.OnSettingsClickListener; -import com.android.systemui.statusbar.stack.StackStateAnimator; import java.lang.IllegalArgumentException; import java.util.List; @@ -71,12 +60,16 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G private int mAppUid; private List<NotificationChannel> mNotificationChannels; private NotificationChannel mSingleNotificationChannel; + private StatusBarNotification mSbn; private int mStartingUserImportance; private TextView mNumChannelsView; private View mChannelDisabledView; + private TextView mSettingsLinkView; private Switch mChannelEnabledSwitch; private CheckSaveListener mCheckSaveListener; + private OnAppSettingsClickListener mAppSettingsClickListener; + private PackageManager mPm; private NotificationGuts mGutsContainer; @@ -95,11 +88,18 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G void onClick(View v, NotificationChannel channel, int appUid); } + public interface OnAppSettingsClickListener { + void onClick(View v, Intent intent); + } + public void bindNotification(final PackageManager pm, final INotificationManager iNotificationManager, final String pkg, final List<NotificationChannel> notificationChannels, + int startingUserImportance, + final StatusBarNotification sbn, OnSettingsClickListener onSettingsClick, + OnAppSettingsClickListener onAppSettingsClick, OnClickListener onDoneClick, CheckSaveListener checkSaveListener, final Set<String> nonBlockablePkgs) @@ -108,16 +108,21 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G mPkg = pkg; mNotificationChannels = notificationChannels; mCheckSaveListener = checkSaveListener; + mSbn = sbn; + mPm = pm; + mAppSettingsClickListener = onAppSettingsClick; boolean isSingleDefaultChannel = false; + mStartingUserImportance = startingUserImportance; if (mNotificationChannels.isEmpty()) { throw new IllegalArgumentException("bindNotification requires at least one channel"); - } else if (mNotificationChannels.size() == 1) { - mSingleNotificationChannel = mNotificationChannels.get(0); - mStartingUserImportance = mSingleNotificationChannel.getImportance(); - isSingleDefaultChannel = mSingleNotificationChannel.getId() - .equals(NotificationChannel.DEFAULT_CHANNEL_ID); - } else { - mSingleNotificationChannel = null; + } else { + if (mNotificationChannels.size() == 1) { + mSingleNotificationChannel = mNotificationChannels.get(0); + isSingleDefaultChannel = mSingleNotificationChannel.getId() + .equals(NotificationChannel.DEFAULT_CHANNEL_ID); + } else { + mSingleNotificationChannel = null; + } } String appName = mPkg; @@ -248,6 +253,9 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G final TextView doneButton = (TextView) findViewById(R.id.done); doneButton.setText(R.string.notification_done); doneButton.setOnClickListener(onDoneClick); + + // Optional settings link + updateAppSettingsLink(); } private boolean hasImportanceChanged() { @@ -276,7 +284,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G private int getSelectedImportance() { if (!mChannelEnabledSwitch.isChecked()) { - return NotificationManager.IMPORTANCE_NONE; + return IMPORTANCE_NONE; } else { return mStartingUserImportance; } @@ -286,7 +294,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G // Enabled Switch mChannelEnabledSwitch = (Switch) findViewById(R.id.channel_enabled_switch); mChannelEnabledSwitch.setChecked( - mStartingUserImportance != NotificationManager.IMPORTANCE_NONE); + mStartingUserImportance != IMPORTANCE_NONE); final boolean visible = !nonBlockable && mSingleNotificationChannel != null; mChannelEnabledSwitch.setVisibility(visible ? View.VISIBLE : View.INVISIBLE); @@ -296,12 +304,13 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G mGutsContainer.resetFalsingCheck(); } updateSecondaryText(); + updateAppSettingsLink(); }); } private void updateSecondaryText() { final boolean disabled = mSingleNotificationChannel != null && - getSelectedImportance() == NotificationManager.IMPORTANCE_NONE; + getSelectedImportance() == IMPORTANCE_NONE; if (disabled) { mChannelDisabledView.setVisibility(View.VISIBLE); mNumChannelsView.setVisibility(View.GONE); @@ -311,6 +320,45 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G } } + 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) + .addCategory(Notification.INTENT_CATEGORY_NOTIFICATION_PREFERENCES) + .setPackage(packageName); + final List<ResolveInfo> resolveInfos = pm.queryIntentActivities( + intent, + PackageManager.MATCH_DEFAULT_ONLY + ); + if (resolveInfos == null || resolveInfos.size() == 0 || resolveInfos.get(0) == null) { + return null; + } + final ActivityInfo activityInfo = resolveInfos.get(0).activityInfo; + intent.setClassName(activityInfo.packageName, activityInfo.name); + if (channel != null) { + intent.putExtra(Notification.EXTRA_CHANNEL_ID, channel.getId()); + } + intent.putExtra(Notification.EXTRA_NOTIFICATION_ID, id); + intent.putExtra(Notification.EXTRA_NOTIFICATION_TAG, tag); + return intent; + } + @Override public void setGutsParent(NotificationGuts guts) { mGutsContainer = guts; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index 472af653af6e..9304de52a6be 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -48,8 +48,10 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.IntentSender; +import android.content.pm.ActivityInfo; import android.content.pm.IPackageManager; import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; import android.content.res.Configuration; import android.content.res.Resources; import android.database.ContentObserver; @@ -5701,7 +5703,7 @@ public class StatusBar extends SystemUI implements DemoMode, .findViewById(com.android.internal.R.id.media_actions) != null; } - // The (i) button in the guts that links to the system notification settings for that app + // The button in the guts that links to the system notification settings for that app private void startAppNotificationSettingsActivity(String packageName, final int appUid, final NotificationChannel channel) { final Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS); @@ -5781,10 +5783,17 @@ public class StatusBar extends SystemUI implements DemoMode, startAppNotificationSettingsActivity(pkg, appUid, channel); }; } + final NotificationInfo.OnAppSettingsClickListener onAppSettingsClick = (View v, + Intent intent) -> { + mMetricsLogger.action(MetricsEvent.ACTION_APP_NOTE_SETTINGS); + guts.resetFalsingCheck(); + startNotificationGutsIntent(intent, sbn.getUid()); + }; final View.OnClickListener onDoneClick = (View v) -> { saveAndCloseNotificationMenu(info, row, guts, v); }; - final NotificationInfo.CheckSaveListener checkSaveListener = (Runnable saveImportance) -> { + final NotificationInfo.CheckSaveListener checkSaveListener = + (Runnable saveImportance) -> { // If the user has security enabled, show challenge if the setting is changed. if (isLockscreenPublicMode(userHandle.getIdentifier()) && (mState == StatusBarState.KEYGUARD @@ -5817,7 +5826,9 @@ public class StatusBar extends SystemUI implements DemoMode, } try { info.bindNotification(pmUser, iNotificationManager, pkg, new ArrayList(channels), - onSettingsClick, onDoneClick, checkSaveListener, mNonBlockablePkgs); + row.getEntry().channel.getImportance(), sbn, onSettingsClick, + onAppSettingsClick, onDoneClick, checkSaveListener, + mNonBlockablePkgs); } catch (RemoteException e) { Log.e(TAG, e.toString()); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java index 0621f4ab8fc6..08c580bc0be9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java @@ -18,9 +18,9 @@ package com.android.systemui.statusbar; 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.Matchers.anyObject; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyBoolean; import static org.mockito.Mockito.anyInt; @@ -33,13 +33,18 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.INotificationManager; +import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationChannelGroup; import android.app.NotificationManager; +import android.content.Intent; +import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; import android.graphics.drawable.Drawable; +import android.os.UserHandle; import android.service.notification.StatusBarNotification; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; @@ -56,6 +61,8 @@ import com.android.systemui.SysuiTestCase; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; + +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -74,6 +81,7 @@ public class NotificationInfoTest extends SysuiTestCase { private final PackageManager mMockPackageManager = mock(PackageManager.class); private NotificationChannel mNotificationChannel; private NotificationChannel mDefaultNotificationChannel; + private StatusBarNotification mSbn; @Before public void setUp() throws Exception { @@ -101,6 +109,8 @@ public class NotificationInfoTest extends SysuiTestCase { mDefaultNotificationChannel = new NotificationChannel( NotificationChannel.DEFAULT_CHANNEL_ID, TEST_CHANNEL_NAME, NotificationManager.IMPORTANCE_LOW); + mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, 0, 0, + new Notification(), UserHandle.CURRENT, null, 0); } private CharSequence getStringById(int resId) { @@ -135,7 +145,9 @@ 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, Arrays.asList(mNotificationChannel), null, null, null, null); + TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), + mNotificationChannel.getImportance(), mSbn, null, null, null, + null, null); final TextView textView = (TextView) mNotificationInfo.findViewById(R.id.pkgname); assertTrue(textView.getText().toString().contains("App Name")); } @@ -146,7 +158,9 @@ public class NotificationInfoTest extends SysuiTestCase { when(mMockPackageManager.getApplicationIcon(any(ApplicationInfo.class))) .thenReturn(iconDrawable); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), null, null, null, null); + TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), + mNotificationChannel.getImportance(), mSbn, null, null, null, + null, null); final ImageView iconView = (ImageView) mNotificationInfo.findViewById(R.id.pkgicon); assertEquals(iconDrawable, iconView.getDrawable()); } @@ -154,7 +168,9 @@ public class NotificationInfoTest extends SysuiTestCase { @Test public void testBindNotification_GroupNameHiddenIfNoGroup() throws Exception { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), null, null, null, null); + 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 = @@ -171,7 +187,9 @@ public class NotificationInfoTest extends SysuiTestCase { eq("test_group_id"), eq(TEST_PACKAGE_NAME), anyInt())) .thenReturn(notificationChannelGroup); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), null, null, null, null); + 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.VISIBLE, groupNameView.getVisibility()); assertEquals("Test Group Name", groupNameView.getText()); @@ -183,7 +201,9 @@ public class NotificationInfoTest extends SysuiTestCase { @Test public void testBindNotification_SetsTextChannelName() throws Exception { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), null, null, null, null); + TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), + mNotificationChannel.getImportance(), mSbn, null, null, null, + null, null); final TextView textView = (TextView) mNotificationInfo.findViewById(R.id.channel_name); assertEquals(TEST_CHANNEL_NAME, textView.getText()); } @@ -193,10 +213,11 @@ public class NotificationInfoTest extends SysuiTestCase { final CountDownLatch latch = new CountDownLatch(1); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), + mNotificationChannel.getImportance(), mSbn, (View v, NotificationChannel c, int appUid) -> { - assertEquals(mNotificationChannel, c); - latch.countDown(); - }, null, null, null); + assertEquals(mNotificationChannel, c); + latch.countDown(); + }, null, null, null, null); final TextView settingsButton = (TextView) mNotificationInfo.findViewById(R.id.more_settings); @@ -209,7 +230,7 @@ public class NotificationInfoTest extends SysuiTestCase { public void testBindNotification_SettingsButtonInvisibleWhenNoClickListener() throws Exception { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), - null, null, null, null); + mNotificationChannel.getImportance(), mSbn, null, null, null, null, null); final TextView settingsButton = (TextView) mNotificationInfo.findViewById(R.id.more_settings); assertTrue(settingsButton.getVisibility() != View.VISIBLE); @@ -222,7 +243,8 @@ public class NotificationInfoTest extends SysuiTestCase { null, null, null, null); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), - (View v, NotificationChannel c, int appUid) -> {}, null, null, null); + mNotificationChannel.getImportance(), mSbn, + (View v, NotificationChannel c, int appUid) -> {}, null, null, null, null); final TextView settingsButton = (TextView) mNotificationInfo.findViewById(R.id.more_settings); assertEquals(View.VISIBLE, settingsButton.getVisibility()); @@ -234,10 +256,11 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel, mDefaultNotificationChannel), + mNotificationChannel.getImportance(), mSbn, (View v, NotificationChannel c, int appUid) -> { - assertEquals(null, c); - latch.countDown(); - }, null, null, null); + assertEquals(null, c); + latch.countDown(); + }, null, null, null, null); final TextView settingsButton = (TextView) mNotificationInfo.findViewById(R.id.more_settings); @@ -250,7 +273,9 @@ public class NotificationInfoTest extends SysuiTestCase { public void testBindNotification_SettingsTextWithOneChannel() throws Exception { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), - (View v, NotificationChannel c, int appUid) -> {}, null, null, null); + 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()); @@ -262,7 +287,9 @@ public class NotificationInfoTest extends SysuiTestCase { eq(TEST_PACKAGE_NAME), anyInt(), anyBoolean())).thenReturn(2); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), - (View v, NotificationChannel c, int appUid) -> {}, null, null, null); + 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()); @@ -272,8 +299,11 @@ public class NotificationInfoTest extends SysuiTestCase { public void testBindNotification_SetsOnClickListenerForDone() throws Exception { final CountDownLatch latch = new CountDownLatch(1); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), null, - (View v) -> { latch.countDown(); }, + 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); @@ -286,7 +316,8 @@ public class NotificationInfoTest extends SysuiTestCase { public void testBindNotification_NumChannelsTextUniqueWhenDefaultChannel() throws Exception { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, Arrays.asList(mDefaultNotificationChannel), - null, null, null, null); + mNotificationChannel.getImportance(), mSbn, null, null, + null, null, null); final TextView numChannelsView = (TextView) mNotificationInfo.findViewById(R.id.num_channels_desc); assertEquals(View.VISIBLE, numChannelsView.getVisibility()); @@ -298,7 +329,9 @@ public class NotificationInfoTest extends SysuiTestCase { public void testBindNotification_NumChannelsTextDisplaysWhenNotDefaultChannel() throws Exception { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), null, null, null, null); + 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); @@ -311,7 +344,9 @@ public class NotificationInfoTest extends SysuiTestCase { when(mMockINotificationManager.getNumNotificationChannelsForPackage( eq(TEST_PACKAGE_NAME), anyInt(), anyBoolean())).thenReturn(2); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), null, null, null, null); + 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()); @@ -323,7 +358,7 @@ public class NotificationInfoTest extends SysuiTestCase { throws Exception { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel, mDefaultNotificationChannel), - null, null, null, null); + mNotificationChannel.getImportance(), mSbn, null, null, null, null, null); final TextView numChannelsView = (TextView) mNotificationInfo.findViewById(R.id.num_channels_desc); assertEquals(getChannelsListDescString(mNotificationChannel, mDefaultNotificationChannel), @@ -339,7 +374,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel, mDefaultNotificationChannel, thirdChannel), - null, null, null, null); + mNotificationChannel.getImportance(), mSbn, null, null, null, null, null); final TextView numChannelsView = (TextView) mNotificationInfo.findViewById(R.id.num_channels_desc); assertEquals( @@ -359,8 +394,8 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel, mDefaultNotificationChannel, thirdChannel, - fourthChannel), - null, null, null, null); + fourthChannel), mNotificationChannel.getImportance(), mSbn, null, null, + null, null, null); final TextView numChannelsView = (TextView) mNotificationInfo.findViewById(R.id.num_channels_desc); assertEquals( @@ -375,7 +410,7 @@ public class NotificationInfoTest extends SysuiTestCase { throws Exception { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel, mDefaultNotificationChannel), - null, null, null, null); + mNotificationChannel.getImportance(), mSbn, null, null, null, null, null); final TextView channelNameView = (TextView) mNotificationInfo.findViewById(R.id.channel_name); assertEquals(getNumChannelsString(2), channelNameView.getText()); @@ -386,7 +421,7 @@ public class NotificationInfoTest extends SysuiTestCase { public void testEnabledSwitchInvisibleIfBundleFromDifferentChannels() throws Exception { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel, mDefaultNotificationChannel), - null, null, null, null); + mNotificationChannel.getImportance(), mSbn, null, null, null, null, null); Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch); assertEquals(View.INVISIBLE, enabledSwitch.getVisibility()); } @@ -394,7 +429,8 @@ public class NotificationInfoTest extends SysuiTestCase { @Test public void testbindNotification_ChannelDisabledTextGoneWhenNotDisabled() throws Exception { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), null, null, null, null); + 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); @@ -404,7 +440,9 @@ public class NotificationInfoTest extends SysuiTestCase { public void testbindNotification_ChannelDisabledTextVisibleWhenDisabled() throws Exception { mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_NONE); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), null, null, null, null); + 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); @@ -421,7 +459,8 @@ public class NotificationInfoTest extends SysuiTestCase { mDefaultNotificationChannel.setImportance(NotificationManager.IMPORTANCE_NONE); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, Arrays.asList(mDefaultNotificationChannel), - null, null, null, null); + mDefaultNotificationChannel.getImportance(), mSbn, null, null, + null, null, null); final TextView channelDisabledView = (TextView) mNotificationInfo.findViewById(R.id.channel_disabled); assertEquals(View.VISIBLE, channelDisabledView.getVisibility()); @@ -430,7 +469,9 @@ public class NotificationInfoTest extends SysuiTestCase { @Test public void testBindNotification_DoesNotUpdateNotificationChannel() throws Exception { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), null, null, null, null); + TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), + mNotificationChannel.getImportance(), mSbn, null, null, null, + null, null); verify(mMockINotificationManager, never()).updateNotificationChannelForPackage( anyString(), anyInt(), any()); } @@ -439,7 +480,9 @@ public class NotificationInfoTest extends SysuiTestCase { public void testDoesNotUpdateNotificationChannelAfterImportanceChanged() throws Exception { mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), null, null, null, null); + TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), + mNotificationChannel.getImportance(), mSbn, null, null, null, + null, null); Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch); enabledSwitch.setChecked(false); @@ -451,7 +494,9 @@ public class NotificationInfoTest extends SysuiTestCase { public void testHandleCloseControls_DoesNotUpdateNotificationChannelIfUnchanged() throws Exception { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), null, null, null, null); + TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), + mNotificationChannel.getImportance(), mSbn, null, null, null, + null, null); mNotificationInfo.handleCloseControls(true); verify(mMockINotificationManager, never()).updateNotificationChannelForPackage( @@ -463,7 +508,9 @@ public class NotificationInfoTest extends SysuiTestCase { throws Exception { mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_UNSPECIFIED); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), null, null, null, null); + TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), + mNotificationChannel.getImportance(), mSbn, null, null, null, + null, null); mNotificationInfo.handleCloseControls(true); verify(mMockINotificationManager, never()).updateNotificationChannelForPackage( @@ -474,7 +521,9 @@ public class NotificationInfoTest extends SysuiTestCase { public void testEnabledSwitchOnByDefault() throws Exception { mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), null, null, null, null); + 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()); @@ -484,7 +533,9 @@ public class NotificationInfoTest extends SysuiTestCase { public void testEnabledButtonOffWhenAlreadyBanned() throws Exception { mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_NONE); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), null, null, null, null); + 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()); @@ -494,7 +545,9 @@ public class NotificationInfoTest extends SysuiTestCase { public void testEnabledSwitchVisibleByDefault() throws Exception { mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), null, null, null, null); + 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()); @@ -504,8 +557,9 @@ public class NotificationInfoTest extends SysuiTestCase { public void testEnabledSwitchInvisibleIfNonBlockable() throws Exception { mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), null, null, null, - Collections.singleton(TEST_PACKAGE_NAME)); + 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()); @@ -515,8 +569,9 @@ public class NotificationInfoTest extends SysuiTestCase { public void testNonBlockableAppDoesNotBecomeBlocked() throws Exception { mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), null, null, null, - Collections.singleton(TEST_PACKAGE_NAME)); + TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), + mNotificationChannel.getImportance(), mSbn, null, null, null, + null, Collections.singleton(TEST_PACKAGE_NAME)); mNotificationInfo.handleCloseControls(true); verify(mMockINotificationManager, never()).updateNotificationChannelForPackage( anyString(), anyInt(), any()); @@ -526,8 +581,9 @@ public class NotificationInfoTest extends SysuiTestCase { public void testEnabledSwitchChangedCallsUpdateNotificationChannel() throws Exception { mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), null, null, null, - Collections.singleton(TEST_PACKAGE_NAME)); + 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); enabledSwitch.setChecked(false); @@ -540,8 +596,9 @@ public class NotificationInfoTest extends SysuiTestCase { public void testCloseControlsDoesNotUpdateIfSaveIsFalse() throws Exception { mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), null, null, null, - Collections.singleton(TEST_PACKAGE_NAME)); + 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); enabledSwitch.setChecked(false); @@ -554,8 +611,10 @@ public class NotificationInfoTest extends SysuiTestCase { public void testCloseControlsDoesNotUpdateIfCheckSaveListenerIsNoOp() throws Exception { mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), null, null, - (Runnable saveImportance) -> {}, + TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), + mNotificationChannel.getImportance(), mSbn, null, null, null, + (Runnable saveImportance) -> { + }, Collections.singleton(TEST_PACKAGE_NAME)); Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch); @@ -569,8 +628,11 @@ public class NotificationInfoTest extends SysuiTestCase { public void testCloseControlsUpdatesWhenCheckSaveListenerUsesCallback() throws Exception { mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), null, null, - (Runnable saveImportance) -> { saveImportance.run(); }, + TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), + mNotificationChannel.getImportance(), mSbn, null, null, null, + (Runnable saveImportance) -> { + saveImportance.run(); + }, Collections.singleton(TEST_PACKAGE_NAME)); Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch); @@ -579,4 +641,137 @@ public class NotificationInfoTest extends SysuiTestCase { verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage( eq(TEST_PACKAGE_NAME), anyInt(), eq(mNotificationChannel)); } + + @Test + public void testDisplaySettingsLink() throws Exception { + final CountDownLatch latch = new CountDownLatch(1); + 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, + (View v, Intent intent) -> { + latch.countDown(); + }, 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()); + } + + @Test + public void testDisplaySettingsLink_multipleChannels() throws Exception { + final CountDownLatch latch = new CountDownLatch(1); + 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, mDefaultNotificationChannel), + mNotificationChannel.getImportance(), sbn, null, (View v, Intent intent) -> { + latch.countDown(); + }, null, null, null); + final TextView settingsLink = mNotificationInfo.findViewById(R.id.app_settings); + assertEquals(View.VISIBLE, settingsLink.getVisibility()); + settingsLink.performClick(); + assertEquals(0, latch.getCount()); + } + + @Test + public void testNoSettingsLink_noHandlingActivity() throws Exception { + final String settingsText = "work chats"; + when(mMockPackageManager.queryIntentActivities(any(), anyInt())).thenReturn(null); + 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.GONE, settingsLink.getVisibility()); + } + + @Test + public void testNoSettingsLink_noLinkText() throws Exception { + 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()).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.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()); + } } |