Fixing leaks in LauncherPreview
> Do not add listeners when binding FolderIcon for preview > Cleaning up preview object when the caller is no longer holding on to the communication channel for preview. Bug: 393086035 Flag: EXEMPT bugfix Test: Verified manually (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:986d7cb9c09a22915c922cf8e72c03ce36883742) Merged-In: I4b758e6ce103c5201ef05ab824dd4e02f98c40b6 Change-Id: I4b758e6ce103c5201ef05ab824dd4e02f98c40b6
This commit is contained in:
committed by
Android Build Coastguard Worker
parent
913244fac3
commit
a315410ea3
@@ -177,12 +177,16 @@ public class FolderIcon extends FrameLayout implements FolderListener, FloatingI
|
||||
FolderIcon icon = inflateIcon(resId, activityContext, group, folderInfo);
|
||||
folder.setFolderIcon(icon);
|
||||
folder.bind(folderInfo);
|
||||
|
||||
icon.setFolder(folder);
|
||||
folderInfo.addListener(icon);
|
||||
return icon;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a FolderIcon to be added to the Launcher
|
||||
* Builds a FolderIcon to be added to the activity.
|
||||
* This method doesn't add any listeners to the FolderInfo, and hence any changes to the info
|
||||
* will not be reflected in the folder.
|
||||
*/
|
||||
public static FolderIcon inflateIcon(int resId, ActivityContext activity,
|
||||
@Nullable ViewGroup group, FolderInfo folderInfo) {
|
||||
@@ -228,8 +232,6 @@ public class FolderIcon extends FrameLayout implements FolderListener, FloatingI
|
||||
icon.mPreviewVerifier.setFolderInfo(folderInfo);
|
||||
icon.updatePreviewItems(false);
|
||||
|
||||
folderInfo.addListener(icon);
|
||||
|
||||
return icon;
|
||||
}
|
||||
|
||||
|
||||
@@ -51,11 +51,12 @@ import com.android.launcher3.util.Preconditions;
|
||||
import com.android.launcher3.util.RunnableList;
|
||||
import com.android.systemui.shared.Flags;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
/**
|
||||
@@ -121,7 +122,7 @@ public class GridCustomizationsProvider extends ContentProvider {
|
||||
|
||||
// Set of all active previews used to track duplicate memory allocations
|
||||
private final Set<PreviewLifecycleObserver> mActivePreviews =
|
||||
Collections.newSetFromMap(new WeakHashMap<>());
|
||||
Collections.newSetFromMap(new ConcurrentHashMap<>());
|
||||
|
||||
@Override
|
||||
public boolean onCreate() {
|
||||
@@ -317,8 +318,15 @@ public class GridCustomizationsProvider extends ContentProvider {
|
||||
Bundle result = new Bundle();
|
||||
result.putParcelable(KEY_SURFACE_PACKAGE, renderer.getSurfacePackage());
|
||||
|
||||
Messenger messenger =
|
||||
new Messenger(new Handler(UI_HELPER_EXECUTOR.getLooper(), observer));
|
||||
mActivePreviews.add(observer);
|
||||
lifeCycleTracker.add(() -> mActivePreviews.remove(observer));
|
||||
|
||||
// Wrap the callback in a weak reference. This ensures that the callback is not kept
|
||||
// alive due to the Messenger's IBinder
|
||||
Messenger messenger = new Messenger(new Handler(
|
||||
UI_HELPER_EXECUTOR.getLooper(),
|
||||
new WeakCallbackWrapper(observer)));
|
||||
|
||||
Message msg = Message.obtain();
|
||||
msg.replyTo = messenger;
|
||||
result.putParcelable(KEY_CALLBACK, msg);
|
||||
@@ -400,4 +408,34 @@ public class GridCustomizationsProvider extends ContentProvider {
|
||||
&& plo.renderer.getDisplayId() == renderer.getDisplayId();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A WeakReference wrapper around Handler.Callback to avoid passing hard-reference over IPC
|
||||
* when using a Messenger
|
||||
*/
|
||||
private static class WeakCallbackWrapper implements Handler.Callback {
|
||||
|
||||
private final WeakReference<Handler.Callback> mActual;
|
||||
private final Message mCleanupMessage;
|
||||
|
||||
WeakCallbackWrapper(Handler.Callback actual) {
|
||||
mActual = new WeakReference<>(actual);
|
||||
mCleanupMessage = new Message();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleMessage(Message message) {
|
||||
Handler.Callback actual = mActual.get();
|
||||
return actual != null && actual.handleMessage(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
super.finalize();
|
||||
Handler.Callback actual = mActual.get();
|
||||
if (actual != null) {
|
||||
actual.handleMessage(mCleanupMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,7 +105,6 @@ public class PreviewSurfaceRenderer {
|
||||
private final SurfaceControlViewHost mSurfaceControlViewHost;
|
||||
|
||||
private boolean mDestroyed = false;
|
||||
private LauncherPreviewRenderer mRenderer;
|
||||
private boolean mHideQsb;
|
||||
@Nullable private FrameLayout mViewRoot = null;
|
||||
|
||||
@@ -224,9 +223,8 @@ public class PreviewSurfaceRenderer {
|
||||
* @param hide True to hide and false to show.
|
||||
*/
|
||||
public void hideBottomRow(boolean hide) {
|
||||
if (mRenderer != null) {
|
||||
mRenderer.hideBottomRow(hide);
|
||||
}
|
||||
mHideQsb = hide;
|
||||
loadAsync();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -368,15 +366,16 @@ public class PreviewSurfaceRenderer {
|
||||
if (mDestroyed) {
|
||||
return;
|
||||
}
|
||||
LauncherPreviewRenderer renderer;
|
||||
if (Flags.newCustomizationPickerUi()) {
|
||||
mRenderer = new LauncherPreviewRenderer(inflationContext, idp, mPreviewColorOverride,
|
||||
renderer = new LauncherPreviewRenderer(inflationContext, idp, mPreviewColorOverride,
|
||||
mWallpaperColors, launcherWidgetSpanInfo);
|
||||
} else {
|
||||
mRenderer = new LauncherPreviewRenderer(inflationContext, idp,
|
||||
renderer = new LauncherPreviewRenderer(inflationContext, idp,
|
||||
mWallpaperColors, launcherWidgetSpanInfo);
|
||||
}
|
||||
mRenderer.hideBottomRow(mHideQsb);
|
||||
View view = mRenderer.getRenderedView(dataModel, widgetProviderInfoMap);
|
||||
renderer.hideBottomRow(mHideQsb);
|
||||
View view = renderer.getRenderedView(dataModel, widgetProviderInfoMap);
|
||||
// This aspect scales the view to fit in the surface and centers it
|
||||
final float scale = Math.min(mWidth / (float) view.getMeasuredWidth(),
|
||||
mHeight / (float) view.getMeasuredHeight());
|
||||
|
||||
Reference in New Issue
Block a user