diff options
author | Sunny Goyal <sunnygoyal@google.com> | 2018-10-12 11:42:33 -0700 |
---|---|---|
committer | Sunny Goyal <sunnygoyal@google.com> | 2018-10-19 12:52:17 -0700 |
commit | 87dc48b7bfaa6b7691cc8b8db2433e6f6b5270ef (patch) | |
tree | a8c8f7957ba08ad1e8bd15b55462a32d2a6e4e8e /src | |
parent | 6e11a2d9f275c74e91a8b5af049f6126ed34d176 (diff) | |
download | android_packages_apps_Trebuchet-87dc48b7bfaa6b7691cc8b8db2433e6f6b5270ef.tar.gz android_packages_apps_Trebuchet-87dc48b7bfaa6b7691cc8b8db2433e6f6b5270ef.tar.bz2 android_packages_apps_Trebuchet-87dc48b7bfaa6b7691cc8b8db2433e6f6b5270ef.zip |
Handling configuration changes at runtime instead of killing the process
Change-Id: I0c7f7e58ddb690f371c257b6142a4e918e9acb7f
Diffstat (limited to 'src')
-rw-r--r-- | src/com/android/launcher3/InvariantDeviceProfile.java | 71 | ||||
-rw-r--r-- | src/com/android/launcher3/LauncherAppState.java | 16 | ||||
-rw-r--r-- | src/com/android/launcher3/config/BaseFlags.java | 7 | ||||
-rw-r--r-- | src/com/android/launcher3/icons/BaseIconCache.java | 24 | ||||
-rw-r--r-- | src/com/android/launcher3/icons/LauncherIcons.java | 45 | ||||
-rw-r--r-- | src/com/android/launcher3/util/ConfigMonitor.java | 49 | ||||
-rw-r--r-- | src/com/android/launcher3/util/SQLiteCacheHelper.java | 4 |
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); /** |