Merge "Retains cached widget in launcher process" into tm-qpr-dev am: a35d04afef am: bb38c78fa5

Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/apps/Launcher3/+/22146535

Change-Id: I825f19436115fbfa3279ba2182305cd9825b27dd
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Pinyao Ting
2023-03-21 21:25:06 +00:00
committed by Automerger Merge Worker
2 changed files with 54 additions and 27 deletions
@@ -31,7 +31,11 @@ import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.content.pm.LauncherApps; import android.content.pm.LauncherApps;
import android.os.UserHandle; import android.os.UserHandle;
import android.util.Log; import android.util.Log;
import android.util.SparseArray;
import android.widget.RemoteViews;
import androidx.annotation.GuardedBy;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.config.FeatureFlags;
@@ -70,6 +74,12 @@ public class LauncherAppState implements SafeCloseable {
private final InvariantDeviceProfile mInvariantDeviceProfile; private final InvariantDeviceProfile mInvariantDeviceProfile;
private final RunnableList mOnTerminateCallback = new RunnableList(); private final RunnableList mOnTerminateCallback = new RunnableList();
// WORKAROUND: b/269335387 remove this after widget background listener is enabled
/* Array of RemoteViews cached by Launcher process */
@GuardedBy("itself")
@NonNull
public final SparseArray<RemoteViews> mCachedRemoteViews = new SparseArray<>();
public static LauncherAppState getInstance(final Context context) { public static LauncherAppState getInstance(final Context context) {
return INSTANCE.get(context); return INSTANCE.get(context);
} }
@@ -36,6 +36,7 @@ import androidx.annotation.Nullable;
import com.android.launcher3.BaseActivity; import com.android.launcher3.BaseActivity;
import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R; import com.android.launcher3.R;
import com.android.launcher3.Utilities; import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.config.FeatureFlags;
@@ -74,8 +75,6 @@ public class LauncherWidgetHolder {
private final SparseArray<PendingAppWidgetHostView> mPendingViews = new SparseArray<>(); private final SparseArray<PendingAppWidgetHostView> mPendingViews = new SparseArray<>();
@NonNull @NonNull
private final SparseArray<LauncherAppWidgetHostView> mDeferredViews = new SparseArray<>(); private final SparseArray<LauncherAppWidgetHostView> mDeferredViews = new SparseArray<>();
@NonNull
private final SparseArray<RemoteViews> mCachedRemoteViews = new SparseArray<>();
protected int mFlags = FLAG_STATE_IS_NORMAL; protected int mFlags = FLAG_STATE_IS_NORMAL;
@@ -174,6 +173,12 @@ public class LauncherWidgetHolder {
public void deleteAppWidgetId(int appWidgetId) { public void deleteAppWidgetId(int appWidgetId) {
mWidgetHost.deleteAppWidgetId(appWidgetId); mWidgetHost.deleteAppWidgetId(appWidgetId);
mViews.remove(appWidgetId); mViews.remove(appWidgetId);
if (FeatureFlags.ENABLE_CACHED_WIDGET.get()) {
final LauncherAppState state = LauncherAppState.getInstance(mContext);
synchronized (state.mCachedRemoteViews) {
state.mCachedRemoteViews.delete(appWidgetId);
}
}
} }
/** /**
@@ -308,7 +313,17 @@ public class LauncherWidgetHolder {
if (WidgetsModel.GO_DISABLE_WIDGETS) { if (WidgetsModel.GO_DISABLE_WIDGETS) {
return; return;
} }
if (FeatureFlags.ENABLE_CACHED_WIDGET.get()) {
// Cache the content from the widgets when Launcher stops listening to widget updates
final LauncherAppState state = LauncherAppState.getInstance(mContext);
synchronized (state.mCachedRemoteViews) {
for (int i = 0; i < mViews.size(); i++) {
final int appWidgetId = mViews.keyAt(i);
final LauncherAppWidgetHostView view = mViews.get(appWidgetId);
state.mCachedRemoteViews.put(appWidgetId, view.mLastRemoteViews);
}
}
}
mWidgetHost.stopListening(); mWidgetHost.stopListening();
setListeningFlag(false); setListeningFlag(false);
} }
@@ -350,23 +365,24 @@ public class LauncherWidgetHolder {
// RemoteViews from system process. // RemoteViews from system process.
// TODO: have launcher always listens to widget updates in background so that this // TODO: have launcher always listens to widget updates in background so that this
// check can be removed altogether. // check can be removed altogether.
if (FeatureFlags.ENABLE_CACHED_WIDGET.get() if (FeatureFlags.ENABLE_CACHED_WIDGET.get()) {
&& mCachedRemoteViews.get(appWidgetId) != null) { final RemoteViews cachedRemoteViews = getCachedRemoteViews(appWidgetId);
// We've found RemoteViews from cache for this widget, so we will instantiate a if (cachedRemoteViews != null) {
// widget host view and populate it with the cached RemoteViews. // We've found RemoteViews from cache for this widget, so we will instantiate a
final LauncherAppWidgetHostView view = new LauncherAppWidgetHostView(context); // widget host view and populate it with the cached RemoteViews.
view.setAppWidget(appWidgetId, appWidget); final LauncherAppWidgetHostView view = new LauncherAppWidgetHostView(context);
view.updateAppWidget(mCachedRemoteViews.get(appWidgetId)); view.setAppWidget(appWidgetId, appWidget);
mDeferredViews.put(appWidgetId, view); view.updateAppWidget(cachedRemoteViews);
mViews.put(appWidgetId, view); mDeferredViews.put(appWidgetId, view);
return view; mViews.put(appWidgetId, view);
} else { return view;
// 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;
} }
// If cache misses or not enabled, a placeholder for the widget will be returned.
DeferredAppWidgetHostView view = new DeferredAppWidgetHostView(context);
view.setAppWidget(appWidgetId, appWidget);
mViews.put(appWidgetId, view);
return view;
} else { } else {
try { try {
return mWidgetHost.createView(context, appWidgetId, appWidget); return mWidgetHost.createView(context, appWidgetId, appWidget);
@@ -432,15 +448,8 @@ public class LauncherWidgetHolder {
LauncherAppWidgetHost tempHost = (LauncherAppWidgetHost) mWidgetHost; LauncherAppWidgetHost tempHost = (LauncherAppWidgetHost) mWidgetHost;
tempHost.clearViews(); tempHost.clearViews();
if (FeatureFlags.ENABLE_CACHED_WIDGET.get()) { if (FeatureFlags.ENABLE_CACHED_WIDGET.get()) {
// First, we clear any previously cached content from existing widgets // Clear previously cached content from existing widgets
mCachedRemoteViews.clear();
mDeferredViews.clear(); mDeferredViews.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(); mViews.clear();
} }
@@ -481,6 +490,14 @@ public class LauncherWidgetHolder {
return (flags & FLAGS_SHOULD_LISTEN) == FLAGS_SHOULD_LISTEN; return (flags & FLAGS_SHOULD_LISTEN) == FLAGS_SHOULD_LISTEN;
} }
@Nullable
private RemoteViews getCachedRemoteViews(int appWidgetId) {
final LauncherAppState state = LauncherAppState.getInstance(mContext);
synchronized (state.mCachedRemoteViews) {
return state.mCachedRemoteViews.get(appWidgetId);
}
}
/** /**
* Returns the new LauncherWidgetHolder instance * Returns the new LauncherWidgetHolder instance
*/ */