Merge "Add ToggleableGlobalSettingsFlag for QUICK_SWITCH" into ub-launcher3-master
diff --git a/Android.mk b/Android.mk
index 422c6f0..d9e4641 100644
--- a/Android.mk
+++ b/Android.mk
@@ -76,7 +76,7 @@
     androidx.recyclerview_recyclerview \
     androidx.dynamicanimation_dynamicanimation \
     androidx.preference_preference \
-    iconloader
+    iconloader_base
 
 LOCAL_STATIC_JAVA_LIBRARIES := LauncherPluginLib
 
diff --git a/iconloaderlib/Android.bp b/iconloaderlib/Android.bp
index 8a71f94..f12d16e 100644
--- a/iconloaderlib/Android.bp
+++ b/iconloaderlib/Android.bp
@@ -13,7 +13,7 @@
 // limitations under the License.
 
 android_library {
-    name: "iconloader",
+    name: "iconloader_base",
     sdk_version: "28",
     min_sdk_version: "21",
     static_libs: [
@@ -26,3 +26,19 @@
         "src/**/*.java",
     ],
 }
+
+android_library {
+    name: "iconloader",
+    sdk_version: "system_current",
+    min_sdk_version: "21",
+    static_libs: [
+        "androidx.core_core",
+    ],
+    resource_dirs: [
+        "res",
+    ],
+    srcs: [
+        "src/**/*.java",
+        "src_full_lib/**/*.java",
+    ],
+}
diff --git a/iconloaderlib/build.gradle b/iconloaderlib/build.gradle
index a6433ad..f6a820a 100644
--- a/iconloaderlib/build.gradle
+++ b/iconloaderlib/build.gradle
@@ -24,7 +24,7 @@
 
     sourceSets {
         main {
-            java.srcDirs = ['src']
+            java.srcDirs = ['src', 'src_full_lib']
             manifest.srcFile 'AndroidManifest.xml'
             res.srcDirs = ['res']
         }
diff --git a/iconloaderlib/res/values/config.xml b/iconloaderlib/res/values/config.xml
new file mode 100644
index 0000000..68c2d2e
--- /dev/null
+++ b/iconloaderlib/res/values/config.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2018, 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.
+*/
+-->
+<resources>
+
+    <!-- Various configurations to control the simple cache implementation -->
+
+    <dimen name="default_icon_bitmap_size">56dp</dimen>
+    <bool name="simple_cache_enable_im_memory">false</bool>
+    <string name="cache_db_name" translatable="false">app_icons.db</string>
+
+</resources>
\ No newline at end of file
diff --git a/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java b/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java
index 065a14d..a318574 100644
--- a/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java
+++ b/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java
@@ -1,5 +1,10 @@
 package com.android.launcher3.icons;
 
+import static android.graphics.Paint.DITHER_FLAG;
+import static android.graphics.Paint.FILTER_BITMAP_FLAG;
+
+import static com.android.launcher3.icons.ShadowGenerator.BLUR_FACTOR;
+
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
@@ -18,29 +23,26 @@
 import android.os.Process;
 import android.os.UserHandle;
 
-import static android.graphics.Paint.DITHER_FLAG;
-import static android.graphics.Paint.FILTER_BITMAP_FLAG;
-import static com.android.launcher3.icons.ShadowGenerator.BLUR_FACTOR;
-
 /**
  * This class will be moved to androidx library. There shouldn't be any dependency outside
  * this package.
  */
 public class BaseIconFactory implements AutoCloseable {
 
+    private static final String TAG = "BaseIconFactory";
     private static final int DEFAULT_WRAPPER_BACKGROUND = Color.WHITE;
     static final boolean ATLEAST_OREO = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O;
     static final boolean ATLEAST_P = Build.VERSION.SDK_INT >= Build.VERSION_CODES.P;
 
     private final Rect mOldBounds = new Rect();
-    private final Context mContext;
+    protected final Context mContext;
     private final Canvas mCanvas;
     private final PackageManager mPm;
     private final ColorExtractor mColorExtractor;
     private boolean mDisableColorExtractor;
 
-    private int mFillResIconDpi;
-    private int mIconBitmapSize;
+    protected final int mFillResIconDpi;
+    protected final int mIconBitmapSize;
 
     private IconNormalizer mNormalizer;
     private ShadowGenerator mShadowGenerator;
@@ -302,7 +304,21 @@
     }
 
     @Override
-    public void close() { }
+    public void close() {
+        clear();
+    }
+
+    public BitmapInfo makeDefaultIcon(UserHandle user) {
+        return createBadgedIconBitmap(getFullResDefaultActivityIcon(mFillResIconDpi),
+                user, Build.VERSION.SDK_INT);
+    }
+
+    public static Drawable getFullResDefaultActivityIcon(int iconDpi) {
+        return Resources.getSystem().getDrawableForDensity(
+                Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
+                        ? android.R.drawable.sym_def_app_icon : android.R.mipmap.sym_def_app_icon,
+                iconDpi);
+    }
 
     /**
      * An extension of {@link BitmapDrawable} which returns the bitmap pixel size as intrinsic size.
diff --git a/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java b/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java
index 2fa4b68..63820f6 100644
--- a/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java
+++ b/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java
@@ -15,6 +15,7 @@
  */
 package com.android.launcher3.icons.cache;
 
+import static com.android.launcher3.icons.BaseIconFactory.getFullResDefaultActivityIcon;
 import static com.android.launcher3.icons.BitmapInfo.LOW_RES_ICON;
 import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
 
@@ -34,7 +35,6 @@
 import android.graphics.BitmapFactory;
 import android.graphics.drawable.Drawable;
 import android.os.Build;
-import android.os.Build.VERSION;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Process;
@@ -50,9 +50,13 @@
 import com.android.launcher3.util.Provider;
 import com.android.launcher3.util.SQLiteCacheHelper;
 
+import java.util.AbstractMap;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
 
 import androidx.annotation.NonNull;
 
@@ -76,8 +80,7 @@
     protected final Context mContext;
     protected final PackageManager mPackageManager;
 
-    private final HashMap<ComponentKey, CacheEntry> mCache =
-            new HashMap<>(INITIAL_ICON_CACHE_CAPACITY);
+    private final Map<ComponentKey, CacheEntry> mCache;
     protected final Handler mWorkerHandler;
 
     protected int mIconDpi;
@@ -89,13 +92,30 @@
     private final Looper mBgLooper;
 
     public BaseIconCache(Context context, String dbFileName, Looper bgLooper,
-            int iconDpi, int iconPixelSize) {
+            int iconDpi, int iconPixelSize, boolean inMemoryCache) {
         mContext = context;
         mDbFileName = dbFileName;
         mPackageManager = context.getPackageManager();
         mBgLooper = bgLooper;
         mWorkerHandler = new Handler(mBgLooper);
 
+        if (inMemoryCache) {
+            mCache = new HashMap<>(INITIAL_ICON_CACHE_CAPACITY);
+        } else {
+            // Use a dummy cache
+            mCache = new AbstractMap<ComponentKey, CacheEntry>() {
+                @Override
+                public Set<Entry<ComponentKey, CacheEntry>> entrySet() {
+                    return Collections.emptySet();
+                }
+
+                @Override
+                public CacheEntry put(ComponentKey key, CacheEntry value) {
+                    return value;
+                }
+            };
+        }
+
         if (BitmapRenderer.USE_HARDWARE_BITMAP && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
             mDecodeOptions = new BitmapFactory.Options();
             mDecodeOptions.inPreferredConfig = Bitmap.Config.HARDWARE;
@@ -137,27 +157,20 @@
         mCache.clear();
     }
 
-    private Drawable getFullResDefaultActivityIcon() {
-        return Resources.getSystem().getDrawableForDensity(
-                Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
-                        ? android.R.drawable.sym_def_app_icon : android.R.mipmap.sym_def_app_icon,
-                mIconDpi);
-    }
-
     private Drawable getFullResIcon(Resources resources, int iconId) {
         if (resources != null && iconId != 0) {
             try {
                 return resources.getDrawableForDensity(iconId, mIconDpi);
             } catch (Resources.NotFoundException e) { }
         }
-        return getFullResDefaultActivityIcon();
+        return getFullResDefaultActivityIcon(mIconDpi);
     }
 
     public Drawable getFullResIcon(String packageName, int iconId) {
         try {
             return getFullResIcon(mPackageManager.getResourcesForApplication(packageName), iconId);
         } catch (PackageManager.NameNotFoundException e) { }
-        return getFullResDefaultActivityIcon();
+        return getFullResDefaultActivityIcon(mIconDpi);
     }
 
     public Drawable getFullResIcon(ActivityInfo info) {
@@ -165,13 +178,12 @@
             return getFullResIcon(mPackageManager.getResourcesForApplication(info.applicationInfo),
                     info.getIconResource());
         } catch (PackageManager.NameNotFoundException e) { }
-        return getFullResDefaultActivityIcon();
+        return getFullResDefaultActivityIcon(mIconDpi);
     }
 
-    protected BitmapInfo makeDefaultIcon(UserHandle user) {
+    private BitmapInfo makeDefaultIcon(UserHandle user) {
         try (BaseIconFactory li = getIconFactory()) {
-            return li.createBadgedIconBitmap(
-                    getFullResDefaultActivityIcon(), user, VERSION.SDK_INT);
+            return li.makeDefaultIcon(user);
         }
     }
 
diff --git a/iconloaderlib/src_full_lib/com/android/launcher3/icons/IconFactory.java b/iconloaderlib/src_full_lib/com/android/launcher3/icons/IconFactory.java
new file mode 100644
index 0000000..48f11fd
--- /dev/null
+++ b/iconloaderlib/src_full_lib/com/android/launcher3/icons/IconFactory.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2018 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.launcher3.icons;
+
+import android.content.Context;
+
+/**
+ * Wrapper class to provide access to {@link BaseIconFactory} and also to provide pool of this class
+ * that are threadsafe.
+ */
+public class IconFactory extends BaseIconFactory {
+
+    private static final Object sPoolSync = new Object();
+    private static IconFactory sPool;
+    private static int sPoolId = 0;
+
+    /**
+     * Return a new Message instance from the global pool. Allows us to
+     * avoid allocating new objects in many cases.
+     */
+    public static IconFactory obtain(Context context) {
+        int poolId;
+        synchronized (sPoolSync) {
+            if (sPool != null) {
+                IconFactory m = sPool;
+                sPool = m.next;
+                m.next = null;
+                return m;
+            }
+            poolId = sPoolId;
+        }
+
+        return new IconFactory(context,
+                context.getResources().getConfiguration().densityDpi,
+                context.getResources().getDimensionPixelSize(R.dimen.default_icon_bitmap_size),
+                poolId);
+    }
+
+    public static void clearPool() {
+        synchronized (sPoolSync) {
+            sPool = null;
+            sPoolId++;
+        }
+    }
+
+    private final int mPoolId;
+
+    private IconFactory next;
+
+    private IconFactory(Context context, int fillResIconDpi, int iconBitmapSize, int poolId) {
+        super(context, fillResIconDpi, iconBitmapSize);
+        mPoolId = poolId;
+    }
+
+    /**
+     * Recycles a LauncherIcons that may be in-use.
+     */
+    public void recycle() {
+        synchronized (sPoolSync) {
+            if (sPoolId != mPoolId) {
+                return;
+            }
+            // Clear any temporary state variables
+            clear();
+
+            next = sPool;
+            sPool = this;
+        }
+    }
+
+    @Override
+    public void close() {
+        recycle();
+    }
+}
diff --git a/iconloaderlib/src_full_lib/com/android/launcher3/icons/SimpleIconCache.java b/iconloaderlib/src_full_lib/com/android/launcher3/icons/SimpleIconCache.java
new file mode 100644
index 0000000..1337975
--- /dev/null
+++ b/iconloaderlib/src_full_lib/com/android/launcher3/icons/SimpleIconCache.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2018 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.launcher3.icons;
+
+import static android.content.Intent.ACTION_MANAGED_PROFILE_ADDED;
+import static android.content.Intent.ACTION_MANAGED_PROFILE_REMOVED;
+
+import android.annotation.TargetApi;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.os.Build;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.SparseLongArray;
+
+import com.android.launcher3.icons.cache.BaseIconCache;
+
+/**
+ * Wrapper class to provide access to {@link BaseIconFactory} and also to provide pool of this class
+ * that are threadsafe.
+ */
+@TargetApi(Build.VERSION_CODES.P)
+public class SimpleIconCache extends BaseIconCache {
+
+    private static SimpleIconCache sIconCache = null;
+    private static final Object CACHE_LOCK = new Object();
+
+    private final SparseLongArray mUserSerialMap = new SparseLongArray(2);
+    private final UserManager mUserManager;
+
+    public SimpleIconCache(Context context, String dbFileName, Looper bgLooper, int iconDpi,
+            int iconPixelSize, boolean inMemoryCache) {
+        super(context, dbFileName, bgLooper, iconDpi, iconPixelSize, inMemoryCache);
+        mUserManager = context.getSystemService(UserManager.class);
+
+        // Listen for user cache changes.
+        IntentFilter filter = new IntentFilter(ACTION_MANAGED_PROFILE_ADDED);
+        filter.addAction(ACTION_MANAGED_PROFILE_REMOVED);
+        context.registerReceiver(new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                resetUserCache();
+            }
+        }, filter, null, new Handler(bgLooper), 0);
+    }
+
+    @Override
+    protected long getSerialNumberForUser(UserHandle user) {
+        synchronized (mUserSerialMap) {
+            int index = mUserSerialMap.indexOfKey(user.getIdentifier());
+            if (index >= 0) {
+                return mUserSerialMap.valueAt(index);
+            }
+            long serial = mUserManager.getSerialNumberForUser(user);
+            mUserSerialMap.put(user.getIdentifier(), serial);
+            return serial;
+        }
+    }
+
+    private void resetUserCache() {
+        synchronized (mUserSerialMap) {
+            mUserSerialMap.clear();
+        }
+    }
+
+    @Override
+    protected boolean isInstantApp(ApplicationInfo info) {
+        return info.isInstantApp();
+    }
+
+    @Override
+    protected BaseIconFactory getIconFactory() {
+        return IconFactory.obtain(mContext);
+    }
+
+    public static SimpleIconCache getIconCache(Context context) {
+        synchronized (CACHE_LOCK) {
+            if (sIconCache != null) {
+                return sIconCache;
+            }
+            boolean inMemoryCache =
+                    context.getResources().getBoolean(R.bool.simple_cache_enable_im_memory);
+            String dbFileName = context.getString(R.string.cache_db_name);
+
+            HandlerThread bgThread = new HandlerThread("simple-icon-cache");
+            bgThread.start();
+
+            sIconCache = new SimpleIconCache(context.getApplicationContext(), dbFileName,
+                    bgThread.getLooper(), context.getResources().getConfiguration().densityDpi,
+                    context.getResources().getDimensionPixelSize(R.dimen.default_icon_bitmap_size),
+                    inMemoryCache);
+            return sIconCache;
+        }
+    }
+}
diff --git a/src/com/android/launcher3/icons/IconCache.java b/src/com/android/launcher3/icons/IconCache.java
index 6bb9dab..4b54bc3 100644
--- a/src/com/android/launcher3/icons/IconCache.java
+++ b/src/com/android/launcher3/icons/IconCache.java
@@ -72,7 +72,7 @@
 
     public IconCache(Context context, InvariantDeviceProfile inv) {
         super(context, LauncherFiles.APP_ICONS_DB, LauncherModel.getWorkerLooper(),
-                inv.fillResIconDpi, inv.iconBitmapSize);
+                inv.fillResIconDpi, inv.iconBitmapSize, true /* inMemoryCache */);
         mComponentWithLabelCachingLogic = new ComponentCachingLogic(context);
         mLauncherActivityInfoCachingLogic = new LauncherActivtiyCachingLogic(this);
         mLauncherApps = LauncherAppsCompat.getInstance(mContext);
