Merge "Reloading workspace when the shortcuts permission changes" into ub-launcher3-calgary
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index adf07a1..886c5f0 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -1090,6 +1090,9 @@
         if (!isWorkspaceLoading()) {
             // Process any items that were added while Launcher was away.
             InstallShortcutReceiver.disableAndFlushInstallQueue(this);
+
+            // Refresh shortcuts if the permission changed.
+            mModel.refreshShortcutsIfRequired();
         }
 
         if (shouldShowDiscoveryBounce()) {
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 34660ac..6a63110 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -146,6 +146,20 @@
     // Maps all launcher activities to the id's of their shortcuts (if they have any).
     private final MultiHashMap<ComponentKey, String> mBgDeepShortcutMap = new MultiHashMap<>();
 
+    private boolean mHasShortcutHostPermission;
+    // Runnable to check if the shortcuts permission has changed.
+    private final Runnable mShortcutPermissionCheckRunnable = new Runnable() {
+        @Override
+        public void run() {
+            if (mDeepShortcutsLoaded) {
+                boolean hasShortcutHostPermission = mDeepShortcutManager.hasHostPermission();
+                if (hasShortcutHostPermission != mHasShortcutHostPermission) {
+                    mApp.reloadWorkspace();
+                }
+            }
+        }
+    };
+
     // The lock that must be acquired before referencing any static bg data structures.  Unlike
     // other locks, this one can generally be held long-term because we never expect any of these
     // static data structures to be referenced outside of the worker thread except on the first
@@ -1244,6 +1258,7 @@
             if (resetAllAppsLoaded) mAllAppsLoaded = false;
             if (resetWorkspaceLoaded) mWorkspaceLoaded = false;
             // Always reset deep shortcuts loaded.
+            // TODO: why?
             mDeepShortcutsLoaded = false;
         }
     }
@@ -1299,6 +1314,7 @@
                 // If there is already one running, tell it to stop.
                 stopLoaderLocked();
                 mLoaderTask = new LoaderTask(mApp.getContext(), synchronousBindPage);
+                // TODO: mDeepShortcutsLoaded does not need to be true for synchronous bind.
                 if (synchronousBindPage != PagedView.INVALID_RESTORE_PAGE && mAllAppsLoaded
                         && mWorkspaceLoaded && mDeepShortcutsLoaded && !mIsLoaderTaskRunning) {
                     mLoaderTask.runBindSynchronousPage(synchronousBindPage);
@@ -2793,11 +2809,14 @@
             }
             if (!mDeepShortcutsLoaded) {
                 mBgDeepShortcutMap.clear();
-                for (UserHandleCompat user : mUserManager.getUserProfiles()) {
-                    if (mUserManager.isUserUnlocked(user)) {
-                        List<ShortcutInfoCompat> shortcuts = mDeepShortcutManager
-                                .queryForAllShortcuts(user);
-                        updateDeepShortcutMap(null, user, shortcuts);
+                mHasShortcutHostPermission = mDeepShortcutManager.hasHostPermission();
+                if (mHasShortcutHostPermission) {
+                    for (UserHandleCompat user : mUserManager.getUserProfiles()) {
+                        if (mUserManager.isUserUnlocked(user)) {
+                            List<ShortcutInfoCompat> shortcuts = mDeepShortcutManager
+                                    .queryForAllShortcuts(user);
+                            updateDeepShortcutMap(null, user, shortcuts);
+                        }
                     }
                 }
                 synchronized (LoaderTask.this) {
@@ -2863,6 +2882,18 @@
     }
 
     /**
+     * Refreshes the cached shortcuts if the shortcut permission has changed.
+     * Current implementation simply reloads the workspace, but it can be optimized to
+     * use partial updates similar to {@link UserManagerCompat}
+     */
+    public void refreshShortcutsIfRequired() {
+        if (Utilities.isNycMR1OrAbove()) {
+            sWorker.removeCallbacks(mShortcutPermissionCheckRunnable);
+            sWorker.post(mShortcutPermissionCheckRunnable);
+        }
+    }
+
+    /**
      * Called when the icons for packages have been updated in the icon cache.
      */
     public void onPackageIconsUpdated(HashSet<String> updatedPackages, UserHandleCompat user) {
diff --git a/src/com/android/launcher3/shortcuts/DeepShortcutManager.java b/src/com/android/launcher3/shortcuts/DeepShortcutManager.java
index 05ab843..49d6fa9 100644
--- a/src/com/android/launcher3/shortcuts/DeepShortcutManager.java
+++ b/src/com/android/launcher3/shortcuts/DeepShortcutManager.java
@@ -224,4 +224,16 @@
             return Collections.EMPTY_LIST;
         }
     }
+
+    @TargetApi(25)
+    public boolean hasHostPermission() {
+        if (Utilities.isNycMR1OrAbove()) {
+            try {
+                return mLauncherApps.hasShortcutHostPermission();
+            } catch (SecurityException|IllegalStateException e) {
+                Log.e(TAG, "Failed to make shortcut manager call", e);
+            }
+        }
+        return false;
+    }
 }