Loading src/com/android/launcher3/config/FeatureFlags.java +4 −0 Original line number Diff line number Diff line Loading @@ -277,6 +277,10 @@ public final class FeatureFlags { "ENABLE_DISMISS_PREDICTION_UNDO", false, "Show an 'Undo' snackbar when users dismiss a predicted hotseat item"); public static final BooleanFlag ENABLE_CACHED_WIDGET = getDebugFlag( "ENABLE_CACHED_WIDGET", true, "Show previously cached widgets as opposed to deferred widget where available"); public static void initialize(Context context) { synchronized (sDebugFlags) { for (DebugFlag flag : sDebugFlags) { Loading src/com/android/launcher3/widget/LauncherAppWidgetHost.java +55 −6 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.util.SparseArray; import android.widget.RemoteViews; import android.widget.Toast; import androidx.annotation.Nullable; Loading @@ -37,6 +38,7 @@ import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.LauncherAppState; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.model.WidgetsModel; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.testing.TestLogging; Loading Loading @@ -70,13 +72,14 @@ public class LauncherAppWidgetHost extends AppWidgetHost { private final ArrayList<ProviderChangedListener> mProviderChangeListeners = new ArrayList<>(); private final SparseArray<LauncherAppWidgetHostView> mViews = new SparseArray<>(); private final SparseArray<PendingAppWidgetHostView> mPendingViews = new SparseArray<>(); private final SparseArray<LauncherAppWidgetHostView> mDeferredViews = new SparseArray<>(); private final SparseArray<RemoteViews> mCachedRemoteViews = new SparseArray<>(); private final Context mContext; private int mFlags = FLAG_STATE_IS_NORMAL; private IntConsumer mAppWidgetRemovedCallback = null; public LauncherAppWidgetHost(Context context) { this(context, null); } Loading @@ -95,6 +98,11 @@ public class LauncherAppWidgetHost extends AppWidgetHost { if (mPendingViews.get(appWidgetId) != null) { view = mPendingViews.get(appWidgetId); mPendingViews.remove(appWidgetId); } else if (mDeferredViews.get(appWidgetId) != null) { // In case the widget view is deferred, we will simply return the deferred view as // opposed to instantiate a new instance of LauncherAppWidgetHostView since launcher // already added the former to the workspace. view = mDeferredViews.get(appWidgetId); } else { view = new LauncherAppWidgetHostView(context); } Loading @@ -120,12 +128,25 @@ public class LauncherAppWidgetHost extends AppWidgetHost { // widgets upon bind anyway. See issue 14255011 for more context. } // We go in reverse order and inflate any deferred widget // We go in reverse order and inflate any deferred or cached widget for (int i = mViews.size() - 1; i >= 0; i--) { LauncherAppWidgetHostView view = mViews.valueAt(i); if (view instanceof DeferredAppWidgetHostView) { view.reInflate(); } if (FeatureFlags.ENABLE_CACHED_WIDGET.get()) { final int appWidgetId = mViews.keyAt(i); if (view == mDeferredViews.get(appWidgetId)) { // If the widget view was deferred, we'll need to call super.createView here // to make the binder call to system process to fetch cumulative updates to this // widget, as well as setting up this view for future updates. super.createView(view.mLauncher, appWidgetId, view.getAppWidgetInfo()); // At this point #onCreateView should have been called, which in turn returned // the deferred view. There's no reason to keep the reference anymore, so we // removed it here. mDeferredViews.remove(appWidgetId); } } } } Loading Loading @@ -221,10 +242,28 @@ public class LauncherAppWidgetHost extends AppWidgetHost { CustomWidgetManager.INSTANCE.get(context).onViewCreated(lahv); return lahv; } else if ((mFlags & FLAG_LISTENING) == 0) { // Since the launcher hasn't started listening to widget updates, we can't simply call // super.createView here because the later will make a binder call to retrieve // RemoteViews from system process. // TODO: have launcher always listens to widget updates in background so that this // check can be removed altogether. if (FeatureFlags.ENABLE_CACHED_WIDGET.get() && mCachedRemoteViews.get(appWidgetId) != null) { // We've found RemoteViews from cache for this widget, so we will instantiate a // widget host view and populate it with the cached RemoteViews. final LauncherAppWidgetHostView view = new LauncherAppWidgetHostView(context); view.setAppWidget(appWidgetId, appWidget); view.updateAppWidget(mCachedRemoteViews.get(appWidgetId)); mDeferredViews.put(appWidgetId, view); mViews.put(appWidgetId, view); return view; } else { // When cache misses, a placeholder for the widget will be returned instead. DeferredAppWidgetHostView view = new DeferredAppWidgetHostView(context); view.setAppWidget(appWidgetId, appWidget); mViews.put(appWidgetId, view); return view; } } else { try { return super.createView(context, appWidgetId, appWidget); Loading Loading @@ -281,6 +320,16 @@ public class LauncherAppWidgetHost extends AppWidgetHost { @Override public void clearViews() { super.clearViews(); if (FeatureFlags.ENABLE_CACHED_WIDGET.get()) { // First, we clear any previously cached content from existing widgets mCachedRemoteViews.clear(); // Then we proceed to cache the content from the widgets for (int i = 0; i < mViews.size(); i++) { final int appWidgetId = mViews.keyAt(i); final LauncherAppWidgetHostView view = mViews.get(appWidgetId); mCachedRemoteViews.put(appWidgetId, view.mLastRemoteViews); } } mViews.clear(); } Loading src/com/android/launcher3/widget/LauncherAppWidgetHostView.java +14 −7 Original line number Diff line number Diff line Loading @@ -43,6 +43,7 @@ import com.android.launcher3.CheckLongPressHelper; import com.android.launcher3.Launcher; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.dragndrop.DragLayer; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.LauncherAppWidgetInfo; Loading Loading @@ -85,7 +86,7 @@ public class LauncherAppWidgetHostView extends BaseLauncherAppWidgetHostView private Runnable mAutoAdvanceRunnable; private long mDeferUpdatesUntilMillis = 0; private RemoteViews mDeferredRemoteViews; RemoteViews mLastRemoteViews; private boolean mHasDeferredColorChange = false; private @Nullable SparseIntArray mDeferredColorChange = null; Loading Loading @@ -150,11 +151,18 @@ public class LauncherAppWidgetHostView extends BaseLauncherAppWidgetHostView TRACE_METHOD_NAME + getAppWidgetInfo().provider, getAppWidgetId()); mTrackingWidgetUpdate = false; } if (FeatureFlags.ENABLE_CACHED_WIDGET.get()) { mLastRemoteViews = remoteViews; if (isDeferringUpdates()) { mDeferredRemoteViews = remoteViews; return; } mDeferredRemoteViews = null; } else { if (isDeferringUpdates()) { mLastRemoteViews = remoteViews; return; } mLastRemoteViews = null; } super.updateAppWidget(remoteViews); Loading Loading @@ -218,8 +226,7 @@ public class LauncherAppWidgetHostView extends BaseLauncherAppWidgetHostView SparseIntArray deferredColors; boolean hasDeferredColors; mDeferUpdatesUntilMillis = 0; remoteViews = mDeferredRemoteViews; mDeferredRemoteViews = null; remoteViews = mLastRemoteViews; deferredColors = mDeferredColorChange; hasDeferredColors = mHasDeferredColorChange; mDeferredColorChange = null; Loading Loading
src/com/android/launcher3/config/FeatureFlags.java +4 −0 Original line number Diff line number Diff line Loading @@ -277,6 +277,10 @@ public final class FeatureFlags { "ENABLE_DISMISS_PREDICTION_UNDO", false, "Show an 'Undo' snackbar when users dismiss a predicted hotseat item"); public static final BooleanFlag ENABLE_CACHED_WIDGET = getDebugFlag( "ENABLE_CACHED_WIDGET", true, "Show previously cached widgets as opposed to deferred widget where available"); public static void initialize(Context context) { synchronized (sDebugFlags) { for (DebugFlag flag : sDebugFlags) { Loading
src/com/android/launcher3/widget/LauncherAppWidgetHost.java +55 −6 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.util.SparseArray; import android.widget.RemoteViews; import android.widget.Toast; import androidx.annotation.Nullable; Loading @@ -37,6 +38,7 @@ import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.LauncherAppState; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.model.WidgetsModel; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.testing.TestLogging; Loading Loading @@ -70,13 +72,14 @@ public class LauncherAppWidgetHost extends AppWidgetHost { private final ArrayList<ProviderChangedListener> mProviderChangeListeners = new ArrayList<>(); private final SparseArray<LauncherAppWidgetHostView> mViews = new SparseArray<>(); private final SparseArray<PendingAppWidgetHostView> mPendingViews = new SparseArray<>(); private final SparseArray<LauncherAppWidgetHostView> mDeferredViews = new SparseArray<>(); private final SparseArray<RemoteViews> mCachedRemoteViews = new SparseArray<>(); private final Context mContext; private int mFlags = FLAG_STATE_IS_NORMAL; private IntConsumer mAppWidgetRemovedCallback = null; public LauncherAppWidgetHost(Context context) { this(context, null); } Loading @@ -95,6 +98,11 @@ public class LauncherAppWidgetHost extends AppWidgetHost { if (mPendingViews.get(appWidgetId) != null) { view = mPendingViews.get(appWidgetId); mPendingViews.remove(appWidgetId); } else if (mDeferredViews.get(appWidgetId) != null) { // In case the widget view is deferred, we will simply return the deferred view as // opposed to instantiate a new instance of LauncherAppWidgetHostView since launcher // already added the former to the workspace. view = mDeferredViews.get(appWidgetId); } else { view = new LauncherAppWidgetHostView(context); } Loading @@ -120,12 +128,25 @@ public class LauncherAppWidgetHost extends AppWidgetHost { // widgets upon bind anyway. See issue 14255011 for more context. } // We go in reverse order and inflate any deferred widget // We go in reverse order and inflate any deferred or cached widget for (int i = mViews.size() - 1; i >= 0; i--) { LauncherAppWidgetHostView view = mViews.valueAt(i); if (view instanceof DeferredAppWidgetHostView) { view.reInflate(); } if (FeatureFlags.ENABLE_CACHED_WIDGET.get()) { final int appWidgetId = mViews.keyAt(i); if (view == mDeferredViews.get(appWidgetId)) { // If the widget view was deferred, we'll need to call super.createView here // to make the binder call to system process to fetch cumulative updates to this // widget, as well as setting up this view for future updates. super.createView(view.mLauncher, appWidgetId, view.getAppWidgetInfo()); // At this point #onCreateView should have been called, which in turn returned // the deferred view. There's no reason to keep the reference anymore, so we // removed it here. mDeferredViews.remove(appWidgetId); } } } } Loading Loading @@ -221,10 +242,28 @@ public class LauncherAppWidgetHost extends AppWidgetHost { CustomWidgetManager.INSTANCE.get(context).onViewCreated(lahv); return lahv; } else if ((mFlags & FLAG_LISTENING) == 0) { // Since the launcher hasn't started listening to widget updates, we can't simply call // super.createView here because the later will make a binder call to retrieve // RemoteViews from system process. // TODO: have launcher always listens to widget updates in background so that this // check can be removed altogether. if (FeatureFlags.ENABLE_CACHED_WIDGET.get() && mCachedRemoteViews.get(appWidgetId) != null) { // We've found RemoteViews from cache for this widget, so we will instantiate a // widget host view and populate it with the cached RemoteViews. final LauncherAppWidgetHostView view = new LauncherAppWidgetHostView(context); view.setAppWidget(appWidgetId, appWidget); view.updateAppWidget(mCachedRemoteViews.get(appWidgetId)); mDeferredViews.put(appWidgetId, view); mViews.put(appWidgetId, view); return view; } else { // When cache misses, a placeholder for the widget will be returned instead. DeferredAppWidgetHostView view = new DeferredAppWidgetHostView(context); view.setAppWidget(appWidgetId, appWidget); mViews.put(appWidgetId, view); return view; } } else { try { return super.createView(context, appWidgetId, appWidget); Loading Loading @@ -281,6 +320,16 @@ public class LauncherAppWidgetHost extends AppWidgetHost { @Override public void clearViews() { super.clearViews(); if (FeatureFlags.ENABLE_CACHED_WIDGET.get()) { // First, we clear any previously cached content from existing widgets mCachedRemoteViews.clear(); // Then we proceed to cache the content from the widgets for (int i = 0; i < mViews.size(); i++) { final int appWidgetId = mViews.keyAt(i); final LauncherAppWidgetHostView view = mViews.get(appWidgetId); mCachedRemoteViews.put(appWidgetId, view.mLastRemoteViews); } } mViews.clear(); } Loading
src/com/android/launcher3/widget/LauncherAppWidgetHostView.java +14 −7 Original line number Diff line number Diff line Loading @@ -43,6 +43,7 @@ import com.android.launcher3.CheckLongPressHelper; import com.android.launcher3.Launcher; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.dragndrop.DragLayer; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.LauncherAppWidgetInfo; Loading Loading @@ -85,7 +86,7 @@ public class LauncherAppWidgetHostView extends BaseLauncherAppWidgetHostView private Runnable mAutoAdvanceRunnable; private long mDeferUpdatesUntilMillis = 0; private RemoteViews mDeferredRemoteViews; RemoteViews mLastRemoteViews; private boolean mHasDeferredColorChange = false; private @Nullable SparseIntArray mDeferredColorChange = null; Loading Loading @@ -150,11 +151,18 @@ public class LauncherAppWidgetHostView extends BaseLauncherAppWidgetHostView TRACE_METHOD_NAME + getAppWidgetInfo().provider, getAppWidgetId()); mTrackingWidgetUpdate = false; } if (FeatureFlags.ENABLE_CACHED_WIDGET.get()) { mLastRemoteViews = remoteViews; if (isDeferringUpdates()) { mDeferredRemoteViews = remoteViews; return; } mDeferredRemoteViews = null; } else { if (isDeferringUpdates()) { mLastRemoteViews = remoteViews; return; } mLastRemoteViews = null; } super.updateAppWidget(remoteViews); Loading Loading @@ -218,8 +226,7 @@ public class LauncherAppWidgetHostView extends BaseLauncherAppWidgetHostView SparseIntArray deferredColors; boolean hasDeferredColors; mDeferUpdatesUntilMillis = 0; remoteViews = mDeferredRemoteViews; mDeferredRemoteViews = null; remoteViews = mLastRemoteViews; deferredColors = mDeferredColorChange; hasDeferredColors = mHasDeferredColorChange; mDeferredColorChange = null; Loading