diff options
| author | 2018-10-25 16:54:27 -0400 | |
|---|---|---|
| committer | 2018-10-29 14:16:03 -0400 | |
| commit | ac98aea2ed4de69a25cb72f389b999fa8ff5d4d2 (patch) | |
| tree | c41b9a882663bc8d83583a60fa424564d73968f3 | |
| parent | b6bd93d960676a407ef04cb58a15e9b3b187a42e (diff) | |
Proxy notification improvments
- Fix a bug where the notifications weren't being posted
- Add attribution to the notification guts
Bug: 111452544
Test: atest
Change-Id: I58d104fe0ad8450a4722585335011ea633fee52a
6 files changed, 151 insertions, 49 deletions
diff --git a/packages/SystemUI/res/layout/notification_info.xml b/packages/SystemUI/res/layout/notification_info.xml index f138685e9810..5c950ecfb49e 100644 --- a/packages/SystemUI/res/layout/notification_info.xml +++ b/packages/SystemUI/res/layout/notification_info.xml @@ -51,7 +51,7 @@ android:layout_centerVertical="true" android:layout_toEndOf="@id/pkgicon" /> <TextView - android:id="@+id/pkg_group_divider" + android:id="@+id/pkg_divider" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="@*android:style/TextAppearance.Material.Notification.Info" @@ -61,7 +61,7 @@ android:layout_centerVertical="true" android:layout_toEndOf="@id/pkgname" /> <TextView - android:id="@+id/group_name" + android:id="@+id/delegate_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="@*android:style/TextAppearance.Material.Notification.Info" @@ -70,7 +70,7 @@ android:ellipsize="end" android:maxLines="1" android:layout_centerVertical="true" - android:layout_toEndOf="@id/pkg_group_divider" /> + android:layout_toEndOf="@id/pkg_divider" /> <!-- 24 dp icon with 16 dp padding all around to mirror notification content margins --> <ImageButton android:id="@+id/info" @@ -101,13 +101,39 @@ android:layout_marginStart="@*android:dimen/notification_content_margin_start" android:layout_marginEnd="@*android:dimen/notification_content_margin_start" android:orientation="vertical"> - <!-- Channel Name --> - <TextView - android:id="@+id/channel_name" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_weight="1" - style="@android:style/TextAppearance.Material.Notification.Title" /> + <RelativeLayout + android:id="@+id/names" + android:layout_width="match_parent" + android:layout_height="wrap_content"> + <TextView + android:id="@+id/group_name" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textAppearance="@*android:style/TextAppearance.Material.Notification.Title" + android:layout_marginStart="2dp" + android:layout_marginEnd="2dp" + android:ellipsize="end" + android:maxLines="1" + android:layout_centerVertical="true" /> + <TextView + android:id="@+id/pkg_group_divider" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textAppearance="@*android:style/TextAppearance.Material.Notification.Title" + android:layout_marginStart="2dp" + android:layout_marginEnd="2dp" + android:text="@*android:string/notification_header_divider_symbol" + android:layout_centerVertical="true" + android:layout_toEndOf="@id/group_name" /> + <!-- Channel Name --> + <TextView + android:id="@+id/channel_name" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_weight="1" + style="@android:style/TextAppearance.Material.Notification.Title" + android:layout_toEndOf="@id/pkg_group_divider"/> + </RelativeLayout> <!-- Question prompt --> <TextView android:id="@+id/block_prompt" diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 42e19aace0c3..260bfe633804 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -1593,6 +1593,9 @@ <!-- Notification: Control panel: Label that displays when the app's notifications cannot be blocked. --> <string name="notification_unblockable_desc">These notifications can\'t be turned off</string> + <!-- Notification: Control panel: Label for the app that posted this notification, if it's not the package that the notification was posted for --> + <string name="notification_delegate_header">via <xliff:g id="app_name" example="YouTube">%1$s</xliff:g></string> + <!-- Notification Inline controls: describes what the app is doing in the background [CHAR_LIMIT=NONE] --> <string name="appops_camera">This app is using the camera.</string> <!-- Notification Inline controls: describes what the app is doing in the background [CHAR_LIMIT=NONE] --> diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java index 903c27277b70..912a2f7e598d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java @@ -72,6 +72,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G private String mPackageName; private String mAppName; private int mAppUid; + private String mDelegatePkg; private int mNumUniqueChannelsInRow; private NotificationChannel mSingleNotificationChannel; private int mStartingUserImportance; @@ -193,6 +194,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G (mSbn.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE) != 0; mIsForBlockingHelper = isForBlockingHelper; mAppUid = mSbn.getUid(); + mDelegatePkg = mSbn.getOpPkg(); mIsDeviceProvisioned = isDeviceProvisioned; int numTotalChannels = mINotificationManager.getNumNotificationChannelsForPackage( @@ -234,26 +236,8 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G ((ImageView) findViewById(R.id.pkgicon)).setImageDrawable(pkgicon); ((TextView) findViewById(R.id.pkgname)).setText(mAppName); - // Set group information if this channel has an associated group. - CharSequence groupName = null; - if (mSingleNotificationChannel != null && mSingleNotificationChannel.getGroup() != null) { - final NotificationChannelGroup notificationChannelGroup = - mINotificationManager.getNotificationChannelGroupForPackage( - mSingleNotificationChannel.getGroup(), mPackageName, mAppUid); - if (notificationChannelGroup != null) { - groupName = notificationChannelGroup.getName(); - } - } - TextView groupNameView = findViewById(R.id.group_name); - TextView groupDividerView = findViewById(R.id.pkg_group_divider); - if (groupName != null) { - groupNameView.setText(groupName); - groupNameView.setVisibility(View.VISIBLE); - groupDividerView.setVisibility(View.VISIBLE); - } else { - groupNameView.setVisibility(View.GONE); - groupDividerView.setVisibility(View.GONE); - } + // Delegate + bindDelegate(); // Settings button. final View settingsButton = findViewById(R.id.info); @@ -273,9 +257,10 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G } } - private void bindPrompt() { + private void bindPrompt() throws RemoteException { final TextView blockPrompt = findViewById(R.id.block_prompt); bindName(); + bindGroup(); if (mIsNonblockable) { blockPrompt.setText(R.string.notification_unblockable_desc); } else { @@ -298,6 +283,60 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G } } + private void bindDelegate() { + TextView delegateView = findViewById(R.id.delegate_name); + TextView dividerView = findViewById(R.id.pkg_divider); + + CharSequence delegatePkg = null; + if (!TextUtils.equals(mPackageName, mDelegatePkg)) { + // this notification was posted by a delegate! + ApplicationInfo info; + try { + info = mPm.getApplicationInfo( + mDelegatePkg, + PackageManager.MATCH_UNINSTALLED_PACKAGES + | PackageManager.MATCH_DISABLED_COMPONENTS + | PackageManager.MATCH_DIRECT_BOOT_UNAWARE + | PackageManager.MATCH_DIRECT_BOOT_AWARE); + if (info != null) { + delegatePkg = String.valueOf(mPm.getApplicationLabel(info)); + } + } catch (PackageManager.NameNotFoundException e) {} + } + if (delegatePkg != null) { + delegateView.setText(mContext.getResources().getString( + R.string.notification_delegate_header, delegatePkg)); + delegateView.setVisibility(View.VISIBLE); + dividerView.setVisibility(View.VISIBLE); + } else { + delegateView.setVisibility(View.GONE); + dividerView.setVisibility(View.GONE); + } + } + + private void bindGroup() throws RemoteException { + // Set group information if this channel has an associated group. + CharSequence groupName = null; + if (mSingleNotificationChannel != null && mSingleNotificationChannel.getGroup() != null) { + final NotificationChannelGroup notificationChannelGroup = + mINotificationManager.getNotificationChannelGroupForPackage( + mSingleNotificationChannel.getGroup(), mPackageName, mAppUid); + if (notificationChannelGroup != null) { + groupName = notificationChannelGroup.getName(); + } + } + TextView groupNameView = findViewById(R.id.group_name); + TextView groupDividerView = findViewById(R.id.pkg_group_divider); + if (groupName != null) { + groupNameView.setText(groupName); + groupNameView.setVisibility(View.VISIBLE); + groupDividerView.setVisibility(View.VISIBLE); + } else { + groupNameView.setVisibility(View.GONE); + groupDividerView.setVisibility(View.GONE); + } + } + @VisibleForTesting void logBlockingHelperCounter(String counterTag) { if (mIsForBlockingHelper) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java index ca968a8af85b..02a618b7f82a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java @@ -129,7 +129,7 @@ public class NotificationInfoTest extends SysuiTestCase { .thenReturn(packageInfo); final ApplicationInfo applicationInfo = new ApplicationInfo(); applicationInfo.uid = TEST_UID; // non-zero - when(mMockPackageManager.getApplicationInfo(anyString(), anyInt())).thenReturn( + when(mMockPackageManager.getApplicationInfo(eq(TEST_PACKAGE_NAME), anyInt())).thenReturn( applicationInfo); final PackageInfo systemPackageInfo = new PackageInfo(); systemPackageInfo.packageName = TEST_SYSTEM_PACKAGE_NAME; @@ -190,6 +190,35 @@ public class NotificationInfoTest extends SysuiTestCase { } @Test + public void testBindNotification_noDelegate() throws Exception { + mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, + TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false); + final TextView nameView = mNotificationInfo.findViewById(R.id.delegate_name); + assertEquals(GONE, nameView.getVisibility()); + final TextView dividerView = mNotificationInfo.findViewById(R.id.pkg_divider); + assertEquals(GONE, dividerView.getVisibility()); + } + + @Test + public void testBindNotification_delegate() throws Exception { + mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, "other", 0, null, TEST_UID, 0, + new Notification(), UserHandle.CURRENT, null, 0); + final ApplicationInfo applicationInfo = new ApplicationInfo(); + applicationInfo.uid = 7; // non-zero + when(mMockPackageManager.getApplicationInfo(eq("other"), anyInt())).thenReturn( + applicationInfo); + when(mMockPackageManager.getApplicationLabel(any())).thenReturn("Other"); + + mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, + TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false); + final TextView nameView = mNotificationInfo.findViewById(R.id.delegate_name); + assertEquals(VISIBLE, nameView.getVisibility()); + assertTrue(nameView.getText().toString().contains("Other")); + final TextView dividerView = mNotificationInfo.findViewById(R.id.pkg_divider); + assertEquals(VISIBLE, dividerView.getVisibility()); + } + + @Test public void testBindNotification_GroupNameHiddenIfNoGroup() throws Exception { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false); diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 93b83ae72cca..8d581df2c43e 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -4332,19 +4332,20 @@ public class NotificationManagerService extends SystemService { * * Has side effects. */ - private boolean checkDisqualifyingFeatures(int userId, int callingUid, int id, String tag, + private boolean checkDisqualifyingFeatures(int userId, int uid, int id, String tag, NotificationRecord r, boolean isAutogroup) { final String pkg = r.sbn.getPackageName(); final boolean isSystemNotification = - isUidSystemOrPhone(callingUid) || ("android".equals(pkg)); + isUidSystemOrPhone(uid) || ("android".equals(pkg)); final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg); // Limit the number of notifications that any given package except the android // package or a registered listener can enqueue. Prevents DOS attacks and deals with leaks. if (!isSystemNotification && !isNotificationFromListener) { synchronized (mNotificationLock) { + final int callingUid = Binder.getCallingUid(); if (mNotificationsByKey.get(r.sbn.getKey()) == null - && isCallerInstantApp(pkg, Binder.getCallingUid(), userId)) { + && isCallerInstantApp(callingUid, userId)) { // Ephemeral apps have some special constraints for notifications. // They are not allowed to create new notifications however they are allowed to // update notifications created by the system (e.g. a foreground service @@ -6452,24 +6453,24 @@ public class NotificationManagerService extends SystemService { } @VisibleForTesting - boolean isCallerInstantApp(String pkg, int callingUid, int userId) { + boolean isCallerInstantApp(int callingUid, int userId) { // System is always allowed to act for ephemeral apps. if (isUidSystemOrPhone(callingUid)) { return false; } - mAppOps.checkPackage(callingUid, pkg); - try { - ApplicationInfo ai = mPackageManager.getApplicationInfo(pkg, 0, userId); - if (ai == null) { - throw new SecurityException("Unknown package " + pkg); - } - return ai.isInstantApp(); + final String pkg = mPackageManager.getNameForUid(callingUid); + mAppOps.checkPackage(callingUid, pkg); + + ApplicationInfo ai = mPackageManager.getApplicationInfo(pkg, 0, userId); + if (ai == null) { + throw new SecurityException("Unknown package " + pkg); + } + return ai.isInstantApp(); } catch (RemoteException re) { - throw new SecurityException("Unknown package " + pkg, re); + throw new SecurityException("Unknown uid " + callingUid, re); } - } private void checkCallerIsSameApp(String pkg) { diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index 3266b8b92a19..f5c0603a2417 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -288,6 +288,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL); when(mPackageManagerClient.hasSystemFeature(FEATURE_WATCH)).thenReturn(false); when(mUgmInternal.newUriPermissionOwner(anyString())).thenReturn(mPermOwner); + when(mPackageManager.getNameForUid(mUid)).thenReturn(PKG); // write to a test file; the system file isn't readable from tests mFile = new File(mContext.getCacheDir(), "test.xml"); @@ -1735,7 +1736,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @Test - public void testGetNotificationChannelFromPrivilegedListener_assistant_noAccess() throws Exception { + public void testGetNotificationChannelFromPrivilegedListener_assistant_noAccess() + throws Exception { mService.setPreferencesHelper(mPreferencesHelper); when(mCompanionMgr.getAssociations(PKG, mUid)).thenReturn(new ArrayList<>()); when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(false); @@ -3459,11 +3461,12 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { ApplicationInfo info = new ApplicationInfo(); info.privateFlags = ApplicationInfo.PRIVATE_FLAG_INSTANT; when(mPackageManager.getApplicationInfo(anyString(), anyInt(), eq(0))).thenReturn(info); + when(mPackageManager.getNameForUid(anyInt())).thenReturn("any"); - assertTrue(mService.isCallerInstantApp("any", 45770, 0)); + assertTrue(mService.isCallerInstantApp(45770, 0)); info.privateFlags = 0; - assertFalse(mService.isCallerInstantApp("any", 575370, 0)); + assertFalse(mService.isCallerInstantApp(575370, 0)); } @Test @@ -3472,8 +3475,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { info.privateFlags = ApplicationInfo.PRIVATE_FLAG_INSTANT; when(mPackageManager.getApplicationInfo(anyString(), anyInt(), eq(10))).thenReturn(info); when(mPackageManager.getApplicationInfo(anyString(), anyInt(), eq(0))).thenReturn(null); + when(mPackageManager.getNameForUid(anyInt())).thenReturn("any"); - assertTrue(mService.isCallerInstantApp("any", 68638450, 10)); + assertTrue(mService.isCallerInstantApp(68638450, 10)); } @Test |