Merge "Recycling taskViews instead of inflating & throwing them away everytime" into ub-launcher3-master
This commit is contained in:
commit
1a956e812c
|
@ -42,14 +42,8 @@
|
|||
android:importantForAccessibility="noHideDescendants"
|
||||
android:background="#800000FF"
|
||||
android:layout_gravity="bottom"
|
||||
android:gravity="center"
|
||||
android:textColor="@android:color/white"
|
||||
android:visibility="gone"
|
||||
>
|
||||
<TextView
|
||||
android:id="@+id/remaining_time"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:textColor="@android:color/white"
|
||||
/>
|
||||
</com.android.quickstep.views.DigitalWellBeingToast>
|
||||
</com.android.quickstep.views.TaskView>
|
|
@ -16,16 +16,13 @@
|
|||
|
||||
package com.android.quickstep;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Matrix;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.AnyThread;
|
||||
|
||||
import com.android.launcher3.BaseActivity;
|
||||
import com.android.launcher3.BaseDraggingActivity;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.util.Preconditions;
|
||||
import com.android.launcher3.util.MainThreadInitializedObject;
|
||||
import com.android.launcher3.util.ResourceBasedOverride;
|
||||
import com.android.quickstep.views.TaskView;
|
||||
import com.android.systemui.shared.recents.model.Task;
|
||||
|
@ -34,11 +31,12 @@ import com.android.systemui.shared.recents.model.ThumbnailData;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.AnyThread;
|
||||
|
||||
/**
|
||||
* Factory class to create and add an overlays on the TaskView
|
||||
*/
|
||||
public class TaskOverlayFactory implements ResourceBasedOverride {
|
||||
private static TaskOverlayFactory sInstance;
|
||||
|
||||
/** Note that these will be shown in order from top to bottom, if available for the task. */
|
||||
private static final TaskSystemShortcut[] MENU_OPTIONS = new TaskSystemShortcut[]{
|
||||
|
@ -49,14 +47,9 @@ public class TaskOverlayFactory implements ResourceBasedOverride {
|
|||
new TaskSystemShortcut.Freeform()
|
||||
};
|
||||
|
||||
public static TaskOverlayFactory get(Context context) {
|
||||
Preconditions.assertUIThread();
|
||||
if (sInstance == null) {
|
||||
sInstance = Overrides.getObject(TaskOverlayFactory.class,
|
||||
context.getApplicationContext(), R.string.task_overlay_factory_class);
|
||||
}
|
||||
return sInstance;
|
||||
}
|
||||
public static final MainThreadInitializedObject<TaskOverlayFactory> INSTANCE =
|
||||
new MainThreadInitializedObject<>(c -> Overrides.getObject(TaskOverlayFactory.class,
|
||||
c, R.string.task_overlay_factory_class));
|
||||
|
||||
@AnyThread
|
||||
public boolean needAssist() {
|
||||
|
|
|
@ -203,7 +203,7 @@ public class TouchInteractionService extends Service {
|
|||
mEventQueue = new MotionEventQueue(mMainThreadChoreographer, TouchConsumer.NO_OP);
|
||||
mOverviewInteractionState = OverviewInteractionState.INSTANCE.get(this);
|
||||
mOverviewCallbacks = OverviewCallbacks.get(this);
|
||||
mTaskOverlayFactory = TaskOverlayFactory.get(this);
|
||||
mTaskOverlayFactory = TaskOverlayFactory.INSTANCE.get(this);
|
||||
mTouchInteractionLog = new TouchInteractionLog();
|
||||
mInputConsumer = InputConsumerController.getRecentsAnimationInputConsumer();
|
||||
mInputConsumer.registerInputConsumer();
|
||||
|
|
|
@ -23,7 +23,6 @@ import android.content.Intent;
|
|||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.launcher3.Launcher;
|
||||
|
@ -32,7 +31,8 @@ import com.android.launcher3.Utilities;
|
|||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||
import com.android.systemui.shared.recents.model.Task;
|
||||
|
||||
public final class DigitalWellBeingToast extends LinearLayout {
|
||||
public final class DigitalWellBeingToast extends TextView {
|
||||
|
||||
public interface InitializeCallback {
|
||||
void call(float saturation, String contentDescription);
|
||||
}
|
||||
|
@ -56,12 +56,11 @@ public final class DigitalWellBeingToast extends LinearLayout {
|
|||
final long appRemainingTimeMs = -1;
|
||||
final boolean isGroupLimit = true;
|
||||
post(() -> {
|
||||
final TextView remainingTimeText = findViewById(R.id.remaining_time);
|
||||
if (appUsageLimitTimeMs < 0) {
|
||||
setVisibility(GONE);
|
||||
} else {
|
||||
setVisibility(VISIBLE);
|
||||
remainingTimeText.setText(getText(appRemainingTimeMs, isGroupLimit));
|
||||
setText(getText(appRemainingTimeMs, isGroupLimit));
|
||||
}
|
||||
|
||||
callback.call(
|
||||
|
|
|
@ -81,6 +81,7 @@ import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
|
|||
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
|
||||
import com.android.launcher3.util.PendingAnimation;
|
||||
import com.android.launcher3.util.Themes;
|
||||
import com.android.launcher3.util.ViewPool;
|
||||
import com.android.quickstep.OverviewCallbacks;
|
||||
import com.android.quickstep.QuickScrubController;
|
||||
import com.android.quickstep.RecentsAnimationWrapper;
|
||||
|
@ -156,6 +157,8 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
|||
|
||||
private final InvariantDeviceProfile mIdp;
|
||||
|
||||
private final ViewPool<TaskView> mTaskViewPool;
|
||||
|
||||
/**
|
||||
* TODO: Call reloadIdNeeded in onTaskStackChanged.
|
||||
*/
|
||||
|
@ -304,6 +307,9 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
|||
.inflate(R.layout.overview_clear_all_button, this, false);
|
||||
mClearAllButton.setOnClickListener(this::dismissAllTasks);
|
||||
|
||||
mTaskViewPool = new ViewPool<>(context, this, R.layout.task, 20 /* max size */,
|
||||
10 /* initial size */);
|
||||
|
||||
mIsRtl = !Utilities.isRtl(getResources());
|
||||
setLayoutDirection(mIsRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR);
|
||||
mTaskTopMargin = getResources()
|
||||
|
@ -384,6 +390,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
|||
mHasVisibleTaskData.delete(task.key.id);
|
||||
taskView.onTaskListVisibilityChanged(false /* visible */);
|
||||
}
|
||||
mTaskViewPool.recycle(taskView);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -487,10 +494,6 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
|||
|
||||
int oldChildCount = getChildCount();
|
||||
|
||||
// Ensure there are as many views as there are tasks in the stack (adding and trimming as
|
||||
// necessary)
|
||||
final LayoutInflater inflater = LayoutInflater.from(getContext());
|
||||
|
||||
// Unload existing visible task data
|
||||
unloadVisibleTaskData();
|
||||
|
||||
|
@ -503,7 +506,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
|||
removeView(mClearAllButton);
|
||||
}
|
||||
for (int i = getChildCount(); i < requiredTaskCount; i++) {
|
||||
addView(inflater.inflate(R.layout.task, this, false));
|
||||
addView(mTaskViewPool.getView());
|
||||
}
|
||||
while (getChildCount() > requiredTaskCount) {
|
||||
removeView(getChildAt(getChildCount() - 1));
|
||||
|
@ -754,8 +757,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
|||
public void showTask(int runningTaskId) {
|
||||
if (getChildCount() == 0) {
|
||||
// Add an empty view for now until the task plan is loaded and applied
|
||||
final TaskView taskView = (TaskView) LayoutInflater.from(getContext())
|
||||
.inflate(R.layout.task, this, false);
|
||||
final TaskView taskView = mTaskViewPool.getView();
|
||||
addView(taskView);
|
||||
addView(mClearAllButton);
|
||||
|
||||
|
|
|
@ -107,7 +107,7 @@ public class TaskThumbnailView extends View {
|
|||
public TaskThumbnailView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
mCornerRadius = getResources().getDimension(R.dimen.task_corner_radius);
|
||||
mOverlay = TaskOverlayFactory.get(context).createOverlay(this);
|
||||
mOverlay = TaskOverlayFactory.INSTANCE.get(context).createOverlay(this);
|
||||
mPaint.setFilterBitmap(true);
|
||||
mBackgroundPaint.setColor(Color.WHITE);
|
||||
mClearPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
|
||||
|
|
|
@ -52,6 +52,7 @@ import com.android.launcher3.anim.Interpolators;
|
|||
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
|
||||
import com.android.launcher3.util.PendingAnimation;
|
||||
import com.android.launcher3.util.ViewPool.Reusable;
|
||||
import com.android.quickstep.RecentsModel;
|
||||
import com.android.quickstep.TaskIconCache;
|
||||
import com.android.quickstep.TaskOverlayFactory;
|
||||
|
@ -70,7 +71,7 @@ import java.util.function.Consumer;
|
|||
/**
|
||||
* A task in the Recents view.
|
||||
*/
|
||||
public class TaskView extends FrameLayout implements PageCallbacks {
|
||||
public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
|
||||
|
||||
private static final String TAG = TaskView.class.getSimpleName();
|
||||
|
||||
|
@ -399,19 +400,29 @@ public class TaskView extends FrameLayout implements PageCallbacks {
|
|||
setIconAndDimTransitionProgress(iconScale, invert);
|
||||
}
|
||||
|
||||
public void resetVisualProperties() {
|
||||
private void resetViewTransforms() {
|
||||
setZoomScale(1);
|
||||
setTranslationX(0f);
|
||||
setTranslationY(0f);
|
||||
setTranslationZ(0);
|
||||
setAlpha(1f);
|
||||
setIconScaleAndDim(1);
|
||||
}
|
||||
|
||||
public void resetVisualProperties() {
|
||||
resetViewTransforms();
|
||||
if (!getRecentsView().getQuickScrubController().isQuickSwitch()) {
|
||||
// Reset full screen progress unless we are doing back to back quick switch.
|
||||
setFullscreenProgress(0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRecycle() {
|
||||
resetViewTransforms();
|
||||
setFullscreenProgress(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageScroll(ScrollState scrollState) {
|
||||
float curveInterpolation =
|
||||
|
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.launcher3.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.android.launcher3.util.ViewPool.Reusable;
|
||||
|
||||
import androidx.annotation.AnyThread;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.UiThread;
|
||||
|
||||
/**
|
||||
* Utility class to maintain a pool of reusable views.
|
||||
* During initialization, views are inflated on the background thread.
|
||||
*/
|
||||
public class ViewPool<T extends View & Reusable> {
|
||||
|
||||
private final Object[] mPool;
|
||||
|
||||
private final LayoutInflater mInflater;
|
||||
private final ViewGroup mParent;
|
||||
private final int mLayoutId;
|
||||
|
||||
private int mCurrentSize = 0;
|
||||
|
||||
public ViewPool(Context context, @Nullable ViewGroup parent,
|
||||
int layoutId, int maxSize, int initialSize) {
|
||||
mLayoutId = layoutId;
|
||||
mParent = parent;
|
||||
mInflater = LayoutInflater.from(context);
|
||||
mPool = new Object[maxSize];
|
||||
|
||||
if (initialSize > 0) {
|
||||
initPool(initialSize);
|
||||
}
|
||||
}
|
||||
|
||||
@UiThread
|
||||
private void initPool(int initialSize) {
|
||||
Preconditions.assertUIThread();
|
||||
Handler handler = new Handler();
|
||||
|
||||
// Inflate views on a non looper thread. This allows us to catch errors like calling
|
||||
// "new Handler()" in constructor easily.
|
||||
new Thread(() -> {
|
||||
for (int i = 0; i < initialSize; i++) {
|
||||
T view = inflateNewView();
|
||||
handler.post(() -> addToPool(view));
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
@UiThread
|
||||
public void recycle(T view) {
|
||||
Preconditions.assertUIThread();
|
||||
view.onRecycle();
|
||||
addToPool(view);
|
||||
}
|
||||
|
||||
@UiThread
|
||||
private void addToPool(T view) {
|
||||
Preconditions.assertUIThread();
|
||||
if (mCurrentSize >= mPool.length) {
|
||||
// pool is full
|
||||
return;
|
||||
}
|
||||
|
||||
mPool[mCurrentSize] = view;
|
||||
mCurrentSize++;
|
||||
}
|
||||
|
||||
@UiThread
|
||||
public T getView() {
|
||||
Preconditions.assertUIThread();
|
||||
if (mCurrentSize > 0) {
|
||||
mCurrentSize--;
|
||||
return (T) mPool[mCurrentSize];
|
||||
}
|
||||
return inflateNewView();
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
private T inflateNewView() {
|
||||
return (T) mInflater.inflate(mLayoutId, mParent, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface to indicate that a view is reusable
|
||||
*/
|
||||
public interface Reusable {
|
||||
|
||||
/**
|
||||
* Called when a view is recycled / added back to the pool
|
||||
*/
|
||||
void onRecycle();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue