Merge "Use new widget functionality to reconfigure widget" into sc-dev
diff --git a/packages/SystemUI/res/xml/people_space_widget_info.xml b/packages/SystemUI/res/xml/people_space_widget_info.xml
index b2bf6da..e386147 100644
--- a/packages/SystemUI/res/xml/people_space_widget_info.xml
+++ b/packages/SystemUI/res/xml/people_space_widget_info.xml
@@ -15,12 +15,13 @@
   -->
 
 <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
-    android:minWidth="120dp"
-    android:minHeight="50dp"
+    android:minWidth="136dp"
+    android:minHeight="55dp"
     android:minResizeWidth="60dp"
     android:minResizeHeight="50dp"
     android:maxResizeHeight="207dp"
     android:updatePeriodMillis="60000"
+    android:widgetFeatures="reconfigurable"
     android:description="@string/people_tile_description"
     android:previewLayout="@layout/people_space_placeholder_layout"
     android:resizeMode="horizontal|vertical"
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
index 02c12f6..a0b5521 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
@@ -29,7 +29,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.LauncherApps;
-import android.content.pm.PackageManager;
 import android.content.res.TypedArray;
 import android.graphics.Color;
 import android.graphics.Outline;
@@ -60,7 +59,6 @@
     private IPeopleManager mPeopleManager;
     private PeopleSpaceWidgetManager mPeopleSpaceWidgetManager;
     private INotificationManager mNotificationManager;
-    private PackageManager mPackageManager;
     private LauncherApps mLauncherApps;
     private Context mContext;
     private NotificationEntryManager mNotificationEntryManager;
@@ -81,7 +79,6 @@
         mContext = getApplicationContext();
         mNotificationManager = INotificationManager.Stub.asInterface(
                 ServiceManager.getService(Context.NOTIFICATION_SERVICE));
-        mPackageManager = getPackageManager();
         mPeopleManager = IPeopleManager.Stub.asInterface(
                 ServiceManager.getService(Context.PEOPLE_SERVICE));
         mLauncherApps = mContext.getSystemService(LauncherApps.class);
@@ -112,7 +109,7 @@
             LinearLayout item = findViewById(R.id.item);
             GradientDrawable shape = (GradientDrawable) item.getBackground();
             final TypedArray ta = mContext.obtainStyledAttributes(
-                    new int[] {android.R.attr.colorBackgroundFloating});
+                    new int[]{android.R.attr.colorBackgroundFloating});
             shape.setColor(ta.getColor(0, Color.WHITE));
             return;
         }
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 117be47..d63dc4a 100644
--- a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java
+++ b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java
@@ -95,6 +95,7 @@
     private PeopleManager mPeopleManager;
     private NotificationEntryManager mNotificationEntryManager;
     private PackageManager mPackageManager;
+    private PeopleSpaceWidgetProvider mPeopleSpaceWidgetProvider;
     public UiEventLogger mUiEventLogger = new UiEventLoggerImpl();
     @GuardedBy("mLock")
     public static Map<PeopleTileKey, PeopleSpaceWidgetProvider.TileConversationListener>
@@ -119,6 +120,7 @@
         mPeopleManager = mContext.getSystemService(PeopleManager.class);
         mNotificationEntryManager = Dependency.get(NotificationEntryManager.class);
         mPackageManager = mContext.getPackageManager();
+        mPeopleSpaceWidgetProvider = new PeopleSpaceWidgetProvider();
     }
 
     /**
@@ -129,7 +131,7 @@
             AppWidgetManager appWidgetManager, IPeopleManager iPeopleManager,
             PeopleManager peopleManager, LauncherApps launcherApps,
             NotificationEntryManager notificationEntryManager, PackageManager packageManager,
-            boolean isForTesting) {
+            boolean isForTesting, PeopleSpaceWidgetProvider peopleSpaceWidgetProvider) {
         mAppWidgetManager = appWidgetManager;
         mIPeopleManager = iPeopleManager;
         mPeopleManager = peopleManager;
@@ -137,6 +139,7 @@
         mNotificationEntryManager = notificationEntryManager;
         mPackageManager = packageManager;
         mIsForTesting = isForTesting;
+        mPeopleSpaceWidgetProvider = peopleSpaceWidgetProvider;
     }
 
     /**
@@ -616,7 +619,20 @@
             return;
         }
 
-        mUiEventLogger.log(PeopleSpaceUtils.PeopleSpaceWidgetEvent.PEOPLE_SPACE_WIDGET_ADDED);
+        PeopleTileKey existingKeyIfStored;
+        synchronized (mLock) {
+            existingKeyIfStored = getKeyFromStorageByWidgetId(appWidgetId);
+        }
+        // Delete previous storage if the widget already existed and is just reconfigured.
+        if (existingKeyIfStored.isValid()) {
+            if (DEBUG) Log.d(TAG, "Remove previous storage for widget: " + appWidgetId);
+            deleteWidgets(new int[]{appWidgetId});
+        } else {
+            // Widget newly added.
+            mUiEventLogger.log(
+                    PeopleSpaceUtils.PeopleSpaceWidgetEvent.PEOPLE_SPACE_WIDGET_ADDED);
+        }
+
         synchronized (mLock) {
             if (DEBUG) Log.d(TAG, "Add storage for : " + tile.getId());
             PeopleTileKey key = new PeopleTileKey(tile);
@@ -634,8 +650,7 @@
 
         PeopleSpaceUtils.updateAppWidgetOptionsAndView(
                 mAppWidgetManager, mContext, appWidgetId, tile);
-        PeopleSpaceWidgetProvider provider = new PeopleSpaceWidgetProvider();
-        provider.onUpdate(mContext, mAppWidgetManager, new int[]{appWidgetId});
+        mPeopleSpaceWidgetProvider.onUpdate(mContext, mAppWidgetManager, new int[]{appWidgetId});
     }
 
     /** Registers a conversation listener for {@code appWidgetId} if not already registered. */
@@ -644,12 +659,7 @@
         // Retrieve storage needed for registration.
         PeopleTileKey key;
         synchronized (mLock) {
-            SharedPreferences widgetSp = mContext.getSharedPreferences(String.valueOf(widgetId),
-                    Context.MODE_PRIVATE);
-            key = new PeopleTileKey(
-                    widgetSp.getString(SHORTCUT_ID, EMPTY_STRING),
-                    widgetSp.getInt(USER_ID, INVALID_USER_ID),
-                    widgetSp.getString(PACKAGE_NAME, EMPTY_STRING));
+            key = getKeyFromStorageByWidgetId(widgetId);
             if (!key.isValid()) {
                 if (DEBUG) Log.w(TAG, "Could not register listener for widget: " + widgetId);
                 return;
@@ -669,6 +679,20 @@
                 mContext.getMainExecutor());
     }
 
+    /**
+     * Attempts to get a key from storage for {@code widgetId}, returning null if an invalid key is
+     * found.
+     */
+    private PeopleTileKey getKeyFromStorageByWidgetId(int widgetId) {
+        SharedPreferences widgetSp = mContext.getSharedPreferences(String.valueOf(widgetId),
+                Context.MODE_PRIVATE);
+        PeopleTileKey key = new PeopleTileKey(
+                widgetSp.getString(SHORTCUT_ID, EMPTY_STRING),
+                widgetSp.getInt(USER_ID, INVALID_USER_ID),
+                widgetSp.getString(PACKAGE_NAME, EMPTY_STRING));
+        return key;
+    }
+
     /** Deletes all storage, listeners, and caching for {@code appWidgetIds}. */
     public void deleteWidgets(int[] appWidgetIds) {
         for (int widgetId : appWidgetIds) {
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 d91625e..7125500 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
@@ -186,11 +186,11 @@
         mLauncherApps = mock(LauncherApps.class);
         mDependency.injectTestDependency(NotificationEntryManager.class, mNotificationEntryManager);
         mManager = new PeopleSpaceWidgetManager(mContext);
-        mManager.setAppWidgetManager(mAppWidgetManager, mIPeopleManager, mPeopleManager,
-                mLauncherApps, mNotificationEntryManager, mPackageManager, true);
-        mManager.attach(mListenerService);
         mProvider = new PeopleSpaceWidgetProvider();
         mProvider.setPeopleSpaceWidgetManager(mManager);
+        mManager.setAppWidgetManager(mAppWidgetManager, mIPeopleManager, mPeopleManager,
+                mLauncherApps, mNotificationEntryManager, mPackageManager, true, mProvider);
+        mManager.attach(mListenerService);
 
         verify(mListenerService).addNotificationHandler(mListenerCaptor.capture());
         NotificationHandler serviceListener = requireNonNull(mListenerCaptor.getValue());
@@ -842,6 +842,52 @@
                 any());
     }
 
