Merge "Allow some system notifications to be blocked." into oc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
3a2ac3e11b
@@ -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 +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user