Fixing MainThreadInitializedObject
> Making SafeCloseable implementation mandatory, to prevent leaks during test and preview > Removing getNoCreate method and defining executeIfCreated to avoid null pointer exceptions > Fixing sandbox value leaking into main, by Checking sandbox against App context > Converting sanbox to an interface instead a class Bug: 335280439 Test: Presubmit Flag: None Change-Id: I951dcde871898e745ff6490a1c4f8fd1512888f5
This commit is contained in:
@@ -326,8 +326,12 @@ public class QuickstepModelDelegate extends ModelDelegate {
|
||||
super.destroy();
|
||||
mActive = false;
|
||||
StatsLogCompatManager.LOGS_CONSUMER.remove(mAppEventProducer);
|
||||
if (mIsPrimaryInstance) {
|
||||
mStatsManager.clearPullAtomCallback(SysUiStatsLog.LAUNCHER_LAYOUT_SNAPSHOT);
|
||||
if (mIsPrimaryInstance && mStatsManager != null) {
|
||||
try {
|
||||
mStatsManager.clearPullAtomCallback(SysUiStatsLog.LAUNCHER_LAYOUT_SNAPSHOT);
|
||||
} catch (RuntimeException e) {
|
||||
Log.e(TAG, "Failed to unregister snapshot logging callback with StatsManager", e);
|
||||
}
|
||||
}
|
||||
destroyPredictors();
|
||||
}
|
||||
|
||||
@@ -32,7 +32,6 @@ import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.DeadObjectException;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Process;
|
||||
import android.os.UserHandle;
|
||||
import android.text.TextUtils;
|
||||
@@ -48,9 +47,10 @@ import com.android.launcher3.R;
|
||||
import com.android.launcher3.model.data.ItemInfo;
|
||||
import com.android.launcher3.popup.RemoteActionShortcut;
|
||||
import com.android.launcher3.popup.SystemShortcut;
|
||||
import com.android.launcher3.util.BgObjectWithLooper;
|
||||
import com.android.launcher3.util.Executors;
|
||||
import com.android.launcher3.util.MainThreadInitializedObject;
|
||||
import com.android.launcher3.util.Preconditions;
|
||||
import com.android.launcher3.util.SafeCloseable;
|
||||
import com.android.launcher3.util.SimpleBroadcastReceiver;
|
||||
import com.android.launcher3.views.ActivityContext;
|
||||
|
||||
@@ -61,7 +61,7 @@ import java.util.Map;
|
||||
/**
|
||||
* Data model for digital wellbeing status of apps.
|
||||
*/
|
||||
public final class WellbeingModel extends BgObjectWithLooper {
|
||||
public final class WellbeingModel implements SafeCloseable {
|
||||
private static final String TAG = "WellbeingModel";
|
||||
private static final int[] RETRY_TIMES_MS = {5000, 15000, 30000};
|
||||
private static final boolean DEBUG = false;
|
||||
@@ -81,8 +81,12 @@ public final class WellbeingModel extends BgObjectWithLooper {
|
||||
private final Context mContext;
|
||||
private final String mWellbeingProviderPkg;
|
||||
|
||||
private Handler mWorkerHandler;
|
||||
private ContentObserver mContentObserver;
|
||||
private final Handler mWorkerHandler;
|
||||
private final ContentObserver mContentObserver;
|
||||
private final SimpleBroadcastReceiver mWellbeingAppChangeReceiver =
|
||||
new SimpleBroadcastReceiver(t -> restartObserver());
|
||||
private final SimpleBroadcastReceiver mAppAddRemoveReceiver =
|
||||
new SimpleBroadcastReceiver(this::onAppPackageChanged);
|
||||
|
||||
private final Object mModelLock = new Object();
|
||||
// Maps the action Id to the corresponding RemoteAction
|
||||
@@ -94,16 +98,23 @@ public final class WellbeingModel extends BgObjectWithLooper {
|
||||
private WellbeingModel(final Context context) {
|
||||
mContext = context;
|
||||
mWellbeingProviderPkg = mContext.getString(R.string.wellbeing_provider_pkg);
|
||||
initializeInBackground("WellbeingHandler");
|
||||
mWorkerHandler = new Handler(TextUtils.isEmpty(mWellbeingProviderPkg)
|
||||
? Executors.UI_HELPER_EXECUTOR.getLooper()
|
||||
: Executors.getPackageExecutor(mWellbeingProviderPkg).getLooper());
|
||||
|
||||
mContentObserver = new ContentObserver(mWorkerHandler) {
|
||||
@Override
|
||||
public void onChange(boolean selfChange, Uri uri) {
|
||||
updateAllPackages();
|
||||
}
|
||||
};
|
||||
mWorkerHandler.post(this::initializeInBackground);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onInitialized(Looper looper) {
|
||||
mWorkerHandler = new Handler(looper);
|
||||
mContentObserver = newContentObserver(mWorkerHandler, this::onWellbeingUriChanged);
|
||||
private void initializeInBackground() {
|
||||
if (!TextUtils.isEmpty(mWellbeingProviderPkg)) {
|
||||
mContext.registerReceiver(
|
||||
new SimpleBroadcastReceiver(t -> restartObserver()),
|
||||
mWellbeingAppChangeReceiver,
|
||||
getPackageFilter(mWellbeingProviderPkg,
|
||||
Intent.ACTION_PACKAGE_ADDED, Intent.ACTION_PACKAGE_CHANGED,
|
||||
Intent.ACTION_PACKAGE_REMOVED, Intent.ACTION_PACKAGE_DATA_CLEARED,
|
||||
@@ -113,17 +124,21 @@ public final class WellbeingModel extends BgObjectWithLooper {
|
||||
IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
|
||||
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
|
||||
filter.addDataScheme("package");
|
||||
mContext.registerReceiver(new SimpleBroadcastReceiver(this::onAppPackageChanged),
|
||||
filter, null, mWorkerHandler);
|
||||
mContext.registerReceiver(mAppAddRemoveReceiver, filter, null, mWorkerHandler);
|
||||
|
||||
restartObserver();
|
||||
}
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private void onWellbeingUriChanged(Uri uri) {
|
||||
Preconditions.assertNonUiThread();
|
||||
updateAllPackages();
|
||||
@Override
|
||||
public void close() {
|
||||
if (!TextUtils.isEmpty(mWellbeingProviderPkg)) {
|
||||
mWorkerHandler.post(() -> {
|
||||
mWellbeingAppChangeReceiver.unregisterReceiverSafely(mContext);
|
||||
mAppAddRemoveReceiver.unregisterReceiverSafely(mContext);
|
||||
mContext.getContentResolver().unregisterContentObserver(mContentObserver);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void setInTest(boolean inTest) {
|
||||
|
||||
@@ -39,6 +39,7 @@ import com.android.launcher3.util.DisplayController.DisplayInfoChangeListener;
|
||||
import com.android.launcher3.util.DisplayController.Info;
|
||||
import com.android.launcher3.util.MainThreadInitializedObject;
|
||||
import com.android.launcher3.util.NavigationMode;
|
||||
import com.android.launcher3.util.SafeCloseable;
|
||||
import com.android.quickstep.util.RecentsOrientedState;
|
||||
import com.android.systemui.shared.system.QuickStepContract;
|
||||
import com.android.systemui.shared.system.TaskStackChangeListener;
|
||||
@@ -50,7 +51,7 @@ import java.util.ArrayList;
|
||||
/**
|
||||
* Helper class for transforming touch events
|
||||
*/
|
||||
public class RotationTouchHelper implements DisplayInfoChangeListener {
|
||||
public class RotationTouchHelper implements DisplayInfoChangeListener, SafeCloseable {
|
||||
|
||||
public static final MainThreadInitializedObject<RotationTouchHelper> INSTANCE =
|
||||
new MainThreadInitializedObject<>(RotationTouchHelper::new);
|
||||
@@ -197,6 +198,11 @@ public class RotationTouchHelper implements DisplayInfoChangeListener {
|
||||
mOnDestroyActions.add(action);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans up all the registered listeners and receivers.
|
||||
*/
|
||||
|
||||
@@ -24,21 +24,29 @@ import android.view.MotionEvent;
|
||||
|
||||
import com.android.launcher3.util.DisplayController;
|
||||
import com.android.launcher3.util.MainThreadInitializedObject;
|
||||
import com.android.launcher3.util.SafeCloseable;
|
||||
|
||||
public class SimpleOrientationTouchTransformer implements
|
||||
DisplayController.DisplayInfoChangeListener {
|
||||
DisplayController.DisplayInfoChangeListener, SafeCloseable {
|
||||
|
||||
public static final MainThreadInitializedObject<SimpleOrientationTouchTransformer> INSTANCE =
|
||||
new MainThreadInitializedObject<>(SimpleOrientationTouchTransformer::new);
|
||||
|
||||
private final Context mContext;
|
||||
private OrientationRectF mOrientationRectF;
|
||||
|
||||
public SimpleOrientationTouchTransformer(Context context) {
|
||||
mContext = context;
|
||||
DisplayController.INSTANCE.get(context).addChangeListener(this);
|
||||
onDisplayInfoChanged(context, DisplayController.INSTANCE.get(context).getInfo(),
|
||||
CHANGE_ALL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
DisplayController.INSTANCE.get(mContext).removeChangeListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisplayInfoChanged(Context context, DisplayController.Info info, int flags) {
|
||||
if ((flags & (CHANGE_ROTATION | CHANGE_ACTIVE_SCREEN)) == 0) {
|
||||
|
||||
@@ -65,6 +65,7 @@ import com.android.internal.util.ScreenshotRequest;
|
||||
import com.android.internal.view.AppearanceRegion;
|
||||
import com.android.launcher3.util.MainThreadInitializedObject;
|
||||
import com.android.launcher3.util.Preconditions;
|
||||
import com.android.launcher3.util.SafeCloseable;
|
||||
import com.android.quickstep.util.ActiveGestureLog;
|
||||
import com.android.quickstep.util.AssistUtils;
|
||||
import com.android.quickstep.util.unfold.ProxyUnfoldTransitionProvider;
|
||||
@@ -108,7 +109,7 @@ import java.util.List;
|
||||
/**
|
||||
* Holds the reference to SystemUI.
|
||||
*/
|
||||
public class SystemUiProxy implements ISystemUiProxy, NavHandle {
|
||||
public class SystemUiProxy implements ISystemUiProxy, NavHandle, SafeCloseable {
|
||||
private static final String TAG = SystemUiProxy.class.getSimpleName();
|
||||
|
||||
public static final MainThreadInitializedObject<SystemUiProxy> INSTANCE =
|
||||
@@ -198,6 +199,9 @@ public class SystemUiProxy implements ISystemUiProxy, NavHandle {
|
||||
? new ProxyUnfoldTransitionProvider() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() { }
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if (mSystemUiProxy != null) {
|
||||
|
||||
@@ -59,6 +59,7 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn
|
||||
public static final boolean SHELL_TRANSITIONS_ROTATION = ENABLE_SHELL_TRANSITIONS
|
||||
&& SystemProperties.getBoolean("persist.wm.debug.shell_transit_rotate", false);
|
||||
|
||||
private final Context mCtx;
|
||||
private RecentsAnimationController mController;
|
||||
private RecentsAnimationCallbacks mCallbacks;
|
||||
private RecentsAnimationTargets mTargets;
|
||||
@@ -66,7 +67,6 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn
|
||||
private GestureState mLastGestureState;
|
||||
private RemoteAnimationTarget[] mLastAppearedTaskTargets;
|
||||
private Runnable mLiveTileCleanUpHandler;
|
||||
private Context mCtx;
|
||||
|
||||
private boolean mRecentsAnimationStartPending = false;
|
||||
private boolean mShouldIgnoreMotionEvents = false;
|
||||
@@ -329,7 +329,7 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn
|
||||
options.setTransientLaunch();
|
||||
}
|
||||
options.setSourceInfo(ActivityOptions.SourceInfo.TYPE_RECENTS_ANIMATION, eventTime);
|
||||
mRecentsAnimationStartPending = SystemUiProxy.INSTANCE.getNoCreate()
|
||||
mRecentsAnimationStartPending = SystemUiProxy.INSTANCE.get(mCtx)
|
||||
.startRecentsActivity(intent, options, mCallbacks);
|
||||
if (enableHandleDelayedGestureCallbacks()) {
|
||||
ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
|
||||
|
||||
@@ -34,6 +34,7 @@ import androidx.annotation.Nullable;
|
||||
import androidx.annotation.UiThread;
|
||||
|
||||
import com.android.launcher3.util.MainThreadInitializedObject;
|
||||
import com.android.launcher3.util.SafeCloseable;
|
||||
import com.android.launcher3.util.SplitConfigurationOptions;
|
||||
import com.android.launcher3.util.SplitConfigurationOptions.SplitStageInfo;
|
||||
import com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
|
||||
@@ -57,7 +58,8 @@ import java.util.List;
|
||||
* This class tracked the top-most task and some 'approximate' task history to allow faster
|
||||
* system state estimation during touch interaction
|
||||
*/
|
||||
public class TopTaskTracker extends ISplitScreenListener.Stub implements TaskStackChangeListener {
|
||||
public class TopTaskTracker extends ISplitScreenListener.Stub
|
||||
implements TaskStackChangeListener, SafeCloseable {
|
||||
|
||||
public static MainThreadInitializedObject<TopTaskTracker> INSTANCE =
|
||||
new MainThreadInitializedObject<>(TopTaskTracker::new);
|
||||
@@ -67,12 +69,13 @@ public class TopTaskTracker extends ISplitScreenListener.Stub implements TaskSta
|
||||
// Ordered list with first item being the most recent task.
|
||||
private final LinkedList<RunningTaskInfo> mOrderedTaskList = new LinkedList<>();
|
||||
|
||||
|
||||
private final Context mContext;
|
||||
private final SplitStageInfo mMainStagePosition = new SplitStageInfo();
|
||||
private final SplitStageInfo mSideStagePosition = new SplitStageInfo();
|
||||
private int mPinnedTaskId = INVALID_TASK_ID;
|
||||
|
||||
private TopTaskTracker(Context context) {
|
||||
mContext = context;
|
||||
mMainStagePosition.stageType = SplitConfigurationOptions.STAGE_TYPE_MAIN;
|
||||
mSideStagePosition.stageType = SplitConfigurationOptions.STAGE_TYPE_SIDE;
|
||||
|
||||
@@ -80,6 +83,12 @@ public class TopTaskTracker extends ISplitScreenListener.Stub implements TaskSta
|
||||
SystemUiProxy.INSTANCE.get(context).registerSplitScreenListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
TaskStackChangeListeners.getInstance().unregisterTaskStackListener(this);
|
||||
SystemUiProxy.INSTANCE.get(mContext).unregisterSplitScreenListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTaskRemoved(int taskId) {
|
||||
mOrderedTaskList.removeIf(rto -> rto.taskId == taskId);
|
||||
|
||||
@@ -347,7 +347,6 @@ public class StatsLogCompatManager extends StatsLogManager {
|
||||
event.getId() + "";
|
||||
Log.d(TAG, name);
|
||||
}
|
||||
LauncherAppState appState = LauncherAppState.getInstanceNoCreate();
|
||||
|
||||
if (mSlice == null && mSliceItem != null) {
|
||||
mSlice = LauncherAtom.Slice.newBuilder().setUri(
|
||||
@@ -369,15 +368,10 @@ public class StatsLogCompatManager extends StatsLogManager {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mItemInfo.container < 0 || appState == null) {
|
||||
// Write log on the model thread so that logs do not go out of order
|
||||
// (for eg: drop comes after drag)
|
||||
Executors.MODEL_EXECUTOR.execute(
|
||||
() -> write(event, applyOverwrites(mItemInfo.buildProto())));
|
||||
} else {
|
||||
if (mItemInfo.container < 0 || !LauncherAppState.INSTANCE.executeIfCreated(app -> {
|
||||
// Item is inside a collection, fetch collection info in a BG thread
|
||||
// and then write to StatsLog.
|
||||
appState.getModel().enqueueModelUpdateTask(
|
||||
app.getModel().enqueueModelUpdateTask(
|
||||
new BaseModelUpdateTask() {
|
||||
@Override
|
||||
public void execute(@NonNull final LauncherAppState app,
|
||||
@@ -388,6 +382,11 @@ public class StatsLogCompatManager extends StatsLogManager {
|
||||
write(event, applyOverwrites(mItemInfo.buildProto(collectionInfo)));
|
||||
}
|
||||
});
|
||||
})) {
|
||||
// Write log on the model thread so that logs do not go out of order
|
||||
// (for eg: drop comes after drag)
|
||||
Executors.MODEL_EXECUTOR.execute(
|
||||
() -> write(event, applyOverwrites(mItemInfo.buildProto())));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -316,7 +316,7 @@ public class AppPairsController {
|
||||
itemInfos.stream().map(ItemInfo::getComponentKey).toList();
|
||||
|
||||
// Use TopTaskTracker to find the currently running app (or apps)
|
||||
TopTaskTracker topTaskTracker = getTopTaskTracker(context);
|
||||
TopTaskTracker topTaskTracker = getTopTaskTracker();
|
||||
|
||||
// getRunningSplitTasksIds() will return a pair of ids if we are currently running a
|
||||
// split pair, or an empty array with zero length if we are running a single app.
|
||||
@@ -489,7 +489,7 @@ public class AppPairsController {
|
||||
* Gets the TopTaskTracker, which is a cached record of the top running Task.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public TopTaskTracker getTopTaskTracker(Context context) {
|
||||
return TopTaskTracker.INSTANCE.get(context);
|
||||
public TopTaskTracker getTopTaskTracker() {
|
||||
return TopTaskTracker.INSTANCE.get(mContext);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ public class SplitToWorkspaceController {
|
||||
SplitSelectStateController controller) {
|
||||
mLauncher = launcher;
|
||||
mController = controller;
|
||||
mIconCache = LauncherAppState.getInstanceNoCreate().getIconCache();
|
||||
mIconCache = LauncherAppState.getInstance(launcher).getIconCache();
|
||||
mHalfDividerSize = mLauncher.getResources().getDimensionPixelSize(
|
||||
R.dimen.multi_window_task_divider_size) / 2;
|
||||
}
|
||||
|
||||
@@ -22,6 +22,8 @@ import static com.android.launcher3.BaseActivity.EVENT_DESTROYED;
|
||||
import static com.android.launcher3.BaseActivity.EVENT_RESUMED;
|
||||
import static com.android.launcher3.BaseActivity.EVENT_STOPPED;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.android.quickstep.RecentsModel;
|
||||
@@ -45,6 +47,12 @@ public class TaskRemovedDuringLaunchListener {
|
||||
private final Runnable mUnregisterCallback = this::unregister;
|
||||
private final Runnable mResumeCallback = this::checkTaskLaunchFailed;
|
||||
|
||||
private final Context mContext;
|
||||
|
||||
public TaskRemovedDuringLaunchListener(Context context) {
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a failure listener callback if it detects a scenario in which an app launch
|
||||
* failed before the transition finished.
|
||||
@@ -88,7 +96,7 @@ public class TaskRemovedDuringLaunchListener {
|
||||
if (mLaunchedTaskId != INVALID_TASK_ID) {
|
||||
final int launchedTaskId = mLaunchedTaskId;
|
||||
final Runnable taskLaunchFailedCallback = mTaskLaunchFailedCallback;
|
||||
RecentsModel.INSTANCE.getNoCreate().isTaskRemoved(mLaunchedTaskId, (taskRemoved) -> {
|
||||
RecentsModel.INSTANCE.get(mContext).isTaskRemoved(mLaunchedTaskId, (taskRemoved) -> {
|
||||
if (taskRemoved) {
|
||||
ActiveGestureLog.INSTANCE.addLog(
|
||||
new ActiveGestureLog.CompoundString("Launch failed, task (id=")
|
||||
|
||||
@@ -93,6 +93,7 @@ import com.android.launcher3.util.ActivityOptionsWrapper;
|
||||
import com.android.launcher3.util.CancellableTask;
|
||||
import com.android.launcher3.util.ComponentKey;
|
||||
import com.android.launcher3.util.RunnableList;
|
||||
import com.android.launcher3.util.SafeCloseable;
|
||||
import com.android.launcher3.util.SplitConfigurationOptions;
|
||||
import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
|
||||
import com.android.launcher3.util.TraceHelper;
|
||||
@@ -118,6 +119,8 @@ import com.android.systemui.shared.recents.model.ThumbnailData;
|
||||
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
||||
import com.android.systemui.shared.system.QuickStepContract;
|
||||
|
||||
import kotlin.Unit;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
@@ -126,8 +129,6 @@ import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import kotlin.Unit;
|
||||
|
||||
/**
|
||||
* A task in the Recents view.
|
||||
*/
|
||||
@@ -922,8 +923,8 @@ public class TaskView extends FrameLayout implements Reusable {
|
||||
TestLogging.recordEvent(
|
||||
TestProtocol.SEQUENCE_MAIN, "startActivityFromRecentsAsync", mTask);
|
||||
|
||||
final TaskRemovedDuringLaunchListener
|
||||
failureListener = new TaskRemovedDuringLaunchListener();
|
||||
TaskRemovedDuringLaunchListener failureListener = new TaskRemovedDuringLaunchListener(
|
||||
getContext().getApplicationContext());
|
||||
if (isQuickswitch) {
|
||||
// We only listen for failures to launch in quickswitch because the during this
|
||||
// gesture launcher is in the background state, vs other launches which are in
|
||||
@@ -950,12 +951,8 @@ public class TaskView extends FrameLayout implements Reusable {
|
||||
// Indicate success once the system has indicated that the transition has started
|
||||
ActivityOptions opts = ActivityOptions.makeCustomTaskAnimation(getContext(), 0, 0,
|
||||
MAIN_EXECUTOR.getHandler(),
|
||||
elapsedRealTime -> {
|
||||
callback.accept(true);
|
||||
},
|
||||
elapsedRealTime -> {
|
||||
failureListener.onTransitionFinished();
|
||||
});
|
||||
elapsedRealTime -> callback.accept(true),
|
||||
elapsedRealTime -> failureListener.onTransitionFinished());
|
||||
opts.setLaunchDisplayId(
|
||||
getDisplay() == null ? DEFAULT_DISPLAY : getDisplay().getDisplayId());
|
||||
if (isQuickswitch) {
|
||||
@@ -1857,7 +1854,7 @@ public class TaskView extends FrameLayout implements Reusable {
|
||||
/**
|
||||
* We update and subsequently draw these in {@link #setFullscreenProgress(float)}.
|
||||
*/
|
||||
public static class FullscreenDrawParams {
|
||||
public static class FullscreenDrawParams implements SafeCloseable {
|
||||
|
||||
private float mCornerRadius;
|
||||
private float mWindowCornerRadius;
|
||||
@@ -1892,6 +1889,9 @@ public class TaskView extends FrameLayout implements Reusable {
|
||||
Utilities.mapRange(fullscreenProgress, mCornerRadius, mWindowCornerRadius)
|
||||
/ parentScale / taskViewScale;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() { }
|
||||
}
|
||||
|
||||
public class TaskIdAttributeContainer {
|
||||
|
||||
Reference in New Issue
Block a user