diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java index 8d2639d4cdd07..242c6afebc3e7 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java @@ -21,6 +21,7 @@ import android.app.Activity; import com.android.systemui.ForegroundServicesDialog; import com.android.systemui.keyguard.WorkLockActivity; import com.android.systemui.people.PeopleSpaceActivity; +import com.android.systemui.people.widget.LaunchConversationActivity; import com.android.systemui.screenrecord.ScreenRecordDialog; import com.android.systemui.screenshot.LongScreenshotActivity; import com.android.systemui.settings.brightness.BrightnessDialog; @@ -106,4 +107,10 @@ public abstract class DefaultActivityBinder { @IntoMap @ClassKey(LongScreenshotActivity.class) public abstract Activity bindLongScreenshotActivity(LongScreenshotActivity activity); + + /** Inject into LaunchConversationActivity. */ + @Binds + @IntoMap + @ClassKey(LaunchConversationActivity.class) + public abstract Activity bindLaunchConversationActivity(LaunchConversationActivity activity); } diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java index f9a16c1c19704..502c95c47d03d 100644 --- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java +++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java @@ -609,6 +609,8 @@ public class PeopleSpaceUtils { PeopleSpaceWidgetProvider.EXTRA_PACKAGE_NAME, tile.getPackageName()); activityIntent.putExtra(PeopleSpaceWidgetProvider.EXTRA_USER_HANDLE, tile.getUserHandle()); + activityIntent.putExtra( + PeopleSpaceWidgetProvider.EXTRA_NOTIFICATION_KEY, tile.getNotificationKey()); views.setOnClickPendingIntent(R.id.item, PendingIntent.getActivity( context, appWidgetId, diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/LaunchConversationActivity.java b/packages/SystemUI/src/com/android/systemui/people/widget/LaunchConversationActivity.java index 13e30f920f429..48f6184a96d9b 100644 --- a/packages/SystemUI/src/com/android/systemui/people/widget/LaunchConversationActivity.java +++ b/packages/SystemUI/src/com/android/systemui/people/widget/LaunchConversationActivity.java @@ -17,21 +17,38 @@ package com.android.systemui.people.widget; import android.app.Activity; +import android.content.Context; import android.content.Intent; import android.content.pm.LauncherApps; import android.os.Bundle; +import android.os.ServiceManager; import android.os.UserHandle; +import android.service.notification.NotificationStats; +import android.text.TextUtils; import android.util.Log; import com.android.internal.logging.UiEventLogger; import com.android.internal.logging.UiEventLoggerImpl; +import com.android.internal.statusbar.IStatusBarService; +import com.android.internal.statusbar.NotificationVisibility; import com.android.systemui.people.PeopleSpaceUtils; +import com.android.systemui.statusbar.notification.NotificationEntryManager; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; + +import javax.inject.Inject; /** Proxy activity to launch ShortcutInfo's conversation. */ public class LaunchConversationActivity extends Activity { private static final String TAG = "PeopleSpaceLaunchConv"; private static final boolean DEBUG = PeopleSpaceUtils.DEBUG; private UiEventLogger mUiEventLogger = new UiEventLoggerImpl(); + private NotificationEntryManager mNotificationEntryManager; + + @Inject + public LaunchConversationActivity(NotificationEntryManager notificationEntryManager) { + super(); + mNotificationEntryManager = notificationEntryManager; + } @Override public void onCreate(Bundle savedInstanceState) { @@ -43,6 +60,8 @@ public class LaunchConversationActivity extends Activity { String packageName = intent.getStringExtra(PeopleSpaceWidgetProvider.EXTRA_PACKAGE_NAME); UserHandle userHandle = intent.getParcelableExtra( PeopleSpaceWidgetProvider.EXTRA_USER_HANDLE); + String notificationKey = + intent.getStringExtra(PeopleSpaceWidgetProvider.EXTRA_NOTIFICATION_KEY); if (tileId != null && !tileId.isEmpty()) { if (DEBUG) { @@ -54,12 +73,56 @@ public class LaunchConversationActivity extends Activity { getApplicationContext().getSystemService(LauncherApps.class); launcherApps.startShortcut( packageName, tileId, null, null, userHandle); + + IStatusBarService statusBarService = IStatusBarService.Stub.asInterface( + ServiceManager.getService(Context.STATUS_BAR_SERVICE)); + clearNotificationIfPresent( + statusBarService, notificationKey, packageName, userHandle); } catch (Exception e) { - Log.e(TAG, "Exception starting shortcut:" + e); + Log.e(TAG, "Exception:" + e); } } else { if (DEBUG) Log.d(TAG, "Trying to launch conversation with null shortcutInfo."); } finish(); } + + void clearNotificationIfPresent(IStatusBarService statusBarService, + String notifKey, String packageName, UserHandle userHandle) { + if (TextUtils.isEmpty(notifKey)) { + if (DEBUG) Log.d(TAG, "Skipping clear notification: notification key is empty"); + return; + } + + try { + if (statusBarService == null || mNotificationEntryManager == null) { + if (DEBUG) { + Log.d(TAG, "Skipping clear notification: null services, key: " + notifKey); + } + return; + } + + NotificationEntry entry = mNotificationEntryManager.getPendingOrActiveNotif(notifKey); + if (entry == null || entry.getRanking() == null) { + if (DEBUG) { + Log.d(TAG, "Skipping clear notification: NotificationEntry or its Ranking" + + " is null, key: " + notifKey); + } + return; + } + + int count = mNotificationEntryManager.getActiveNotificationsCount(); + int rank = entry.getRanking().getRank(); + NotificationVisibility notifVisibility = NotificationVisibility.obtain(notifKey, + rank, count, true); + + if (DEBUG) Log.d(TAG, "Clearing notification, key: " + notifKey + ", rank: " + rank); + statusBarService.onNotificationClear( + packageName, userHandle.getIdentifier(), notifKey, + NotificationStats.DISMISSAL_OTHER, + NotificationStats.DISMISS_SENTIMENT_POSITIVE, notifVisibility); + } catch (Exception e) { + Log.e(TAG, "Exception cancelling notification:" + e); + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetProvider.java b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetProvider.java index c0c18471ba321..cccf7aa13028f 100644 --- a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetProvider.java +++ b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetProvider.java @@ -35,6 +35,7 @@ public class PeopleSpaceWidgetProvider extends AppWidgetProvider { public static final String EXTRA_TILE_ID = "extra_tile_id"; public static final String EXTRA_PACKAGE_NAME = "extra_package_name"; public static final String EXTRA_USER_HANDLE = "extra_user_handle"; + public static final String EXTRA_NOTIFICATION_KEY = "extra_notification_key"; public PeopleSpaceWidgetManager peopleSpaceWidgetManager; diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/widget/LaunchConversationActivityTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/widget/LaunchConversationActivityTest.java new file mode 100644 index 0000000000000..fce02174a1e0c --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/people/widget/LaunchConversationActivityTest.java @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2020 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.systemui.people.widget; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.os.UserHandle; +import android.service.notification.NotificationListenerService; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper.RunWithLooper; + +import androidx.test.filters.SmallTest; + +import com.android.internal.statusbar.IStatusBarService; +import com.android.internal.statusbar.NotificationVisibility; +import com.android.systemui.SysuiTestCase; +import com.android.systemui.statusbar.notification.NotificationEntryManager; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +@RunWithLooper +public class LaunchConversationActivityTest extends SysuiTestCase { + private static final String EMPTY_STRING = ""; + private static final String PACKAGE_NAME = "com.android.systemui.tests"; + private static final String NOTIF_KEY = "notifKey"; + private static final String NOTIF_KEY_NO_ENTRY = "notifKeyNoEntry"; + private static final String NOTIF_KEY_NO_RANKING = "notifKeyNoRanking"; + + + private static final UserHandle USER_HANDLE = UserHandle.of(0); + private static final int NOTIF_COUNT = 10; + private static final int NOTIF_RANK = 2; + + private LaunchConversationActivity mActivity; + + @Mock + private NotificationEntryManager mNotificationEntryManager; + @Mock + private IStatusBarService mIStatusBarService; + @Mock + private NotificationEntry mNotifEntry; + @Mock + private NotificationEntry mNotifEntryNoRanking; + @Mock + private NotificationListenerService.Ranking mRanking; + + @Captor + private ArgumentCaptor mNotificationVisibilityCaptor; + + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + mActivity = new LaunchConversationActivity(mNotificationEntryManager); + + when(mNotificationEntryManager.getActiveNotificationsCount()).thenReturn(NOTIF_COUNT); + when(mNotificationEntryManager.getPendingOrActiveNotif(NOTIF_KEY)).thenReturn(mNotifEntry); + when(mNotificationEntryManager.getPendingOrActiveNotif(NOTIF_KEY_NO_ENTRY)) + .thenReturn(null); + when(mNotificationEntryManager.getPendingOrActiveNotif(NOTIF_KEY_NO_RANKING)) + .thenReturn(mNotifEntryNoRanking); + when(mNotifEntry.getRanking()).thenReturn(mRanking); + when(mNotifEntryNoRanking.getRanking()).thenReturn(null); + when(mRanking.getRank()).thenReturn(NOTIF_RANK); + } + + @Test + public void testDoNotClearNotificationIfNoKey() throws Exception { + mActivity.clearNotificationIfPresent(mIStatusBarService, + EMPTY_STRING, PACKAGE_NAME, USER_HANDLE); + + verify(mIStatusBarService, never()).onNotificationClear( + any(), anyInt(), any(), anyInt(), anyInt(), any()); + } + + @Test + public void testDoNotClearNotificationIfNoNotificationEntry() throws Exception { + mActivity.clearNotificationIfPresent(mIStatusBarService, + NOTIF_KEY_NO_ENTRY, PACKAGE_NAME, USER_HANDLE); + + verify(mIStatusBarService, never()).onNotificationClear( + any(), anyInt(), any(), anyInt(), anyInt(), any()); + } + + @Test + public void testDoNotClearNotificationIfNoRanking() throws Exception { + mActivity.clearNotificationIfPresent(mIStatusBarService, + NOTIF_KEY_NO_RANKING, PACKAGE_NAME, USER_HANDLE); + + verify(mIStatusBarService, never()).onNotificationClear( + any(), anyInt(), any(), anyInt(), anyInt(), any()); + } + + @Test + public void testClearNotification() throws Exception { + mActivity.clearNotificationIfPresent(mIStatusBarService, + NOTIF_KEY, PACKAGE_NAME, USER_HANDLE); + + verify(mIStatusBarService, times(1)).onNotificationClear(any(), + anyInt(), any(), anyInt(), anyInt(), mNotificationVisibilityCaptor.capture()); + + NotificationVisibility nv = mNotificationVisibilityCaptor.getValue(); + assertThat(nv.count).isEqualTo(NOTIF_COUNT); + assertThat(nv.rank).isEqualTo(NOTIF_RANK); + } + +}