+
+    @Test
+    public void testAddThenReconfigureWidgetsUpdatesStorageCacheAndListeners()
+            throws Exception {
+        clearStorage();
+        mManager.addNewWidget(WIDGET_ID_WITH_SHORTCUT, PERSON_TILE);
+        // Check storage.
+        SharedPreferences widgetSp = mContext.getSharedPreferences(
+                String.valueOf(WIDGET_ID_WITH_SHORTCUT),
+                Context.MODE_PRIVATE);
+        assertThat(widgetSp.getString(PACKAGE_NAME, null)).isEqualTo(TEST_PACKAGE_A);
+        assertThat(widgetSp.getString(PeopleSpaceUtils.SHORTCUT_ID, null)).isEqualTo(
+                PERSON_TILE.getId());
+        assertThat(widgetSp.getInt(USER_ID, INVALID_USER_ID)).isEqualTo(0);
+        // Check listener and caching.
+        verify(mPeopleManager).registerConversationListener(eq(TEST_PACKAGE_A), anyInt(),
+                eq(SHORTCUT_ID), any(),
+                any());
+        verify(mLauncherApps, times(1)).cacheShortcuts(
+                eq(TEST_PACKAGE_A),
+                eq(Arrays.asList(SHORTCUT_ID)), eq(UserHandle.of(0)),
+                eq(LauncherApps.FLAG_CACHE_PEOPLE_TILE_SHORTCUTS));
+
+        // Reconfigure WIDGET_ID_WITH_SHORTCUT from PERSON_TILE to PERSON_TILE_WITH_SAME_URI
+        mManager.addNewWidget(WIDGET_ID_WITH_SHORTCUT, PERSON_TILE_WITH_SAME_URI);
+
+        // Check listener is removed and shortcut is uncached.
+        verify(mPeopleManager).unregisterConversationListener(any());
+        verify(mLauncherApps).uncacheShortcuts(eq(TEST_PACKAGE_A),
+                eq(Arrays.asList(PERSON_TILE.getId())), eq(UserHandle.of(0)),
+                eq(LauncherApps.FLAG_CACHE_PEOPLE_TILE_SHORTCUTS));
+        // Check reconfigured storage from TEST_PACKAGE_A to B and SHORTCUT_ID to OTHER_SHORTCUT_ID.
+        assertThat(widgetSp.getString(PACKAGE_NAME, null)).isEqualTo(TEST_PACKAGE_B);
+        assertThat(widgetSp.getString(PeopleSpaceUtils.SHORTCUT_ID, null)).isEqualTo(
+                OTHER_SHORTCUT_ID);
+        assertThat(widgetSp.getInt(USER_ID, INVALID_USER_ID)).isEqualTo(0);
+        // Check listener & caching are reconfigured to TEST_PACKAGE_B and OTHER_SHORTCUT_ID.
+        verify(mPeopleManager, times(1)).registerConversationListener(eq(TEST_PACKAGE_B), anyInt(),
+                eq(OTHER_SHORTCUT_ID), any(),
+                any());
+        verify(mLauncherApps, times(1)).cacheShortcuts(
+                eq(TEST_PACKAGE_B),
+                eq(Arrays.asList(OTHER_SHORTCUT_ID)), eq(UserHandle.of(0)),
+                eq(LauncherApps.FLAG_CACHE_PEOPLE_TILE_SHORTCUTS));
+    }
+
     @Test
     public void testDeleteAllWidgetsForConversationsUncachesShortcutAndRemovesListeners()
             throws Exception {