Merge "Allow some system notifications to be blocked." into oc-dev

This commit is contained in:
Julia Reynolds
2017-05-26 14:39:26 +00:00
committed by Android (Google) Code Review
6 changed files with 136 additions and 9 deletions

View File

@@ -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.
*/
@@ -546,6 +555,13 @@ public final class NotificationChannel implements Parcelable {
return mUserLockedFields;
}
/**
* @hide
*/
public boolean isBlockableSystem() {
return mBlockableSystem;
}
/**
* @hide
*/
@@ -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 +
'}';
}
}

View File

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

View File

@@ -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(
@@ -604,6 +614,45 @@ public class NotificationInfoTest extends SysuiTestCase {
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);

View File

@@ -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();

View File

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

View File

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