diff --git a/src/com/android/launcher3/icons/LauncherIcons.java b/src/com/android/launcher3/icons/LauncherIcons.java
index 153c565..4b869cf 100644
--- a/src/com/android/launcher3/icons/LauncherIcons.java
+++ b/src/com/android/launcher3/icons/LauncherIcons.java
@@ -73,18 +73,12 @@
         }
     }
 
-    private final Context mContext;
-    private final int mFillResIconDpi;
-    private final int mIconBitmapSize;
     private final int mPoolId;
 
     private LauncherIcons next;
 
     private LauncherIcons(Context context, int fillResIconDpi, int iconBitmapSize, int poolId) {
         super(context, fillResIconDpi, iconBitmapSize);
-        mContext = context.getApplicationContext();
-        mFillResIconDpi = fillResIconDpi;
-        mIconBitmapSize = iconBitmapSize;
         mPoolId = poolId;
     }
 
diff --git a/tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java b/tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java
index c39d712..afe9dc6 100644
--- a/tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java
+++ b/tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java
@@ -227,10 +227,5 @@
         public Bitmap newIcon() {
             return Bitmap.createBitmap(1, 1, Config.ARGB_8888);
         }
-
-        @Override
-        protected BitmapInfo makeDefaultIcon(UserHandle user) {
-            return BitmapInfo.fromBitmap(newIcon());
-        }
     }
 }