diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 12791bcc194bf..fb0aea05ba4b0 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -14484,10 +14484,11 @@ public final class Settings { public static final String SHOW_PEOPLE_SPACE = "show_people_space"; /** - * Which types of conversations to show in People Space. + * Which types of conversation(s) to show in People Space. * Values are: - * 0: All conversations (default) + * 0: Single user-selected conversation (default) * 1: Priority conversations only + * 2: All conversations * @hide */ public static final String PEOPLE_SPACE_CONVERSATION_TYPE = diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 2da958f6b8b93..285c4a172e680 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -576,6 +576,7 @@ android:launchMode="singleInstance"> + diff --git a/packages/SystemUI/res/drawable/people_space_activity_card.xml b/packages/SystemUI/res/drawable/people_space_activity_card.xml new file mode 100644 index 0000000000000..81162d208b282 --- /dev/null +++ b/packages/SystemUI/res/drawable/people_space_activity_card.xml @@ -0,0 +1,19 @@ + + + + + \ No newline at end of file diff --git a/packages/SystemUI/res/layout/people_space_activity.xml b/packages/SystemUI/res/layout/people_space_activity.xml index 67ecdaa5d7b60..07af01b0db72b 100644 --- a/packages/SystemUI/res/layout/people_space_activity.xml +++ b/packages/SystemUI/res/layout/people_space_activity.xml @@ -17,8 +17,7 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/scroll" android:layout_width="match_parent" - android:layout_height="match_parent" - android:background="@android:color/holo_blue_light"> + android:layout_height="match_parent"> - + android:paddingBottom="16dp" /> \ No newline at end of file diff --git a/packages/SystemUI/res/layout/people_space_tile_view.xml b/packages/SystemUI/res/layout/people_space_tile_view.xml index 80bb07070b31b..c751e7d08fd10 100644 --- a/packages/SystemUI/res/layout/people_space_tile_view.xml +++ b/packages/SystemUI/res/layout/people_space_tile_view.xml @@ -20,46 +20,53 @@ android:orientation="vertical"> + android:layout_marginBottom="12dp" + android:layout_width="match_parent" + android:layout_height="wrap_content"> - - - - - + android:gravity="start"> - + + + + + + + + + + + \ No newline at end of file diff --git a/packages/SystemUI/res/layout/people_space_widget.xml b/packages/SystemUI/res/layout/people_space_widget.xml index b417fcf6424d3..f4db321b8714b 100644 --- a/packages/SystemUI/res/layout/people_space_widget.xml +++ b/packages/SystemUI/res/layout/people_space_widget.xml @@ -22,6 +22,6 @@ android:background="@drawable/people_space_widget_background" android:clipChildren="false" android:clipToPadding="false" - android:padding="5dp" + android:padding="2dp" android:divider="@null" android:dividerHeight="0dp"/> \ No newline at end of file diff --git a/packages/SystemUI/res/layout/people_space_widget_item.xml b/packages/SystemUI/res/layout/people_space_widget_item.xml index e4de6f91769cc..95de6d61e3ddf 100644 --- a/packages/SystemUI/res/layout/people_space_widget_item.xml +++ b/packages/SystemUI/res/layout/people_space_widget_item.xml @@ -22,38 +22,57 @@ android:background="@drawable/people_space_tile_view_card" android:id="@+id/item" android:orientation="vertical" - android:padding="6dp" - android:layout_marginBottom="6dp" + android:padding="4dp" + android:layout_marginBottom="2dp" android:elevation="4dp" android:layout_width="match_parent" - android:layout_height="wrap_content" - android:gravity="start"> - - - - + android:layout_height="wrap_content"> + + + + + + + + + + + + + + diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 5b74687c3109e..7989b7a08fc85 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -2824,13 +2824,15 @@ Build number copied to clipboard. - You last chatted %1$s ago + Last chatted %1$s ago - You last chatted less than %1$s ago + Last chatted less than %1$s ago - You last chatted over %1$s ago + Last chatted over %1$s ago Open conversation + + Select one conversation to show in your widget: diff --git a/packages/SystemUI/res/xml/people_space_widget_info.xml b/packages/SystemUI/res/xml/people_space_widget_info.xml index f08c8c80f9619..10e28c45a3b74 100644 --- a/packages/SystemUI/res/xml/people_space_widget_info.xml +++ b/packages/SystemUI/res/xml/people_space_widget_info.xml @@ -15,10 +15,11 @@ --> diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java index 5cd3b33a1b5fd..4a633c320999e 100644 --- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java +++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java @@ -16,19 +16,30 @@ package com.android.systemui.people; +import static android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_ID; +import static android.appwidget.AppWidgetManager.INVALID_APPWIDGET_ID; + import android.app.Activity; import android.app.INotificationManager; import android.app.people.IPeopleManager; import android.app.people.PeopleSpaceTile; +import android.appwidget.AppWidgetManager; +import android.content.ComponentName; import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; import android.content.pm.LauncherApps; import android.content.pm.PackageManager; import android.os.Bundle; import android.os.ServiceManager; +import android.provider.Settings; import android.util.Log; import android.view.ViewGroup; +import androidx.preference.PreferenceManager; + import com.android.systemui.R; +import com.android.systemui.people.widget.PeopleSpaceWidgetProvider; import java.util.List; import java.util.Map; @@ -46,6 +57,9 @@ public class PeopleSpaceActivity extends Activity { private PackageManager mPackageManager; private LauncherApps mLauncherApps; private Context mContext; + private AppWidgetManager mAppWidgetManager; + private int mAppWidgetId; + private boolean mShowSingleConversation; @Override protected void onCreate(Bundle savedInstanceState) { @@ -59,7 +73,18 @@ public class PeopleSpaceActivity extends Activity { mPeopleManager = IPeopleManager.Stub.asInterface( ServiceManager.getService(Context.PEOPLE_SERVICE)); mLauncherApps = mContext.getSystemService(LauncherApps.class); + mAppWidgetManager = AppWidgetManager.getInstance(mContext); setTileViewsWithPriorityConversations(); + mAppWidgetId = getIntent().getIntExtra(EXTRA_APPWIDGET_ID, + INVALID_APPWIDGET_ID); + mShowSingleConversation = Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0) == 0; + // Finish the configuration activity immediately if a widget is added for multiple + // conversations. If the mAppWidgetId is INVALID, then the activity wasn't launched as a + // widget configuration activity. + if (!mShowSingleConversation && mAppWidgetId != INVALID_APPWIDGET_ID) { + finishActivity(); + } } /** @@ -93,12 +118,39 @@ public class PeopleSpaceActivity extends Activity { tileView.setName(tile.getUserName().toString()); tileView.setPackageIcon(mPackageManager.getApplicationIcon(pkg)); tileView.setPersonIcon(tile.getUserIcon()); - tileView.setOnClickListener(mLauncherApps, tile); + tileView.setOnClickListener(v -> storeWidgetConfiguration(tile)); } catch (Exception e) { Log.e(TAG, "Couldn't retrieve shortcut information", e); } } + /** Stores the user selected configuration for {@code mAppWidgetId}. */ + private void storeWidgetConfiguration(PeopleSpaceTile tile) { + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext); + SharedPreferences.Editor editor = sp.edit(); + if (PeopleSpaceUtils.DEBUG) { + Log.d(TAG, "Put " + tile.getUserName() + "'s shortcut ID: " + + tile.getId() + " for widget ID: " + + mAppWidgetId); + } + editor.putString(String.valueOf(mAppWidgetId), tile.getId()); + editor.commit(); + AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(mContext); + int[] widgetIds = appWidgetManager.getAppWidgetIds( + new ComponentName(mContext, PeopleSpaceWidgetProvider.class)); + PeopleSpaceUtils.updateSingleConversationWidgets(mContext, widgetIds, mAppWidgetManager, + mNotificationManager); + finishActivity(); + } + + /** Finish activity with a successful widget configuration result. */ + private void finishActivity() { + Intent resultValue = new Intent(); + resultValue.putExtra(EXTRA_APPWIDGET_ID, mAppWidgetId); + setResult(RESULT_OK, resultValue); + finish(); + } + @Override protected void onResume() { super.onResume(); diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceTileView.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceTileView.java index 4aea5b8d64468..9ae7847031aab 100644 --- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceTileView.java +++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceTileView.java @@ -84,4 +84,9 @@ public class PeopleSpaceTileView extends LinearLayout { launcherApps.startShortcut(tile.getPackageName(), tile.getId(), null, null, UserHandle.getUserHandleForUid(tile.getUid()))); } + + /** Sets the click listener of the tile directly. */ + public void setOnClickListener(OnClickListener onClickListener) { + mTileView.setOnClickListener(onClickListener); + } } diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java index fe262b446a3c9..5f3ceb198dc4e 100644 --- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java +++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java @@ -17,11 +17,17 @@ package com.android.systemui.people; import android.app.INotificationManager; +import android.app.PendingIntent; import android.app.people.ConversationChannel; import android.app.people.IPeopleManager; import android.app.people.PeopleSpaceTile; +import android.appwidget.AppWidgetHost; +import android.appwidget.AppWidgetManager; import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; import android.content.pm.LauncherApps; +import android.content.pm.PackageManager; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.drawable.BitmapDrawable; @@ -29,17 +35,24 @@ import android.graphics.drawable.Drawable; import android.icu.text.MeasureFormat; import android.icu.util.Measure; import android.icu.util.MeasureUnit; +import android.os.ServiceManager; import android.os.UserHandle; import android.provider.Settings; import android.service.notification.ConversationChannelWrapper; import android.util.Log; +import android.widget.RemoteViews; + +import androidx.preference.PreferenceManager; import com.android.systemui.R; +import com.android.systemui.people.widget.LaunchConversationActivity; +import com.android.systemui.people.widget.PeopleSpaceWidgetProvider; import java.time.Duration; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Optional; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -57,14 +70,15 @@ public class PeopleSpaceUtils { Context context, INotificationManager notificationManager, IPeopleManager peopleManager, LauncherApps launcherApps) throws Exception { - boolean showAllConversations = Settings.Global.getInt(context.getContentResolver(), - Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0) == 0; + boolean showOnlyPriority = Settings.Global.getInt(context.getContentResolver(), + Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0) == 1; List conversations = notificationManager.getConversations( true).getList(); List> tiles = getSortedTiles(peopleManager, conversations.stream().map(c -> new PeopleSpaceTile.Builder(c.getShortcutInfo(), launcherApps).build())); - if (showAllConversations) { + if (!showOnlyPriority) { + if (DEBUG) Log.d(TAG, "Add recent conversations"); List recentConversations = peopleManager.getRecentConversations().getList(); List> recentTiles = @@ -77,6 +91,73 @@ public class PeopleSpaceUtils { return tiles; } + /** Updates {@code appWidgetIds} with their associated conversation stored. */ + public static void updateSingleConversationWidgets(Context context, int[] appWidgetIds, + AppWidgetManager appWidgetManager, INotificationManager notificationManager) { + PackageManager mPackageManager = context.getPackageManager(); + IPeopleManager mPeopleManager = IPeopleManager.Stub.asInterface( + ServiceManager.getService(Context.PEOPLE_SERVICE)); + LauncherApps mLauncherApps = context.getSystemService(LauncherApps.class); + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context); + Intent activityIntent = new Intent(context, LaunchConversationActivity.class); + activityIntent.addFlags( + Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_CLEAR_TASK + | Intent.FLAG_ACTIVITY_NO_HISTORY + | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); + try { + List> shortcutInfos = + PeopleSpaceUtils.getTiles( + context, notificationManager, + mPeopleManager, mLauncherApps); + for (int appWidgetId : appWidgetIds) { + RemoteViews views = new RemoteViews(context.getPackageName(), + R.layout.people_space_widget_item); + String shortcutId = sp.getString(String.valueOf(appWidgetId), null); + if (DEBUG) { + Log.d(TAG, "Set widget: " + appWidgetId + " with shortcut ID: " + shortcutId); + } + + Optional> entry = shortcutInfos.stream().filter( + e -> e.getValue().getId().equals(shortcutId)).findFirst(); + if (!entry.isPresent() || shortcutId == null) { + if (DEBUG) Log.d(TAG, "Matching conversation not found for shortcut ID"); + AppWidgetHost host = new AppWidgetHost(context, 0); + host.deleteAppWidgetId(appWidgetId); + continue; + } + PeopleSpaceTile tile = entry.get().getValue(); + + String status = PeopleSpaceUtils.getLastInteractionString(context, + entry.get().getKey()); + views.setTextViewText(R.id.status, status); + views.setTextViewText(R.id.name, tile.getUserName().toString()); + + activityIntent.putExtra(PeopleSpaceWidgetProvider.EXTRA_TILE_ID, tile.getId()); + activityIntent.putExtra( + PeopleSpaceWidgetProvider.EXTRA_PACKAGE_NAME, tile.getPackageName()); + activityIntent.putExtra(PeopleSpaceWidgetProvider.EXTRA_UID, tile.getUid()); + views.setOnClickPendingIntent(R.id.item, PendingIntent.getActivity( + context, + appWidgetId, + activityIntent, + PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE)); + + views.setImageViewBitmap( + R.id.package_icon, + PeopleSpaceUtils.convertDrawableToBitmap( + mPackageManager.getApplicationIcon(tile.getPackageName()) + ) + ); + views.setImageViewIcon(R.id.person_icon, tile.getUserIcon()); + // Tell the AppWidgetManager to perform an update on the current app widget. + appWidgetManager.updateAppWidget(appWidgetId, views); + } + } catch (Exception e) { + Log.e(TAG, "Failed to retrieve conversations to set tiles"); + } + } + /** Returns a list sorted by ascending last interaction time from {@code stream}. */ private static List> getSortedTiles( IPeopleManager peopleManager, Stream stream) { diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java index 9b7cf6e85ada8..ac32e193d9f64 100644 --- a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java +++ b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java @@ -16,11 +16,14 @@ package com.android.systemui.people.widget; +import android.app.INotificationManager; import android.app.NotificationChannel; +import android.appwidget.AppWidgetManager; import android.content.ComponentName; import android.content.Context; import android.os.ServiceManager; import android.os.UserHandle; +import android.provider.Settings; import android.service.notification.NotificationListenerService; import android.service.notification.StatusBarNotification; import android.util.Log; @@ -42,13 +45,18 @@ public class PeopleSpaceWidgetManager { private static final boolean DEBUG = PeopleSpaceUtils.DEBUG; private final Context mContext; - private IAppWidgetService mAppWidgetManager; + private IAppWidgetService mAppWidgetService; + private AppWidgetManager mAppWidgetManager; + private INotificationManager mNotificationManager; @Inject public PeopleSpaceWidgetManager(Context context, IAppWidgetService appWidgetService) { if (DEBUG) Log.d(TAG, "constructor"); mContext = context; - mAppWidgetManager = appWidgetService; + mAppWidgetService = appWidgetService; + mAppWidgetManager = AppWidgetManager.getInstance(context); + mNotificationManager = INotificationManager.Stub.asInterface( + ServiceManager.getService(Context.NOTIFICATION_SERVICE)); } /** Constructor used for testing. */ @@ -56,21 +64,24 @@ public class PeopleSpaceWidgetManager { protected PeopleSpaceWidgetManager(Context context) { if (DEBUG) Log.d(TAG, "constructor"); mContext = context; - mAppWidgetManager = IAppWidgetService.Stub.asInterface( + mAppWidgetService = IAppWidgetService.Stub.asInterface( ServiceManager.getService(Context.APPWIDGET_SERVICE)); } /** AppWidgetManager setter used for testing. */ @VisibleForTesting - protected void setAppWidgetManager(IAppWidgetService appWidgetService) { - mAppWidgetManager = appWidgetService; + protected void setAppWidgetManager(IAppWidgetService appWidgetService, + AppWidgetManager appWidgetManager, INotificationManager notificationManager) { + mAppWidgetService = appWidgetService; + mAppWidgetManager = appWidgetManager; + mNotificationManager = notificationManager; } /** Updates People Space widgets. */ public void updateWidgets() { try { if (DEBUG) Log.d(TAG, "updateWidgets called"); - int[] widgetIds = mAppWidgetManager.getAppWidgetIds( + int[] widgetIds = mAppWidgetService.getAppWidgetIds( new ComponentName(mContext, PeopleSpaceWidgetProvider.class) ); @@ -80,9 +91,16 @@ public class PeopleSpaceWidgetManager { } if (DEBUG) Log.d(TAG, "updating " + widgetIds.length + " widgets"); - mAppWidgetManager - .notifyAppWidgetViewDataChanged(mContext.getOpPackageName(), widgetIds, - R.id.widget_list_view); + boolean showSingleConversation = Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0) == 0; + if (showSingleConversation) { + PeopleSpaceUtils.updateSingleConversationWidgets(mContext, widgetIds, + mAppWidgetManager, mNotificationManager); + } else { + mAppWidgetService + .notifyAppWidgetViewDataChanged(mContext.getOpPackageName(), widgetIds, + R.id.widget_list_view); + } } catch (Exception e) { Log.e(TAG, "Exception: " + e); } @@ -125,7 +143,8 @@ public class PeopleSpaceWidgetManager { @Override public void onNotificationRankingUpdate( - NotificationListenerService.RankingMap rankingMap) { } + NotificationListenerService.RankingMap rankingMap) { + } @Override public void onNotificationsInitialized() { 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 9f84514f8c47d..1ee9e0ea728d7 100644 --- a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetProvider.java +++ b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetProvider.java @@ -16,11 +16,14 @@ package com.android.systemui.people.widget; +import android.app.INotificationManager; import android.app.PendingIntent; import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProvider; import android.content.Context; import android.content.Intent; +import android.os.ServiceManager; +import android.provider.Settings; import android.util.Log; import android.widget.RemoteViews; @@ -41,6 +44,14 @@ public class PeopleSpaceWidgetProvider extends AppWidgetProvider { super.onUpdate(context, appWidgetManager, appWidgetIds); if (DEBUG) Log.d(TAG, "onUpdate called"); + boolean showSingleConversation = Settings.Global.getInt(context.getContentResolver(), + Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0) == 0; + if (showSingleConversation) { + PeopleSpaceUtils.updateSingleConversationWidgets(context, appWidgetIds, + appWidgetManager, INotificationManager.Stub.asInterface( + ServiceManager.getService(Context.NOTIFICATION_SERVICE))); + return; + } // Perform this loop procedure for each App Widget that belongs to this provider for (int appWidgetId : appWidgetIds) { RemoteViews views = diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java index 477fe6316399c..019424cd48f03 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java @@ -29,12 +29,20 @@ import static org.mockito.Mockito.when; import static java.util.Objects.requireNonNull; +import android.app.INotificationManager; import android.app.NotificationChannel; -import android.content.Context; +import android.appwidget.AppWidgetManager; +import android.content.SharedPreferences; +import android.content.pm.ParceledListSlice; +import android.content.pm.ShortcutInfo; import android.os.RemoteException; import android.os.UserHandle; +import android.provider.Settings; +import android.service.notification.ConversationChannelWrapper; import android.testing.AndroidTestingRunner; +import android.widget.RemoteViews; +import androidx.preference.PreferenceManager; import androidx.test.filters.SmallTest; import com.android.internal.appwidget.IAppWidgetService; @@ -54,6 +62,9 @@ import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.ArrayList; +import java.util.List; + @SmallTest @RunWith(AndroidTestingRunner.class) public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { @@ -65,14 +76,23 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { private static final String TEST_CHANNEL_NAME = "channel_name"; private static final String TEST_PARENT_CHANNEL_ID = "parent_channel_id"; private static final String TEST_CONVERSATION_ID = "conversation_id"; + private static final int WIDGET_ID_WITH_SHORTCUT = 1; + private static final int WIDGET_ID_WITHOUT_SHORTCUT = 2; + private static final String SHORTCUT_ID = "101"; private PeopleSpaceWidgetManager mManager; - @Mock private NotificationListener mListenerService; - @Mock private IAppWidgetService mIAppWidgetService; - @Mock private Context mContext; + @Mock + private NotificationListener mListenerService; + @Mock + private IAppWidgetService mIAppWidgetService; + @Mock + private AppWidgetManager mAppWidgetManager; + @Mock + private INotificationManager mINotificationManager; - @Captor private ArgumentCaptor mListenerCaptor; + @Captor + private ArgumentCaptor mListenerCaptor; private final NoManSimulator mNoMan = new NoManSimulator(); private final FakeSystemClock mClock = new FakeSystemClock(); @@ -80,18 +100,18 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { @Before public void setUp() { MockitoAnnotations.initMocks(this); - mManager = new PeopleSpaceWidgetManager(mContext); - mManager.setAppWidgetManager(mIAppWidgetService); + mManager.setAppWidgetManager(mIAppWidgetService, mAppWidgetManager, mINotificationManager); mManager.attach(mListenerService); verify(mListenerService).addNotificationHandler(mListenerCaptor.capture()); NotificationHandler serviceListener = requireNonNull(mListenerCaptor.getValue()); mNoMan.addListener(serviceListener); + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 2); } - @Test public void testDoNotNotifyAppWidgetIfNoWidgets() throws RemoteException { int[] widgetIdsArray = {}; @@ -105,7 +125,24 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { verify(mIAppWidgetService, times(1)).getAppWidgetIds(any()); verify(mIAppWidgetService, never()).notifyAppWidgetViewDataChanged(any(), any(), anyInt()); + } + @Test + public void testDoNotNotifySingleConversationAppWidgetIfNoWidgets() throws RemoteException { + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0); + int[] widgetIdsArray = {}; + when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray); + + NotifEvent notif1 = mNoMan.postNotif( + new NotificationEntryBuilder() + .setId(0) + .setPkg(TEST_PACKAGE_A)); + mClock.advanceTime(MIN_LINGER_DURATION); + + verify(mIAppWidgetService, times(1)).getAppWidgetIds(any()); + verify(mAppWidgetManager, never()).updateAppWidget(anyInt(), any(RemoteViews.class)); + verify(mIAppWidgetService, never()).notifyAppWidgetViewDataChanged(any(), any(), anyInt()); } @Test @@ -122,7 +159,66 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { verify(mIAppWidgetService, times(1)).getAppWidgetIds(any()); verify(mIAppWidgetService, times(1)) .notifyAppWidgetViewDataChanged(any(), eq(widgetIdsArray), anyInt()); + verify(mIAppWidgetService, never()).updateAppWidgetIds(any(), any(), + any(RemoteViews.class)); + } + @Test + public void testNotifySingleConversationAppWidgetOnceIfNotificationPosted() + throws RemoteException { + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0); + when(mINotificationManager.getConversations(true)).thenReturn( + new ParceledListSlice(getConversationWithShortcutId())); + int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT}; + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext); + SharedPreferences.Editor editor = sp.edit(); + editor.putString(String.valueOf(WIDGET_ID_WITH_SHORTCUT), SHORTCUT_ID); + editor.commit(); + when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray); + + NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder() + .setPkg(TEST_PACKAGE_A) + .setId(1)); + + verify(mIAppWidgetService, times(1)).getAppWidgetIds(any()); + verify(mIAppWidgetService, never()) + .notifyAppWidgetViewDataChanged(any(), eq(widgetIdsArray), anyInt()); + verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT), + any(RemoteViews.class)); + verify(mAppWidgetManager, never()).updateAppWidget(eq(WIDGET_ID_WITHOUT_SHORTCUT), + any(RemoteViews.class)); + } + + @Test + public void testNotifySingleConversationAppWidgetTwiceIfTwoNotificationsPosted() + throws RemoteException { + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0); + when(mINotificationManager.getConversations(true)).thenReturn( + new ParceledListSlice(getConversationWithShortcutId())); + int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT}; + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext); + SharedPreferences.Editor editor = sp.edit(); + editor.putString(String.valueOf(WIDGET_ID_WITH_SHORTCUT), SHORTCUT_ID); + editor.commit(); + when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray); + + NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder() + .setPkg(TEST_PACKAGE_A) + .setId(1)); + mClock.advanceTime(4); + NotifEvent notif2 = mNoMan.postNotif(new NotificationEntryBuilder() + .setPkg(TEST_PACKAGE_B) + .setId(2)); + + verify(mIAppWidgetService, times(2)).getAppWidgetIds(any()); + verify(mIAppWidgetService, never()) + .notifyAppWidgetViewDataChanged(any(), eq(widgetIdsArray), anyInt()); + verify(mAppWidgetManager, times(2)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT), + any(RemoteViews.class)); + verify(mAppWidgetManager, never()).updateAppWidget(eq(WIDGET_ID_WITHOUT_SHORTCUT), + any(RemoteViews.class)); } @Test @@ -141,6 +237,8 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { verify(mIAppWidgetService, times(2)).getAppWidgetIds(any()); verify(mIAppWidgetService, times(2)) .notifyAppWidgetViewDataChanged(any(), eq(widgetIdsArray), anyInt()); + verify(mAppWidgetManager, never()).updateAppWidget(anyInt(), + any(RemoteViews.class)); } @Test @@ -157,6 +255,8 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { verify(mIAppWidgetService, times(2)).getAppWidgetIds(any()); verify(mIAppWidgetService, times(2)) .notifyAppWidgetViewDataChanged(any(), eq(widgetIdsArray), anyInt()); + verify(mAppWidgetManager, never()).updateAppWidget(anyInt(), + any(RemoteViews.class)); } @Test @@ -173,7 +273,8 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { verify(mIAppWidgetService, never()).getAppWidgetIds(any()); verify(mIAppWidgetService, never()).notifyAppWidgetViewDataChanged(any(), any(), anyInt()); - + verify(mAppWidgetManager, never()).updateAppWidget(anyInt(), + any(RemoteViews.class)); } @Test @@ -192,6 +293,17 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { verify(mIAppWidgetService, times(1)).getAppWidgetIds(any()); verify(mIAppWidgetService, times(1)) .notifyAppWidgetViewDataChanged(any(), eq(widgetIdsArray), anyInt()); + verify(mAppWidgetManager, never()).updateAppWidget(anyInt(), + any(RemoteViews.class)); + } + /** Returns a list of a single conversation associated with {@code SHORTCUT_ID}. */ + private List getConversationWithShortcutId() { + List convos = new ArrayList<>(); + ConversationChannelWrapper convo1 = new ConversationChannelWrapper(); + convo1.setShortcutInfo(new ShortcutInfo.Builder(mContext, SHORTCUT_ID).setLongLabel( + "name").build()); + convos.add(convo1); + return convos; } }