summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/com/android/launcher3/InvariantDeviceProfile.java71
-rw-r--r--src/com/android/launcher3/LauncherAppState.java16
-rw-r--r--src/com/android/launcher3/config/BaseFlags.java7
-rw-r--r--src/com/android/launcher3/icons/BaseIconCache.java24
-rw-r--r--src/com/android/launcher3/icons/LauncherIcons.java45
-rw-r--r--src/com/android/launcher3/util/ConfigMonitor.java49
-rw-r--r--src/com/android/launcher3/util/SQLiteCacheHelper.java4
7 files changed, 168 insertions, 48 deletions
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index f3f2238e3..0b2f4d921 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -16,6 +16,8 @@
package com.android.launcher3;
+import static com.android.launcher3.config.FeatureFlags.APPLY_CONFIG_AT_RUNTIME;
+
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.Configuration;
@@ -23,6 +25,7 @@ import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.graphics.Point;
import android.util.DisplayMetrics;
+import android.util.Log;
import android.util.Xml;
import android.view.Display;
import android.view.WindowManager;
@@ -45,13 +48,13 @@ public class InvariantDeviceProfile {
// We do not need any synchronization for this variable as its only written on UI thread.
public static final MainThreadInitializedObject<InvariantDeviceProfile> INSTANCE =
- new MainThreadInitializedObject<>((c) -> {
- new ConfigMonitor(c).register();
- return new InvariantDeviceProfile(c);
- });
+ new MainThreadInitializedObject<>(InvariantDeviceProfile::new);
private static final float ICON_SIZE_DEFINED_IN_APP_DP = 48;
+ public static final int CHANGE_FLAG_GRID = 1 << 0;
+ public static final int CHANGE_FLAG_ICON_SIZE = 1 << 1;
+
// Constants that affects the interpolation curve between statically defined device profile
// buckets.
private static float KNEARESTNEIGHBOR = 3;
@@ -61,9 +64,9 @@ public class InvariantDeviceProfile {
private static float WEIGHT_EFFICIENT = 100000f;
// Profile-defining invariant properties
- String name;
- float minWidthDps;
- float minHeightDps;
+ private String name;
+ private float minWidthDps;
+ private float minHeightDps;
/**
* Number of icons per row and column in the workspace.
@@ -95,9 +98,11 @@ public class InvariantDeviceProfile {
public Point defaultWallpaperSize;
+ private final ArrayList<OnIDPChangeListener> mChangeListeners = new ArrayList<>();
+ private ConfigMonitor mConfigMonitor;
+
@VisibleForTesting
- public InvariantDeviceProfile() {
- }
+ public InvariantDeviceProfile() {}
private InvariantDeviceProfile(InvariantDeviceProfile p) {
this(p.name, p.minWidthDps, p.minHeightDps, p.numRows, p.numColumns,
@@ -125,6 +130,12 @@ public class InvariantDeviceProfile {
@TargetApi(23)
private InvariantDeviceProfile(Context context) {
+ initGrid(context);
+ mConfigMonitor = new ConfigMonitor(context,
+ APPLY_CONFIG_AT_RUNTIME.get() ? this::onConfigChanged : this::killProcess);
+ }
+
+ private void initGrid(Context context) {
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
DisplayMetrics dm = new DisplayMetrics();
@@ -185,6 +196,44 @@ public class InvariantDeviceProfile {
}
}
+ public void addOnChangeListener(OnIDPChangeListener listener) {
+ mChangeListeners.add(listener);
+ }
+
+ private void killProcess(Context context) {
+ Log.e("ConfigMonitor", "restarting launcher");
+ android.os.Process.killProcess(android.os.Process.myPid());
+ }
+
+ private void onConfigChanged(Context context) {
+ // Config changes, what shall we do?
+ InvariantDeviceProfile oldProfile = new InvariantDeviceProfile(this);
+
+ // Re-init grid
+ initGrid(context);
+
+ int changeFlags = 0;
+ if (numRows != oldProfile.numRows ||
+ numColumns != oldProfile.numColumns ||
+ numFolderColumns != oldProfile.numFolderColumns ||
+ numFolderRows != oldProfile.numFolderRows ||
+ numHotseatIcons != oldProfile.numHotseatIcons) {
+ changeFlags |= CHANGE_FLAG_GRID;
+ }
+
+ if (iconSize != oldProfile.iconSize || iconBitmapSize != oldProfile.iconBitmapSize) {
+ changeFlags |= CHANGE_FLAG_ICON_SIZE;
+ }
+
+ // Create a new config monitor
+ mConfigMonitor.unregister();
+ mConfigMonitor = new ConfigMonitor(context, this::onConfigChanged);
+
+ for (OnIDPChangeListener listener : mChangeListeners) {
+ listener.onIdpChanged(changeFlags, this);
+ }
+ }
+
ArrayList<InvariantDeviceProfile> getPredefinedDeviceProfiles(Context context) {
ArrayList<InvariantDeviceProfile> profiles = new ArrayList<>();
try (XmlResourceParser parser = context.getResources().getXml(R.xml.device_profiles)) {
@@ -356,4 +405,8 @@ public class InvariantDeviceProfile {
return x * aspectRatio + y;
}
+ public interface OnIDPChangeListener {
+
+ void onIdpChanged(int changeFlags, InvariantDeviceProfile profile);
+ }
} \ No newline at end of file
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index 6bf581277..338c20bbc 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -17,6 +17,7 @@
package com.android.launcher3;
import static com.android.launcher3.util.SecureSettingsObserver.newNotificationSettingsObserver;
+import static com.android.launcher3.InvariantDeviceProfile.CHANGE_FLAG_ICON_SIZE;
import android.content.ComponentName;
import android.content.ContentProviderClient;
@@ -30,6 +31,7 @@ import com.android.launcher3.compat.PackageInstallerCompat;
import com.android.launcher3.compat.UserManagerCompat;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.icons.IconCache;
+import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.notification.NotificationListener;
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.Preconditions;
@@ -94,6 +96,7 @@ public class LauncherAppState {
mContext.registerReceiver(mModel, filter);
UserManagerCompat.getInstance(mContext).enableAndResetCache();
+ mInvariantDeviceProfile.addOnChangeListener(this::onIdpChanged);
if (!mContext.getResources().getBoolean(R.bool.notification_badging_enabled)) {
mNotificationBadgingObserver = null;
@@ -113,6 +116,19 @@ public class LauncherAppState {
}
}
+ private void onIdpChanged(int changeFlags, InvariantDeviceProfile idp) {
+ if (changeFlags == 0) {
+ return;
+ }
+
+ if ((changeFlags & CHANGE_FLAG_ICON_SIZE) != 0) {
+ LauncherIcons.clearPool();
+ mIconCache.updateIconParams(idp.fillResIconDpi, idp.iconBitmapSize);
+ }
+
+ mModel.forceReload();
+ }
+
/**
* Call from Application.onTerminate(), which is not guaranteed to ever be called.
*/
diff --git a/src/com/android/launcher3/config/BaseFlags.java b/src/com/android/launcher3/config/BaseFlags.java
index dc60c8fff..290d8c499 100644
--- a/src/com/android/launcher3/config/BaseFlags.java
+++ b/src/com/android/launcher3/config/BaseFlags.java
@@ -84,6 +84,12 @@ abstract class BaseFlags {
// trying to make them fit the orientation the device is in.
public static final boolean OVERVIEW_USE_SCREENSHOT_ORIENTATION = true;
+ /**
+ * Feature flag to handle define config changes dynamically instead of killing the process.
+ */
+ public static final TogglableFlag APPLY_CONFIG_AT_RUNTIME = new TogglableFlag(
+ "APPLY_CONFIG_AT_RUNTIME", false, "Apply display changes dynamically");
+
public static void initialize(Context context) {
// Avoid the disk read for builds without the flags UI.
if (showFlagTogglerUi()) {
@@ -188,5 +194,4 @@ abstract class BaseFlags {
return h$;
}
}
-
}
diff --git a/src/com/android/launcher3/icons/BaseIconCache.java b/src/com/android/launcher3/icons/BaseIconCache.java
index 6433103f9..5b74d1da1 100644
--- a/src/com/android/launcher3/icons/BaseIconCache.java
+++ b/src/com/android/launcher3/icons/BaseIconCache.java
@@ -90,11 +90,11 @@ public class BaseIconCache {
private final HashMap<ComponentKey, CacheEntry> mCache =
new HashMap<>(INITIAL_ICON_CACHE_CAPACITY);
private final InstantAppResolver mInstantAppResolver;
- final int mIconDpi;
-
- final IconDB mIconDb;
final Handler mWorkerHandler;
+ int mIconDpi;
+ IconDB mIconDb;
+
private final BitmapFactory.Options mDecodeOptions;
public BaseIconCache(Context context, int iconDpi, int iconPixelSize) {
@@ -103,8 +103,6 @@ public class BaseIconCache {
mUserManager = UserManagerCompat.getInstance(mContext);
mLauncherApps = LauncherAppsCompat.getInstance(mContext);
mInstantAppResolver = InstantAppResolver.newInstance(mContext);
- mIconDpi = iconDpi;
- mIconDb = new IconDB(context, iconPixelSize);
mIconProvider = IconProvider.newInstance(context);
mWorkerHandler = new Handler(LauncherModel.getWorkerLooper());
@@ -115,6 +113,22 @@ public class BaseIconCache {
} else {
mDecodeOptions = null;
}
+
+ mIconDpi = iconDpi;
+ mIconDb = new IconDB(context, iconPixelSize);
+ }
+
+ public void updateIconParams(int iconDpi, int iconPixelSize) {
+ mWorkerHandler.post(() -> updateIconParamsBg(iconDpi, iconPixelSize));
+ }
+
+ private synchronized void updateIconParamsBg(int iconDpi, int iconPixelSize) {
+ mIconDpi = iconDpi;
+ mDefaultIcons.clear();
+
+ mIconDb.close();
+ mIconDb = new IconDB(mContext, iconPixelSize);
+ mCache.clear();
}
private Drawable getFullResDefaultActivityIcon() {
diff --git a/src/com/android/launcher3/icons/LauncherIcons.java b/src/com/android/launcher3/icons/LauncherIcons.java
index 69614a3cb..c96d35db5 100644
--- a/src/com/android/launcher3/icons/LauncherIcons.java
+++ b/src/com/android/launcher3/icons/LauncherIcons.java
@@ -27,11 +27,11 @@ import android.os.UserHandle;
import com.android.launcher3.AppInfo;
import com.android.launcher3.FastBitmapDrawable;
-import com.android.launcher3.graphics.BitmapRenderer;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.ItemInfoWithIcon;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.Utilities;
+import com.android.launcher3.graphics.BitmapRenderer;
import com.android.launcher3.model.PackageItemInfo;
import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.shortcuts.ShortcutInfoCompat;
@@ -48,13 +48,14 @@ public class LauncherIcons extends BaseIconFactory implements AutoCloseable {
private static final Object sPoolSync = new Object();
private static LauncherIcons sPool;
- private LauncherIcons next;
+ 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 LauncherIcons obtain(Context context) {
+ int poolId;
synchronized (sPoolSync) {
if (sPool != null) {
LauncherIcons m = sPool;
@@ -62,9 +63,33 @@ public class LauncherIcons extends BaseIconFactory implements AutoCloseable {
m.next = null;
return m;
}
+ poolId = sPoolId;
}
+
InvariantDeviceProfile idp = LauncherAppState.getIDP(context);
- return new LauncherIcons(context, idp.fillResIconDpi, idp.iconBitmapSize);
+ return new LauncherIcons(context, idp.fillResIconDpi, idp.iconBitmapSize, poolId);
+ }
+
+ public static void clearPool() {
+ synchronized (sPoolSync) {
+ sPool = null;
+ sPoolId++;
+ }
+ }
+
+ 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;
}
/**
@@ -72,6 +97,9 @@ public class LauncherIcons extends BaseIconFactory implements AutoCloseable {
*/
public void recycle() {
synchronized (sPoolSync) {
+ if (sPoolId != mPoolId) {
+ return;
+ }
// Clear any temporary state variables
clear();
@@ -85,17 +113,6 @@ public class LauncherIcons extends BaseIconFactory implements AutoCloseable {
recycle();
}
- private final Context mContext;
- private final int mFillResIconDpi;
- private final int mIconBitmapSize;
-
- private LauncherIcons(Context context, int fillResIconDpi, int iconBitmapSize) {
- super(context, fillResIconDpi, iconBitmapSize);
- mContext = context.getApplicationContext();
- mFillResIconDpi = fillResIconDpi;
- mIconBitmapSize = iconBitmapSize;
- }
-
public BitmapInfo createBadgedIconBitmap(Drawable icon, UserHandle user,
int iconAppTargetSdk) {
return createBadgedIconBitmap(icon, user, iconAppTargetSdk, false);
diff --git a/src/com/android/launcher3/util/ConfigMonitor.java b/src/com/android/launcher3/util/ConfigMonitor.java
index 5dd0d08d6..717acdccb 100644
--- a/src/com/android/launcher3/util/ConfigMonitor.java
+++ b/src/com/android/launcher3/util/ConfigMonitor.java
@@ -29,9 +29,12 @@ import android.util.Log;
import android.view.Display;
import android.view.WindowManager;
+import com.android.launcher3.MainThreadExecutor;
+import com.android.launcher3.Utilities.Consumer;
+
/**
* {@link BroadcastReceiver} which watches configuration changes and
- * restarts the process in case changes which affect the device profile occur.
+ * notifies the callback in case changes which affect the device profile occur.
*/
public class ConfigMonitor extends BroadcastReceiver implements DisplayListener {
@@ -48,7 +51,9 @@ public class ConfigMonitor extends BroadcastReceiver implements DisplayListener
private final Point mRealSize;
private final Point mSmallestSize, mLargestSize;
- public ConfigMonitor(Context context) {
+ private Consumer<Context> mCallback;
+
+ public ConfigMonitor(Context context, Consumer<Context> callback) {
mContext = context;
Configuration config = context.getResources().getConfiguration();
@@ -64,6 +69,12 @@ public class ConfigMonitor extends BroadcastReceiver implements DisplayListener
mSmallestSize = new Point();
mLargestSize = new Point();
display.getCurrentSizeRange(mSmallestSize, mLargestSize);
+
+ mCallback = callback;
+
+ mContext.registerReceiver(this, new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED));
+ mContext.getSystemService(DisplayManager.class)
+ .registerDisplayListener(this, new Handler(UiThreadHelper.getBackgroundLooper()));
}
@Override
@@ -71,16 +82,10 @@ public class ConfigMonitor extends BroadcastReceiver implements DisplayListener
Configuration config = context.getResources().getConfiguration();
if (mFontScale != config.fontScale || mDensity != config.densityDpi) {
Log.d(TAG, "Configuration changed");
- killProcess();
+ notifyChange();
}
}
- public void register() {
- mContext.registerReceiver(this, new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED));
- mContext.getSystemService(DisplayManager.class)
- .registerDisplayListener(this, new Handler(UiThreadHelper.getBackgroundLooper()));
- }
-
@Override
public void onDisplayAdded(int displayId) { }
@@ -97,7 +102,7 @@ public class ConfigMonitor extends BroadcastReceiver implements DisplayListener
if (!mRealSize.equals(mTmpPoint1) && !mRealSize.equals(mTmpPoint1.y, mTmpPoint1.x)) {
Log.d(TAG, String.format("Display size changed from %s to %s", mRealSize, mTmpPoint1));
- killProcess();
+ notifyChange();
return;
}
@@ -105,22 +110,28 @@ public class ConfigMonitor extends BroadcastReceiver implements DisplayListener
if (!mSmallestSize.equals(mTmpPoint1) || !mLargestSize.equals(mTmpPoint2)) {
Log.d(TAG, String.format("Available size changed from [%s, %s] to [%s, %s]",
mSmallestSize, mLargestSize, mTmpPoint1, mTmpPoint2));
- killProcess();
+ notifyChange();
}
}
- private void killProcess() {
- Log.d(TAG, "restarting launcher");
- try {
- mContext.unregisterReceiver(this);
- mContext.getSystemService(DisplayManager.class).unregisterDisplayListener(this);
- } catch (Exception e) {
- // We are going to die anyway, ignore any error die to race condition in registering.
+ private synchronized void notifyChange() {
+ if (mCallback != null) {
+ Consumer<Context> callback = mCallback;
+ mCallback = null;
+ new MainThreadExecutor().execute(() -> callback.accept(mContext));
}
- android.os.Process.killProcess(android.os.Process.myPid());
}
private Display getDefaultDisplay(Context context) {
return context.getSystemService(WindowManager.class).getDefaultDisplay();
}
+
+ public void unregister() {
+ try {
+ mContext.unregisterReceiver(this);
+ mContext.getSystemService(DisplayManager.class).unregisterDisplayListener(this);
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to unregister config monitor", e);
+ }
+ }
}
diff --git a/src/com/android/launcher3/util/SQLiteCacheHelper.java b/src/com/android/launcher3/util/SQLiteCacheHelper.java
index 44c1762c3..3faf0709a 100644
--- a/src/com/android/launcher3/util/SQLiteCacheHelper.java
+++ b/src/com/android/launcher3/util/SQLiteCacheHelper.java
@@ -87,6 +87,10 @@ public abstract class SQLiteCacheHelper {
mOpenHelper.clearDB(mOpenHelper.getWritableDatabase());
}
+ public void close() {
+ mOpenHelper.close();
+ }
+
protected abstract void onCreateTable(SQLiteDatabase db);
/**