Merge changes from topic "presubmit-am-cbc3dc3a1fb64fea92fed20dc6a3f23e" into tm-mainline-prod
* changes:
[automerge] Allow registered call notifications to always appear 2p: 20a47d5ed0
Allow registered call notifications to always appear
This commit is contained in:
committed by
Android (Google) Code Review
commit
117aa0eb9f
@@ -57,6 +57,7 @@ interface INotificationManager
|
|||||||
@UnsupportedAppUsage
|
@UnsupportedAppUsage
|
||||||
void cancelNotificationWithTag(String pkg, String opPkg, String tag, int id, int userId);
|
void cancelNotificationWithTag(String pkg, String opPkg, String tag, int id, int userId);
|
||||||
|
|
||||||
|
boolean isInCall(String pkg, int uid);
|
||||||
void setShowBadge(String pkg, int uid, boolean showBadge);
|
void setShowBadge(String pkg, int uid, boolean showBadge);
|
||||||
boolean canShowBadge(String pkg, int uid);
|
boolean canShowBadge(String pkg, int uid);
|
||||||
boolean hasSentValidMsg(String pkg, int uid);
|
boolean hasSentValidMsg(String pkg, int uid);
|
||||||
|
|||||||
@@ -224,6 +224,7 @@
|
|||||||
<uses-permission android:name="android.permission.MANAGE_NOTIFICATIONS" />
|
<uses-permission android:name="android.permission.MANAGE_NOTIFICATIONS" />
|
||||||
<uses-permission android:name="android.permission.GET_RUNTIME_PERMISSIONS" />
|
<uses-permission android:name="android.permission.GET_RUNTIME_PERMISSIONS" />
|
||||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||||
|
<uses-permission android:name="android.permission.MANAGE_ROLE_HOLDERS" />
|
||||||
|
|
||||||
<!-- It's like, reality, but, you know, virtual -->
|
<!-- It's like, reality, but, you know, virtual -->
|
||||||
<uses-permission android:name="android.permission.ACCESS_VR_MANAGER" />
|
<uses-permission android:name="android.permission.ACCESS_VR_MANAGER" />
|
||||||
|
|||||||
@@ -135,6 +135,15 @@ asked for it -->
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
style="@*android:style/TextAppearance.DeviceDefault.Notification" />
|
style="@*android:style/TextAppearance.DeviceDefault.Notification" />
|
||||||
|
|
||||||
|
<!-- Non configurable app/channel text. appears instead of @+id/interruptiveness_settings-->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/non_configurable_call_text"
|
||||||
|
android:text="@string/notification_unblockable_call_desc"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="@*android:style/TextAppearance.DeviceDefault.Notification" />
|
||||||
|
|
||||||
<!-- Non configurable multichannel text. appears instead of @+id/interruptiveness_settings-->
|
<!-- Non configurable multichannel text. appears instead of @+id/interruptiveness_settings-->
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/non_configurable_multichannel_text"
|
android:id="@+id/non_configurable_multichannel_text"
|
||||||
|
|||||||
@@ -1373,6 +1373,9 @@
|
|||||||
<!-- Notification: Control panel: Label that displays when the app's notifications cannot be blocked. -->
|
<!-- Notification: Control panel: Label that displays when the app's notifications cannot be blocked. -->
|
||||||
<string name="notification_unblockable_desc">These notifications can\'t be modified.</string>
|
<string name="notification_unblockable_desc">These notifications can\'t be modified.</string>
|
||||||
|
|
||||||
|
<!-- Notification: Control panel: Label that displays when a notification cannot be blocked because it's attached to a phone/voip call. -->
|
||||||
|
<string name="notification_unblockable_call_desc">Call notifications can\'t be modified.</string>
|
||||||
|
|
||||||
<!-- Notification: Control panel: label that displays when viewing settings for a group of notifications posted to multiple channels. -->
|
<!-- Notification: Control panel: label that displays when viewing settings for a group of notifications posted to multiple channels. -->
|
||||||
<string name="notification_multichannel_desc">This group of notifications cannot be configured here</string>
|
<string name="notification_multichannel_desc">This group of notifications cannot be configured here</string>
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import android.annotation.Nullable;
|
|||||||
import android.app.INotificationManager;
|
import android.app.INotificationManager;
|
||||||
import android.app.Notification;
|
import android.app.Notification;
|
||||||
import android.app.NotificationChannel;
|
import android.app.NotificationChannel;
|
||||||
|
import android.app.role.RoleManager;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.pm.PackageInfo;
|
import android.content.pm.PackageInfo;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
@@ -380,12 +381,22 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
|||||||
Settings.Secure.NOTIFICATION_PERMISSION_ENABLED, 0, USER_SYSTEM) == 1) {
|
Settings.Secure.NOTIFICATION_PERMISSION_ENABLED, 0, USER_SYSTEM) == 1) {
|
||||||
INotificationManager iNm = INotificationManager.Stub.asInterface(
|
INotificationManager iNm = INotificationManager.Stub.asInterface(
|
||||||
ServiceManager.getService(Context.NOTIFICATION_SERVICE));
|
ServiceManager.getService(Context.NOTIFICATION_SERVICE));
|
||||||
|
|
||||||
|
boolean isSystem = false;
|
||||||
try {
|
try {
|
||||||
return iNm.isPermissionFixed(sbn.getPackageName(), sbn.getUserId());
|
isSystem = iNm.isPermissionFixed(sbn.getPackageName(), sbn.getUserId());
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "cannot reach NMS");
|
Log.e(TAG, "cannot reach NMS");
|
||||||
}
|
}
|
||||||
return false;
|
RoleManager rm = context.getSystemService(RoleManager.class);
|
||||||
|
List<String> fixedRoleHolders = new ArrayList<>();
|
||||||
|
fixedRoleHolders.addAll(rm.getRoleHolders(RoleManager.ROLE_DIALER));
|
||||||
|
fixedRoleHolders.addAll(rm.getRoleHolders(RoleManager.ROLE_EMERGENCY));
|
||||||
|
if (fixedRoleHolders.contains(sbn.getPackageName())) {
|
||||||
|
isSystem = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return isSystem;
|
||||||
} else {
|
} else {
|
||||||
PackageManager packageManager = CentralSurfaces.getPackageManagerForUser(
|
PackageManager packageManager = CentralSurfaces.getPackageManagerForUser(
|
||||||
context, sbn.getUser().getIdentifier());
|
context, sbn.getUser().getIdentifier());
|
||||||
|
|||||||
@@ -124,6 +124,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
|
|||||||
private NotificationEntry mEntry;
|
private NotificationEntry mEntry;
|
||||||
private StatusBarNotification mSbn;
|
private StatusBarNotification mSbn;
|
||||||
private boolean mIsDeviceProvisioned;
|
private boolean mIsDeviceProvisioned;
|
||||||
|
private boolean mIsSystemRegisteredCall;
|
||||||
|
|
||||||
private OnSettingsClickListener mOnSettingsClickListener;
|
private OnSettingsClickListener mOnSettingsClickListener;
|
||||||
private OnAppSettingsClickListener mAppSettingsClickListener;
|
private OnAppSettingsClickListener mAppSettingsClickListener;
|
||||||
@@ -229,6 +230,9 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
|
|||||||
mShowAutomaticSetting = mAssistantFeedbackController.isFeedbackEnabled();
|
mShowAutomaticSetting = mAssistantFeedbackController.isFeedbackEnabled();
|
||||||
mUiEventLogger = uiEventLogger;
|
mUiEventLogger = uiEventLogger;
|
||||||
|
|
||||||
|
mIsSystemRegisteredCall = mSbn.getNotification().isStyle(Notification.CallStyle.class)
|
||||||
|
&& mINotificationManager.isInCall(mSbn.getPackageName(), mSbn.getUid());
|
||||||
|
|
||||||
int numTotalChannels = mINotificationManager.getNumNotificationChannelsForPackage(
|
int numTotalChannels = mINotificationManager.getNumNotificationChannelsForPackage(
|
||||||
pkg, mAppUid, false /* includeDeleted */);
|
pkg, mAppUid, false /* includeDeleted */);
|
||||||
if (mNumUniqueChannelsInRow == 0) {
|
if (mNumUniqueChannelsInRow == 0) {
|
||||||
@@ -252,17 +256,27 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void bindInlineControls() {
|
private void bindInlineControls() {
|
||||||
if (mIsNonblockable) {
|
if (mIsSystemRegisteredCall) {
|
||||||
|
findViewById(R.id.non_configurable_call_text).setVisibility(VISIBLE);
|
||||||
|
findViewById(R.id.non_configurable_text).setVisibility(GONE);
|
||||||
|
findViewById(R.id.non_configurable_multichannel_text).setVisibility(GONE);
|
||||||
|
findViewById(R.id.interruptiveness_settings).setVisibility(GONE);
|
||||||
|
((TextView) findViewById(R.id.done)).setText(R.string.inline_done_button);
|
||||||
|
findViewById(R.id.turn_off_notifications).setVisibility(GONE);
|
||||||
|
} else if (mIsNonblockable) {
|
||||||
findViewById(R.id.non_configurable_text).setVisibility(VISIBLE);
|
findViewById(R.id.non_configurable_text).setVisibility(VISIBLE);
|
||||||
|
findViewById(R.id.non_configurable_call_text).setVisibility(GONE);
|
||||||
findViewById(R.id.non_configurable_multichannel_text).setVisibility(GONE);
|
findViewById(R.id.non_configurable_multichannel_text).setVisibility(GONE);
|
||||||
findViewById(R.id.interruptiveness_settings).setVisibility(GONE);
|
findViewById(R.id.interruptiveness_settings).setVisibility(GONE);
|
||||||
((TextView) findViewById(R.id.done)).setText(R.string.inline_done_button);
|
((TextView) findViewById(R.id.done)).setText(R.string.inline_done_button);
|
||||||
findViewById(R.id.turn_off_notifications).setVisibility(GONE);
|
findViewById(R.id.turn_off_notifications).setVisibility(GONE);
|
||||||
} else if (mNumUniqueChannelsInRow > 1) {
|
} else if (mNumUniqueChannelsInRow > 1) {
|
||||||
|
findViewById(R.id.non_configurable_call_text).setVisibility(GONE);
|
||||||
findViewById(R.id.non_configurable_text).setVisibility(GONE);
|
findViewById(R.id.non_configurable_text).setVisibility(GONE);
|
||||||
findViewById(R.id.interruptiveness_settings).setVisibility(GONE);
|
findViewById(R.id.interruptiveness_settings).setVisibility(GONE);
|
||||||
findViewById(R.id.non_configurable_multichannel_text).setVisibility(VISIBLE);
|
findViewById(R.id.non_configurable_multichannel_text).setVisibility(VISIBLE);
|
||||||
} else {
|
} else {
|
||||||
|
findViewById(R.id.non_configurable_call_text).setVisibility(GONE);
|
||||||
findViewById(R.id.non_configurable_text).setVisibility(GONE);
|
findViewById(R.id.non_configurable_text).setVisibility(GONE);
|
||||||
findViewById(R.id.non_configurable_multichannel_text).setVisibility(GONE);
|
findViewById(R.id.non_configurable_multichannel_text).setVisibility(GONE);
|
||||||
findViewById(R.id.interruptiveness_settings).setVisibility(VISIBLE);
|
findViewById(R.id.interruptiveness_settings).setVisibility(VISIBLE);
|
||||||
|
|||||||
@@ -44,12 +44,15 @@ import android.app.INotificationManager;
|
|||||||
import android.app.Notification;
|
import android.app.Notification;
|
||||||
import android.app.NotificationChannel;
|
import android.app.NotificationChannel;
|
||||||
import android.app.NotificationChannelGroup;
|
import android.app.NotificationChannelGroup;
|
||||||
|
import android.app.PendingIntent;
|
||||||
|
import android.app.Person;
|
||||||
import android.content.pm.ApplicationInfo;
|
import android.content.pm.ApplicationInfo;
|
||||||
import android.content.pm.PackageInfo;
|
import android.content.pm.PackageInfo;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.service.notification.StatusBarNotification;
|
import android.service.notification.StatusBarNotification;
|
||||||
|
import android.telecom.TelecomManager;
|
||||||
import android.test.suitebuilder.annotation.SmallTest;
|
import android.test.suitebuilder.annotation.SmallTest;
|
||||||
import android.testing.AndroidTestingRunner;
|
import android.testing.AndroidTestingRunner;
|
||||||
import android.testing.TestableLooper;
|
import android.testing.TestableLooper;
|
||||||
@@ -116,11 +119,15 @@ public class NotificationInfoTest extends SysuiTestCase {
|
|||||||
private ChannelEditorDialogController mChannelEditorDialogController;
|
private ChannelEditorDialogController mChannelEditorDialogController;
|
||||||
@Mock
|
@Mock
|
||||||
private AssistantFeedbackController mAssistantFeedbackController;
|
private AssistantFeedbackController mAssistantFeedbackController;
|
||||||
|
@Mock
|
||||||
|
private TelecomManager mTelecomManager;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
mTestableLooper = TestableLooper.get(this);
|
mTestableLooper = TestableLooper.get(this);
|
||||||
|
|
||||||
|
mContext.addMockSystemService(TelecomManager.class, mTelecomManager);
|
||||||
|
|
||||||
mDependency.injectTestDependency(Dependency.BG_LOOPER, mTestableLooper.getLooper());
|
mDependency.injectTestDependency(Dependency.BG_LOOPER, mTestableLooper.getLooper());
|
||||||
mDependency.injectTestDependency(MetricsLogger.class, mMetricsLogger);
|
mDependency.injectTestDependency(MetricsLogger.class, mMetricsLogger);
|
||||||
// Inflate the layout
|
// Inflate the layout
|
||||||
@@ -161,7 +168,7 @@ public class NotificationInfoTest extends SysuiTestCase {
|
|||||||
IMPORTANCE_LOW);
|
IMPORTANCE_LOW);
|
||||||
mDefaultNotificationChannelSet.add(mDefaultNotificationChannel);
|
mDefaultNotificationChannelSet.add(mDefaultNotificationChannel);
|
||||||
mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID, 0,
|
mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID, 0,
|
||||||
new Notification(), UserHandle.CURRENT, null, 0);
|
new Notification(), UserHandle.getUserHandleForUid(TEST_UID), null, 0);
|
||||||
mEntry = new NotificationEntryBuilder().setSbn(mSbn).build();
|
mEntry = new NotificationEntryBuilder().setSbn(mSbn).build();
|
||||||
when(mAssistantFeedbackController.isFeedbackEnabled()).thenReturn(false);
|
when(mAssistantFeedbackController.isFeedbackEnabled()).thenReturn(false);
|
||||||
when(mAssistantFeedbackController.getInlineDescriptionResource(any()))
|
when(mAssistantFeedbackController.getInlineDescriptionResource(any()))
|
||||||
@@ -631,6 +638,92 @@ public class NotificationInfoTest extends SysuiTestCase {
|
|||||||
mNotificationInfo.findViewById(R.id.interruptiveness_settings).getVisibility());
|
mNotificationInfo.findViewById(R.id.interruptiveness_settings).getVisibility());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBindNotification_whenCurrentlyInCall() throws Exception {
|
||||||
|
when(mMockINotificationManager.isInCall(anyString(), anyInt())).thenReturn(true);
|
||||||
|
|
||||||
|
Person person = new Person.Builder()
|
||||||
|
.setName("caller")
|
||||||
|
.build();
|
||||||
|
Notification.Builder nb = new Notification.Builder(
|
||||||
|
mContext, mNotificationChannel.getId())
|
||||||
|
.setContentTitle("foo")
|
||||||
|
.setSmallIcon(android.R.drawable.sym_def_app_icon)
|
||||||
|
.setStyle(Notification.CallStyle.forOngoingCall(
|
||||||
|
person, mock(PendingIntent.class)))
|
||||||
|
.setFullScreenIntent(mock(PendingIntent.class), true)
|
||||||
|
.addAction(new Notification.Action.Builder(null, "test", null).build());
|
||||||
|
|
||||||
|
mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID, 0,
|
||||||
|
nb.build(), UserHandle.getUserHandleForUid(TEST_UID), null, 0);
|
||||||
|
mEntry.setSbn(mSbn);
|
||||||
|
mNotificationInfo.bindNotification(
|
||||||
|
mMockPackageManager,
|
||||||
|
mMockINotificationManager,
|
||||||
|
mOnUserInteractionCallback,
|
||||||
|
mChannelEditorDialogController,
|
||||||
|
TEST_PACKAGE_NAME,
|
||||||
|
mNotificationChannel,
|
||||||
|
mNotificationChannelSet,
|
||||||
|
mEntry,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
mUiEventLogger,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
mAssistantFeedbackController);
|
||||||
|
final TextView view = mNotificationInfo.findViewById(R.id.non_configurable_call_text);
|
||||||
|
assertEquals(View.VISIBLE, view.getVisibility());
|
||||||
|
assertEquals(mContext.getString(R.string.notification_unblockable_call_desc),
|
||||||
|
view.getText());
|
||||||
|
assertEquals(GONE,
|
||||||
|
mNotificationInfo.findViewById(R.id.interruptiveness_settings).getVisibility());
|
||||||
|
assertEquals(GONE,
|
||||||
|
mNotificationInfo.findViewById(R.id.non_configurable_text).getVisibility());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBindNotification_whenCurrentlyInCall_notCall() throws Exception {
|
||||||
|
when(mMockINotificationManager.isInCall(anyString(), anyInt())).thenReturn(true);
|
||||||
|
|
||||||
|
Person person = new Person.Builder()
|
||||||
|
.setName("caller")
|
||||||
|
.build();
|
||||||
|
Notification.Builder nb = new Notification.Builder(
|
||||||
|
mContext, mNotificationChannel.getId())
|
||||||
|
.setContentTitle("foo")
|
||||||
|
.setSmallIcon(android.R.drawable.sym_def_app_icon)
|
||||||
|
.setFullScreenIntent(mock(PendingIntent.class), true)
|
||||||
|
.addAction(new Notification.Action.Builder(null, "test", null).build());
|
||||||
|
|
||||||
|
mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID, 0,
|
||||||
|
nb.build(), UserHandle.getUserHandleForUid(TEST_UID), null, 0);
|
||||||
|
mEntry.setSbn(mSbn);
|
||||||
|
mNotificationInfo.bindNotification(
|
||||||
|
mMockPackageManager,
|
||||||
|
mMockINotificationManager,
|
||||||
|
mOnUserInteractionCallback,
|
||||||
|
mChannelEditorDialogController,
|
||||||
|
TEST_PACKAGE_NAME,
|
||||||
|
mNotificationChannel,
|
||||||
|
mNotificationChannelSet,
|
||||||
|
mEntry,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
mUiEventLogger,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
mAssistantFeedbackController);
|
||||||
|
assertEquals(GONE,
|
||||||
|
mNotificationInfo.findViewById(R.id.non_configurable_call_text).getVisibility());
|
||||||
|
assertEquals(VISIBLE,
|
||||||
|
mNotificationInfo.findViewById(R.id.interruptiveness_settings).getVisibility());
|
||||||
|
assertEquals(GONE,
|
||||||
|
mNotificationInfo.findViewById(R.id.non_configurable_text).getVisibility());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBindNotification_automaticIsVisible() throws Exception {
|
public void testBindNotification_automaticIsVisible() throws Exception {
|
||||||
when(mAssistantFeedbackController.isFeedbackEnabled()).thenReturn(true);
|
when(mAssistantFeedbackController.isFeedbackEnabled()).thenReturn(true);
|
||||||
|
|||||||
@@ -240,6 +240,7 @@ import android.service.notification.SnoozeCriterion;
|
|||||||
import android.service.notification.StatusBarNotification;
|
import android.service.notification.StatusBarNotification;
|
||||||
import android.service.notification.ZenModeConfig;
|
import android.service.notification.ZenModeConfig;
|
||||||
import android.service.notification.ZenModeProto;
|
import android.service.notification.ZenModeProto;
|
||||||
|
import android.telecom.TelecomManager;
|
||||||
import android.telephony.PhoneStateListener;
|
import android.telephony.PhoneStateListener;
|
||||||
import android.telephony.TelephonyManager;
|
import android.telephony.TelephonyManager;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
@@ -509,6 +510,7 @@ public class NotificationManagerService extends SystemService {
|
|||||||
private ShortcutHelper mShortcutHelper;
|
private ShortcutHelper mShortcutHelper;
|
||||||
private PermissionHelper mPermissionHelper;
|
private PermissionHelper mPermissionHelper;
|
||||||
private UsageStatsManagerInternal mUsageStatsManagerInternal;
|
private UsageStatsManagerInternal mUsageStatsManagerInternal;
|
||||||
|
private TelecomManager mTelecomManager;
|
||||||
|
|
||||||
final IBinder mForegroundToken = new Binder();
|
final IBinder mForegroundToken = new Binder();
|
||||||
private WorkerHandler mHandler;
|
private WorkerHandler mHandler;
|
||||||
@@ -2100,7 +2102,8 @@ public class NotificationManagerService extends SystemService {
|
|||||||
NotificationHistoryManager historyManager, StatsManager statsManager,
|
NotificationHistoryManager historyManager, StatsManager statsManager,
|
||||||
TelephonyManager telephonyManager, ActivityManagerInternal ami,
|
TelephonyManager telephonyManager, ActivityManagerInternal ami,
|
||||||
MultiRateLimiter toastRateLimiter, PermissionHelper permissionHelper,
|
MultiRateLimiter toastRateLimiter, PermissionHelper permissionHelper,
|
||||||
UsageStatsManagerInternal usageStatsManagerInternal) {
|
UsageStatsManagerInternal usageStatsManagerInternal,
|
||||||
|
TelecomManager telecomManager) {
|
||||||
mHandler = handler;
|
mHandler = handler;
|
||||||
Resources resources = getContext().getResources();
|
Resources resources = getContext().getResources();
|
||||||
mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
|
mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
|
||||||
@@ -2129,6 +2132,7 @@ public class NotificationManagerService extends SystemService {
|
|||||||
mDeviceIdleManager = getContext().getSystemService(DeviceIdleManager.class);
|
mDeviceIdleManager = getContext().getSystemService(DeviceIdleManager.class);
|
||||||
mDpm = dpm;
|
mDpm = dpm;
|
||||||
mUm = userManager;
|
mUm = userManager;
|
||||||
|
mTelecomManager = telecomManager;
|
||||||
mPlatformCompat = IPlatformCompat.Stub.asInterface(
|
mPlatformCompat = IPlatformCompat.Stub.asInterface(
|
||||||
ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
|
ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
|
||||||
|
|
||||||
@@ -2420,7 +2424,8 @@ public class NotificationManagerService extends SystemService {
|
|||||||
PermissionManagerServiceInternal.class), AppGlobals.getPackageManager(),
|
PermissionManagerServiceInternal.class), AppGlobals.getPackageManager(),
|
||||||
AppGlobals.getPermissionManager(), mEnableAppSettingMigration,
|
AppGlobals.getPermissionManager(), mEnableAppSettingMigration,
|
||||||
mForceUserSetOnUpgrade),
|
mForceUserSetOnUpgrade),
|
||||||
LocalServices.getService(UsageStatsManagerInternal.class));
|
LocalServices.getService(UsageStatsManagerInternal.class),
|
||||||
|
getContext().getSystemService(TelecomManager.class));
|
||||||
|
|
||||||
publishBinderService(Context.NOTIFICATION_SERVICE, mService, /* allowIsolated= */ false,
|
publishBinderService(Context.NOTIFICATION_SERVICE, mService, /* allowIsolated= */ false,
|
||||||
DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL);
|
DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL);
|
||||||
@@ -5534,6 +5539,12 @@ public class NotificationManagerService extends SystemService {
|
|||||||
return new ParceledListSlice<>(groups);
|
return new ParceledListSlice<>(groups);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isInCall(String pkg, int uid) {
|
||||||
|
checkCallerIsSystemOrSystemUiOrShell();
|
||||||
|
return isCallNotification(pkg, uid);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setPrivateNotificationsAllowed(boolean allow) {
|
public void setPrivateNotificationsAllowed(boolean allow) {
|
||||||
if (PackageManager.PERMISSION_GRANTED
|
if (PackageManager.PERMISSION_GRANTED
|
||||||
@@ -6846,7 +6857,7 @@ public class NotificationManagerService extends SystemService {
|
|||||||
synchronized (mNotificationLock) {
|
synchronized (mNotificationLock) {
|
||||||
isBlocked |= isRecordBlockedLocked(r);
|
isBlocked |= isRecordBlockedLocked(r);
|
||||||
}
|
}
|
||||||
if (isBlocked && !n.isMediaNotification()) {
|
if (isBlocked && !(n.isMediaNotification() || isCallNotification(pkg, uid, n))) {
|
||||||
if (DBG) {
|
if (DBG) {
|
||||||
Slog.e(TAG, "Suppressing notification from package " + r.getSbn().getPackageName()
|
Slog.e(TAG, "Suppressing notification from package " + r.getSbn().getPackageName()
|
||||||
+ " by user request.");
|
+ " by user request.");
|
||||||
@@ -6858,6 +6869,23 @@ public class NotificationManagerService extends SystemService {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isCallNotification(String pkg, int uid, Notification n) {
|
||||||
|
if (n.isStyle(Notification.CallStyle.class)) {
|
||||||
|
return isCallNotification(pkg, uid);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isCallNotification(String pkg, int uid) {
|
||||||
|
final long identity = Binder.clearCallingIdentity();
|
||||||
|
try {
|
||||||
|
return mTelecomManager.isInManagedCall() || mTelecomManager.isInSelfManagedCall(
|
||||||
|
pkg, UserHandle.getUserHandleForUid(uid));
|
||||||
|
} finally {
|
||||||
|
Binder.restoreCallingIdentity(identity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private boolean areNotificationsEnabledForPackageInt(String pkg, int uid) {
|
private boolean areNotificationsEnabledForPackageInt(String pkg, int uid) {
|
||||||
if (mEnableAppSettingMigration) {
|
if (mEnableAppSettingMigration) {
|
||||||
return mPermissionHelper.hasPermission(uid);
|
return mPermissionHelper.hasPermission(uid);
|
||||||
|
|||||||
@@ -170,6 +170,7 @@ import android.service.notification.NotificationListenerService;
|
|||||||
import android.service.notification.NotificationStats;
|
import android.service.notification.NotificationStats;
|
||||||
import android.service.notification.StatusBarNotification;
|
import android.service.notification.StatusBarNotification;
|
||||||
import android.service.notification.ZenPolicy;
|
import android.service.notification.ZenPolicy;
|
||||||
|
import android.telecom.TelecomManager;
|
||||||
import android.telephony.TelephonyManager;
|
import android.telephony.TelephonyManager;
|
||||||
import android.test.suitebuilder.annotation.SmallTest;
|
import android.test.suitebuilder.annotation.SmallTest;
|
||||||
import android.testing.AndroidTestingRunner;
|
import android.testing.AndroidTestingRunner;
|
||||||
@@ -290,6 +291,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
|||||||
@Mock
|
@Mock
|
||||||
ActivityManager mActivityManager;
|
ActivityManager mActivityManager;
|
||||||
@Mock
|
@Mock
|
||||||
|
TelecomManager mTelecomManager;
|
||||||
|
@Mock
|
||||||
Resources mResources;
|
Resources mResources;
|
||||||
@Mock
|
@Mock
|
||||||
RankingHandler mRankingHandler;
|
RankingHandler mRankingHandler;
|
||||||
@@ -494,7 +497,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
|||||||
mAppUsageStats, mock(DevicePolicyManagerInternal.class), mUgm, mUgmInternal,
|
mAppUsageStats, mock(DevicePolicyManagerInternal.class), mUgm, mUgmInternal,
|
||||||
mAppOpsManager, mAppOpsService, mUm, mHistoryManager, mStatsManager,
|
mAppOpsManager, mAppOpsService, mUm, mHistoryManager, mStatsManager,
|
||||||
mock(TelephonyManager.class),
|
mock(TelephonyManager.class),
|
||||||
mAmi, mToastRateLimiter, mPermissionHelper, mock(UsageStatsManagerInternal.class));
|
mAmi, mToastRateLimiter, mPermissionHelper, mock(UsageStatsManagerInternal.class),
|
||||||
|
mTelecomManager);
|
||||||
// Return first true for RoleObserver main-thread check
|
// Return first true for RoleObserver main-thread check
|
||||||
when(mMainLooper.isCurrentThread()).thenReturn(true).thenReturn(false);
|
when(mMainLooper.isCurrentThread()).thenReturn(true).thenReturn(false);
|
||||||
mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY, mMainLooper);
|
mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY, mMainLooper);
|
||||||
@@ -9126,6 +9130,54 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
|||||||
r.getSbn().getId(), r.getSbn().getTag(), r, false)).isTrue();
|
r.getSbn().getId(), r.getSbn().getTag(), r, false)).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCallNotificationsBypassBlock() throws Exception {
|
||||||
|
when(mAmi.getPendingIntentFlags(any(IIntentSender.class)))
|
||||||
|
.thenReturn(FLAG_MUTABLE | FLAG_ONE_SHOT);
|
||||||
|
when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
|
||||||
|
|
||||||
|
Notification.Builder nb = new Notification.Builder(
|
||||||
|
mContext, mTestNotificationChannel.getId())
|
||||||
|
.setContentTitle("foo")
|
||||||
|
.setSmallIcon(android.R.drawable.sym_def_app_icon)
|
||||||
|
.addAction(new Notification.Action.Builder(null, "test", null).build());
|
||||||
|
StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 8, "tag", mUid, 0,
|
||||||
|
nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
|
||||||
|
NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
|
||||||
|
|
||||||
|
mBinderService.setNotificationsEnabledForPackage(
|
||||||
|
r.getSbn().getPackageName(), r.getUid(), false);
|
||||||
|
|
||||||
|
// normal blocked notifications - blocked
|
||||||
|
assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
|
||||||
|
r.getSbn().getId(), r.getSbn().getTag(), r, false)).isFalse();
|
||||||
|
|
||||||
|
// just using the style - blocked
|
||||||
|
Person person = new Person.Builder()
|
||||||
|
.setName("caller")
|
||||||
|
.build();
|
||||||
|
nb.setStyle(Notification.CallStyle.forOngoingCall(
|
||||||
|
person, mock(PendingIntent.class)));
|
||||||
|
nb.setFullScreenIntent(mock(PendingIntent.class), true);
|
||||||
|
sbn = new StatusBarNotification(PKG, PKG, 8, "tag", mUid, 0,
|
||||||
|
nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
|
||||||
|
r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
|
||||||
|
|
||||||
|
assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
|
||||||
|
r.getSbn().getId(), r.getSbn().getTag(), r, false)).isFalse();
|
||||||
|
|
||||||
|
// style + managed call - bypasses block
|
||||||
|
when(mTelecomManager.isInManagedCall()).thenReturn(true);
|
||||||
|
assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
|
||||||
|
r.getSbn().getId(), r.getSbn().getTag(), r, false)).isTrue();
|
||||||
|
|
||||||
|
// style + self managed call - bypasses block
|
||||||
|
when(mTelecomManager.isInSelfManagedCall(
|
||||||
|
r.getSbn().getPackageName(), r.getUser())).thenReturn(true);
|
||||||
|
assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
|
||||||
|
r.getSbn().getId(), r.getSbn().getTag(), r, false)).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetAllUsersNotificationPermissions_migrationNotEnabled() {
|
public void testGetAllUsersNotificationPermissions_migrationNotEnabled() {
|
||||||
// make sure we don't bother if the migration is not enabled
|
// make sure we don't bother if the migration is not enabled
|
||||||
|
|||||||
@@ -97,6 +97,7 @@ import android.os.UserManager;
|
|||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.service.notification.NotificationListenerFilter;
|
import android.service.notification.NotificationListenerFilter;
|
||||||
import android.service.notification.StatusBarNotification;
|
import android.service.notification.StatusBarNotification;
|
||||||
|
import android.telecom.TelecomManager;
|
||||||
import android.telephony.TelephonyManager;
|
import android.telephony.TelephonyManager;
|
||||||
import android.test.suitebuilder.annotation.SmallTest;
|
import android.test.suitebuilder.annotation.SmallTest;
|
||||||
import android.testing.AndroidTestingRunner;
|
import android.testing.AndroidTestingRunner;
|
||||||
@@ -379,7 +380,7 @@ public class NotificationPermissionMigrationTest extends UiServiceTestCase {
|
|||||||
mAppUsageStats, mock(DevicePolicyManagerInternal.class), mUgm, mUgmInternal,
|
mAppUsageStats, mock(DevicePolicyManagerInternal.class), mUgm, mUgmInternal,
|
||||||
mAppOpsManager, mock(IAppOpsService.class), mUm, mHistoryManager, mStatsManager,
|
mAppOpsManager, mock(IAppOpsService.class), mUm, mHistoryManager, mStatsManager,
|
||||||
mock(TelephonyManager.class), mAmi, mToastRateLimiter, mPermissionHelper,
|
mock(TelephonyManager.class), mAmi, mToastRateLimiter, mPermissionHelper,
|
||||||
mock(UsageStatsManagerInternal.class));
|
mock(UsageStatsManagerInternal.class), mock(TelecomManager.class));
|
||||||
// Return first true for RoleObserver main-thread check
|
// Return first true for RoleObserver main-thread check
|
||||||
when(mMainLooper.isCurrentThread()).thenReturn(true).thenReturn(false);
|
when(mMainLooper.isCurrentThread()).thenReturn(true).thenReturn(false);
|
||||||
mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY, mMainLooper);
|
mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY, mMainLooper);
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ import android.content.pm.PackageManagerInternal;
|
|||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.os.UserManager;
|
import android.os.UserManager;
|
||||||
|
import android.telecom.TelecomManager;
|
||||||
import android.telephony.TelephonyManager;
|
import android.telephony.TelephonyManager;
|
||||||
import android.test.suitebuilder.annotation.SmallTest;
|
import android.test.suitebuilder.annotation.SmallTest;
|
||||||
import android.testing.AndroidTestingRunner;
|
import android.testing.AndroidTestingRunner;
|
||||||
@@ -167,7 +168,7 @@ public class RoleObserverTest extends UiServiceTestCase {
|
|||||||
mock(StatsManager.class), mock(TelephonyManager.class),
|
mock(StatsManager.class), mock(TelephonyManager.class),
|
||||||
mock(ActivityManagerInternal.class),
|
mock(ActivityManagerInternal.class),
|
||||||
mock(MultiRateLimiter.class), mock(PermissionHelper.class),
|
mock(MultiRateLimiter.class), mock(PermissionHelper.class),
|
||||||
mock(UsageStatsManagerInternal.class));
|
mock(UsageStatsManagerInternal.class), mock (TelecomManager.class));
|
||||||
} catch (SecurityException e) {
|
} catch (SecurityException e) {
|
||||||
if (!e.getMessage().contains("Permission Denial: not allowed to send broadcast")) {
|
if (!e.getMessage().contains("Permission Denial: not allowed to send broadcast")) {
|
||||||
throw e;
|
throw e;
|
||||||
|
|||||||
Reference in New Issue
Block a user