diff options
| author | 2017-05-26 14:39:26 +0000 | |
|---|---|---|
| committer | 2017-05-26 14:39:30 +0000 | |
| commit | 3a2ac3e11b336deb272e733dbdfc08317ce78b31 (patch) | |
| tree | e4b709a12dfc5f6f468e964de1711a4fa3463d8a | |
| parent | 03a243889c52cb24d2c80777f3da4653495357a3 (diff) | |
| parent | f732159cf8d6a4e1cd17542a3a2cf020ad6919a3 (diff) | |
Merge "Allow some system notifications to be blocked." into oc-dev
6 files changed, 136 insertions, 9 deletions
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java index bc7fcf55d0a3..c076e5e3c117 100644 --- a/core/java/android/app/NotificationChannel.java +++ b/core/java/android/app/NotificationChannel.java @@ -71,6 +71,7 @@ public final class NotificationChannel implements Parcelable { private static final String ATT_SHOW_BADGE = "show_badge"; private static final String ATT_USER_LOCKED = "locked"; private static final String ATT_GROUP = "group"; + private static final String ATT_BLOCKABLE_SYSTEM = "blockable_system"; private static final String DELIMITER = ","; /** @@ -140,6 +141,7 @@ public final class NotificationChannel implements Parcelable { private boolean mDeleted = DEFAULT_DELETED; private String mGroup; private AudioAttributes mAudioAttributes = Notification.AUDIO_ATTRIBUTES_DEFAULT; + private boolean mBlockableSystem = false; /** * Creates a notification channel. @@ -199,6 +201,7 @@ public final class NotificationChannel implements Parcelable { } mAudioAttributes = in.readInt() > 0 ? AudioAttributes.CREATOR.createFromParcel(in) : null; mLightColor = in.readInt(); + mBlockableSystem = in.readBoolean(); } @Override @@ -249,6 +252,7 @@ public final class NotificationChannel implements Parcelable { dest.writeInt(0); } dest.writeInt(mLightColor); + dest.writeBoolean(mBlockableSystem); } /** @@ -272,6 +276,12 @@ public final class NotificationChannel implements Parcelable { mDeleted = deleted; } + /** + * @hide + */ + public void setBlockableSystem(boolean blockableSystem) { + mBlockableSystem = blockableSystem; + } // Modifiable by apps post channel creation /** @@ -421,7 +431,6 @@ public final class NotificationChannel implements Parcelable { this.mLockscreenVisibility = lockscreenVisibility; } - /** * Returns the id of this channel. */ @@ -549,6 +558,13 @@ public final class NotificationChannel implements Parcelable { /** * @hide */ + public boolean isBlockableSystem() { + return mBlockableSystem; + } + + /** + * @hide + */ @SystemApi public void populateFromXml(XmlPullParser parser) { // Name, id, and importance are set in the constructor. @@ -565,6 +581,7 @@ public final class NotificationChannel implements Parcelable { setDeleted(safeBool(parser, ATT_DELETED, false)); setGroup(parser.getAttributeValue(null, ATT_GROUP)); lockFields(safeInt(parser, ATT_USER_LOCKED, 0)); + setBlockableSystem(safeBool(parser, ATT_BLOCKABLE_SYSTEM, false)); } /** @@ -625,6 +642,9 @@ public final class NotificationChannel implements Parcelable { if (getGroup() != null) { out.attribute(null, ATT_GROUP, getGroup()); } + if (isBlockableSystem()) { + out.attribute(null, ATT_BLOCKABLE_SYSTEM, Boolean.toString(isBlockableSystem())); + } out.endTag(null, TAG_CHANNEL); } @@ -665,6 +685,7 @@ public final class NotificationChannel implements Parcelable { record.put(ATT_SHOW_BADGE, Boolean.toString(canShowBadge())); record.put(ATT_DELETED, Boolean.toString(isDeleted())); record.put(ATT_GROUP, getGroup()); + record.put(ATT_BLOCKABLE_SYSTEM, isBlockableSystem()); return record; } @@ -764,6 +785,7 @@ public final class NotificationChannel implements Parcelable { if (mVibrationEnabled != that.mVibrationEnabled) return false; if (mShowBadge != that.mShowBadge) return false; if (isDeleted() != that.isDeleted()) return false; + if (isBlockableSystem() != that.isBlockableSystem()) return false; if (getId() != null ? !getId().equals(that.getId()) : that.getId() != null) return false; if (getName() != null ? !getName().equals(that.getName()) : that.getName() != null) { return false; @@ -802,6 +824,7 @@ public final class NotificationChannel implements Parcelable { result = 31 * result + (isDeleted() ? 1 : 0); result = 31 * result + (getGroup() != null ? getGroup().hashCode() : 0); result = 31 * result + (getAudioAttributes() != null ? getAudioAttributes().hashCode() : 0); + result = 31 * result + (isBlockableSystem() ? 1 : 0); return result; } @@ -824,6 +847,7 @@ public final class NotificationChannel implements Parcelable { ", mDeleted=" + mDeleted + ", mGroup='" + mGroup + '\'' + ", mAudioAttributes=" + mAudioAttributes + + ", mBlockableSystem=" + mBlockableSystem + '}'; } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java index 7062216ad771..427708b02fbf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java @@ -221,7 +221,9 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G boolean nonBlockable = false; try { final PackageInfo pkgInfo = pm.getPackageInfo(pkg, PackageManager.GET_SIGNATURES); - nonBlockable = Utils.isSystemPackage(getResources(), pm, pkgInfo); + nonBlockable = Utils.isSystemPackage(getResources(), pm, pkgInfo) + && (mSingleNotificationChannel == null + || !mSingleNotificationChannel.isBlockableSystem()); } catch (PackageManager.NameNotFoundException e) { // unlikely. } 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 c7d5e68b93dd..638084763ea8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java @@ -16,6 +16,8 @@ package com.android.systemui.statusbar; +import static android.print.PrintManager.PRINT_SPOOLER_PACKAGE_NAME; + import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertNull; @@ -74,6 +76,7 @@ import java.util.concurrent.CountDownLatch; @UiThreadTest public class NotificationInfoTest extends SysuiTestCase { private static final String TEST_PACKAGE_NAME = "test_package"; + private static final String TEST_SYSTEM_PACKAGE_NAME = PRINT_SPOOLER_PACKAGE_NAME; private static final int TEST_UID = 1; private static final String TEST_CHANNEL = "test_channel"; private static final String TEST_CHANNEL_NAME = "TEST CHANNEL NAME"; @@ -95,11 +98,18 @@ public class NotificationInfoTest extends SysuiTestCase { // PackageManager must return a packageInfo and applicationInfo. final PackageInfo packageInfo = new PackageInfo(); packageInfo.packageName = TEST_PACKAGE_NAME; - when(mMockPackageManager.getPackageInfo(anyString(), anyInt())).thenReturn(packageInfo); + when(mMockPackageManager.getPackageInfo(eq(TEST_PACKAGE_NAME), anyInt())) + .thenReturn(packageInfo); final ApplicationInfo applicationInfo = new ApplicationInfo(); applicationInfo.uid = TEST_UID; // non-zero when(mMockPackageManager.getApplicationInfo(anyString(), anyInt())).thenReturn( applicationInfo); + final PackageInfo systemPackageInfo = new PackageInfo(); + systemPackageInfo.packageName = TEST_SYSTEM_PACKAGE_NAME; + when(mMockPackageManager.getPackageInfo(eq(TEST_SYSTEM_PACKAGE_NAME), anyInt())) + .thenReturn(systemPackageInfo); + when(mMockPackageManager.getPackageInfo(eq("android"), anyInt())) + .thenReturn(packageInfo); // Package has one channel by default. when(mMockINotificationManager.getNumNotificationChannelsForPackage( @@ -605,6 +615,45 @@ public class NotificationInfoTest extends SysuiTestCase { } @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); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java index 7a7bcede630e..4c3efce3be5c 100644 --- a/services/core/java/com/android/server/notification/RankingHelper.java +++ b/services/core/java/com/android/server/notification/RankingHelper.java @@ -551,7 +551,7 @@ public class RankingHelper implements RankingConfig { } NotificationChannel existing = r.channels.get(channel.getId()); - // Keep existing settings, except deleted status and name + // Keep most of the existing settings if (existing != null && fromTargetApp) { if (existing.isDeleted()) { existing.setDeleted(false); @@ -559,6 +559,7 @@ public class RankingHelper implements RankingConfig { existing.setName(channel.getName().toString()); existing.setDescription(channel.getDescription()); + existing.setBlockableSystem(channel.isBlockableSystem()); MetricsLogger.action(getChannelLog(channel, pkg)); updateConfig(); diff --git a/services/core/java/com/android/server/wm/AlertWindowNotification.java b/services/core/java/com/android/server/wm/AlertWindowNotification.java index 7ed3eac10d11..972623c9478d 100644 --- a/services/core/java/com/android/server/wm/AlertWindowNotification.java +++ b/services/core/java/com/android/server/wm/AlertWindowNotification.java @@ -100,7 +100,7 @@ class AlertWindowNotification { final String appName = (aInfo != null) ? pm.getApplicationLabel(aInfo).toString() : mPackageName; - createNotificationChannelIfNeeded(context, appName); + createNotificationChannel(context, appName); final String message = context.getString(R.string.alert_windows_notification_message, appName); @@ -134,16 +134,14 @@ class AlertWindowNotification { return PendingIntent.getActivity(context, mRequestCode, intent, FLAG_CANCEL_CURRENT); } - private void createNotificationChannelIfNeeded(Context context, String appName) { - if (mNotificationManager.getNotificationChannel(mNotificationTag) != null) { - return; - } + private void createNotificationChannel(Context context, String appName) { final String nameChannel = context.getString(R.string.alert_windows_notification_channel_name, appName); final NotificationChannel channel = new NotificationChannel(mNotificationTag, nameChannel, IMPORTANCE_MIN); channel.enableLights(false); channel.enableVibration(false); + channel.setBlockableSystem(true); mNotificationManager.createNotificationChannel(channel); } diff --git a/services/tests/notification/src/com/android/server/notification/NotificationChannelTest.java b/services/tests/notification/src/com/android/server/notification/NotificationChannelTest.java new file mode 100644 index 000000000000..3007cb1755e2 --- /dev/null +++ b/services/tests/notification/src/com/android/server/notification/NotificationChannelTest.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.notification; + +import static android.app.NotificationManager.IMPORTANCE_DEFAULT; + +import static junit.framework.Assert.assertEquals; + +import android.app.NotificationChannel; +import android.os.Parcel; +import android.support.test.runner.AndroidJUnit4; +import android.test.suitebuilder.annotation.SmallTest; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@SmallTest +@RunWith(AndroidJUnit4.class) +public class NotificationChannelTest extends NotificationTestCase { + + @Test + public void testWriteToParcel() { + NotificationChannel channel = + new NotificationChannel("1", "one", IMPORTANCE_DEFAULT); + Parcel parcel = Parcel.obtain(); + channel.writeToParcel(parcel, 0); + parcel.setDataPosition(0); + NotificationChannel channel1 = NotificationChannel.CREATOR.createFromParcel(parcel); + assertEquals(channel, channel1); + } + + @Test + public void testSystemBlockable() { + NotificationChannel channel = new NotificationChannel("a", "ab", IMPORTANCE_DEFAULT); + assertEquals(false, channel.isBlockableSystem()); + channel.setBlockableSystem(true); + assertEquals(true, channel.isBlockableSystem()); + } +} |