Adding a utility class to cache views at an activity level
Bug: 122345781 Change-Id: I9a939e0b19c06c1089c1ceb515f8b97fb5dbb49e
This commit is contained in:
parent
07b985b5e5
commit
5686333117
|
@ -118,7 +118,8 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe
|
|||
final RectF iconLocation = new RectF();
|
||||
boolean canUseWorkspaceView = workspaceView != null && workspaceView.isAttachedToWindow();
|
||||
FloatingIconView floatingIconView = canUseWorkspaceView
|
||||
? recentsView.getFloatingIconView(activity, workspaceView, iconLocation)
|
||||
? FloatingIconView.getFloatingIconView(activity, workspaceView,
|
||||
true /* hideOriginal */, iconLocation, false /* isOpening */)
|
||||
: null;
|
||||
|
||||
return new HomeAnimationFactory() {
|
||||
|
|
|
@ -66,7 +66,6 @@ import android.view.KeyEvent;
|
|||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.view.ViewDebug;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
|
@ -77,7 +76,6 @@ import com.android.launcher3.BaseActivity;
|
|||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.Insettable;
|
||||
import com.android.launcher3.InvariantDeviceProfile;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherAnimUtils.ViewProgressProperty;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.PagedView;
|
||||
|
@ -95,7 +93,6 @@ import com.android.launcher3.util.OverScroller;
|
|||
import com.android.launcher3.util.PendingAnimation;
|
||||
import com.android.launcher3.util.Themes;
|
||||
import com.android.launcher3.util.ViewPool;
|
||||
import com.android.launcher3.views.FloatingIconView;
|
||||
import com.android.quickstep.RecentsAnimationWrapper;
|
||||
import com.android.quickstep.RecentsModel;
|
||||
import com.android.quickstep.RecentsModel.TaskThumbnailChangeListener;
|
||||
|
@ -308,8 +305,6 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
|||
private Layout mEmptyTextLayout;
|
||||
private LiveTileOverlay mLiveTileOverlay;
|
||||
|
||||
private FloatingIconView mFloatingIconView;
|
||||
|
||||
private BaseActivity.MultiWindowModeChangedListener mMultiWindowModeChangedListener =
|
||||
(inMultiWindowMode) -> {
|
||||
if (!inMultiWindowMode && mOverviewStateEnabled) {
|
||||
|
@ -1687,12 +1682,6 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
|||
}
|
||||
}
|
||||
|
||||
public FloatingIconView getFloatingIconView(Launcher launcher, View view, RectF iconLocation) {
|
||||
mFloatingIconView = FloatingIconView.getFloatingIconView(launcher, view,
|
||||
true /* hideOriginal */, iconLocation, false /* isOpening */, mFloatingIconView);
|
||||
return mFloatingIconView;
|
||||
}
|
||||
|
||||
public ClipAnimationHelper getTempClipAnimationHelper() {
|
||||
return mTempClipAnimationHelper;
|
||||
}
|
||||
|
|
|
@ -142,7 +142,6 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans
|
|||
private final float mClosingWindowTransY;
|
||||
|
||||
private DeviceProfile mDeviceProfile;
|
||||
private FloatingIconView mFloatingView;
|
||||
|
||||
private RemoteAnimationProvider mRemoteAnimationProvider;
|
||||
|
||||
|
@ -411,15 +410,15 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans
|
|||
private ValueAnimator getOpeningWindowAnimators(View v, RemoteAnimationTargetCompat[] targets,
|
||||
Rect windowTargetBounds, boolean toggleVisibility) {
|
||||
RectF bounds = new RectF();
|
||||
mFloatingView = FloatingIconView.getFloatingIconView(mLauncher, v, toggleVisibility,
|
||||
bounds, true /* isOpening */, mFloatingView);
|
||||
FloatingIconView floatingView = FloatingIconView.getFloatingIconView(mLauncher, v,
|
||||
toggleVisibility, bounds, true /* isOpening */);
|
||||
Rect crop = new Rect();
|
||||
Matrix matrix = new Matrix();
|
||||
|
||||
RemoteAnimationTargetSet openingTargets = new RemoteAnimationTargetSet(targets,
|
||||
MODE_OPENING);
|
||||
SyncRtSurfaceTransactionApplierCompat surfaceApplier =
|
||||
new SyncRtSurfaceTransactionApplierCompat(mFloatingView);
|
||||
new SyncRtSurfaceTransactionApplierCompat(floatingView);
|
||||
openingTargets.addDependentTransactionApplier(surfaceApplier);
|
||||
|
||||
// Scale the app icon to take up the entire screen. This simplifies the math when
|
||||
|
@ -463,7 +462,7 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans
|
|||
ValueAnimator appAnimator = ValueAnimator.ofFloat(0, 1);
|
||||
appAnimator.setDuration(APP_LAUNCH_DURATION);
|
||||
appAnimator.setInterpolator(LINEAR);
|
||||
appAnimator.addListener(mFloatingView);
|
||||
appAnimator.addListener(floatingView);
|
||||
appAnimator.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
|
@ -557,7 +556,7 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans
|
|||
} else {
|
||||
currentBounds.bottom -= croppedHeight;
|
||||
}
|
||||
mFloatingView.update(currentBounds, mIconAlpha.value, percent, 0f,
|
||||
floatingView.update(currentBounds, mIconAlpha.value, percent, 0f,
|
||||
cornerRadius * scale, true /* isOpening */);
|
||||
} else {
|
||||
matrix.setTranslate(target.position.x, target.position.y);
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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.
|
||||
-->
|
||||
<com.android.launcher3.views.FloatingIconView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
|
@ -86,7 +86,6 @@
|
|||
|
||||
<!-- View IDs to store item highlight information -->
|
||||
<item type="id" name="view_unhighlight_background" />
|
||||
<item type="id" name="view_highlighted" />
|
||||
|
||||
<!-- Menu id for feature flags -->
|
||||
<item type="id" name="menu_apply_flags" />
|
||||
|
|
|
@ -36,6 +36,7 @@ import com.android.launcher3.logging.UserEventDispatcher.UserEventDelegate;
|
|||
import com.android.launcher3.uioverrides.UiFactory;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||
import com.android.launcher3.util.SystemUiController;
|
||||
import com.android.launcher3.util.ViewCache;
|
||||
import com.android.launcher3.views.ActivityContext;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
|
@ -102,6 +103,12 @@ public abstract class BaseActivity extends Activity
|
|||
// animation
|
||||
@InvisibilityFlags private int mForceInvisible;
|
||||
|
||||
private final ViewCache mViewCache = new ViewCache();
|
||||
|
||||
public ViewCache getViewCache() {
|
||||
return mViewCache;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeviceProfile getDeviceProfile() {
|
||||
return mDeviceProfile;
|
||||
|
|
|
@ -44,7 +44,6 @@ import android.view.View;
|
|||
import com.android.launcher3.FastBitmapDrawable;
|
||||
import com.android.launcher3.ItemInfo;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherModel;
|
||||
import com.android.launcher3.LauncherSettings;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.LauncherStateManager;
|
||||
|
@ -55,6 +54,7 @@ import com.android.launcher3.anim.Interpolators;
|
|||
import com.android.launcher3.icons.LauncherIcons;
|
||||
import com.android.launcher3.util.Themes;
|
||||
import com.android.launcher3.util.Thunk;
|
||||
import com.android.launcher3.util.UiThreadHelper;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
|
@ -210,8 +210,7 @@ public class DragView extends View implements LauncherStateManager.StateListener
|
|||
return;
|
||||
}
|
||||
// Load the adaptive icon on a background thread and add the view in ui thread.
|
||||
final Looper workerLooper = LauncherModel.getWorkerLooper();
|
||||
new Handler(workerLooper).postAtFrontOfQueue(new Runnable() {
|
||||
new Handler(UiThreadHelper.getBackgroundLooper()).postAtFrontOfQueue(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Object[] outObj = new Object[1];
|
||||
|
|
|
@ -102,7 +102,6 @@ public class FolderIcon extends FrameLayout implements FolderListener {
|
|||
private List<BubbleTextView> mCurrentPreviewItems = new ArrayList<>();
|
||||
|
||||
boolean mAnimating = false;
|
||||
private Rect mTempBounds = new Rect();
|
||||
|
||||
private float mSlop;
|
||||
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* 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.util.SparseArray;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
/**
|
||||
* Utility class to cache views at an activity level
|
||||
*/
|
||||
public class ViewCache {
|
||||
|
||||
protected final SparseArray<CacheEntry> mCache = new SparseArray();
|
||||
|
||||
public void setCacheSize(int layoutId, int size) {
|
||||
mCache.put(layoutId, new CacheEntry(size));
|
||||
}
|
||||
|
||||
public <T extends View> T getView(int layoutId, Context context, ViewGroup parent) {
|
||||
CacheEntry entry = mCache.get(layoutId);
|
||||
if (entry == null) {
|
||||
entry = new CacheEntry(1);
|
||||
mCache.put(layoutId, entry);
|
||||
}
|
||||
|
||||
if (entry.mCurrentSize > 0) {
|
||||
entry.mCurrentSize --;
|
||||
T result = (T) entry.mViews[entry.mCurrentSize];
|
||||
entry.mViews[entry.mCurrentSize] = null;
|
||||
return result;
|
||||
}
|
||||
|
||||
return (T) LayoutInflater.from(context).inflate(layoutId, parent, false);
|
||||
}
|
||||
|
||||
public void recycleView(int layoutId, View view) {
|
||||
CacheEntry entry = mCache.get(layoutId);
|
||||
if (entry != null && entry.mCurrentSize < entry.mMaxSize) {
|
||||
entry.mViews[entry.mCurrentSize] = view;
|
||||
entry.mCurrentSize++;
|
||||
}
|
||||
}
|
||||
|
||||
private static class CacheEntry {
|
||||
|
||||
final int mMaxSize;
|
||||
final View[] mViews;
|
||||
|
||||
int mCurrentSize;
|
||||
|
||||
public CacheEntry(int maxSize) {
|
||||
mMaxSize = maxSize;
|
||||
mViews = new View[maxSize];
|
||||
mCurrentSize = 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -27,6 +27,7 @@ import android.animation.AnimatorSet;
|
|||
import android.animation.ObjectAnimator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Outline;
|
||||
|
@ -40,6 +41,7 @@ import android.os.Build;
|
|||
import android.os.CancellationSignal;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewOutlineProvider;
|
||||
|
@ -61,6 +63,7 @@ import com.android.launcher3.graphics.ShiftedBitmapDrawable;
|
|||
import com.android.launcher3.icons.LauncherIcons;
|
||||
import com.android.launcher3.popup.SystemShortcut;
|
||||
import com.android.launcher3.shortcuts.DeepShortcutView;
|
||||
import com.android.launcher3.util.UiThreadHelper;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.WorkerThread;
|
||||
|
@ -148,12 +151,20 @@ public class FloatingIconView extends View implements
|
|||
private final SpringAnimation mFgSpringX;
|
||||
private float mFgTransX;
|
||||
|
||||
private FloatingIconView(Launcher launcher) {
|
||||
super(launcher);
|
||||
mLauncher = launcher;
|
||||
public FloatingIconView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public FloatingIconView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public FloatingIconView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
mLauncher = Launcher.getLauncher(context);
|
||||
mBlurSizeOutline = getResources().getDimensionPixelSize(
|
||||
R.dimen.blur_size_medium_outline);
|
||||
mListenerView = new ListenerView(launcher, null);
|
||||
mListenerView = new ListenerView(context, attrs);
|
||||
|
||||
mFgSpringX = new SpringAnimation(this, mFgTransXProperty)
|
||||
.setSpring(new SpringForce()
|
||||
|
@ -350,6 +361,7 @@ public class FloatingIconView extends View implements
|
|||
}
|
||||
|
||||
@WorkerThread
|
||||
@SuppressWarnings("WrongThread")
|
||||
private void getIcon(View v, ItemInfo info, boolean isOpening,
|
||||
Runnable onIconLoadedRunnable, CancellationSignal loadIconSignal) {
|
||||
final LayoutParams lp = (LayoutParams) getLayoutParams();
|
||||
|
@ -396,7 +408,7 @@ public class FloatingIconView extends View implements
|
|||
&& finalDrawable instanceof AdaptiveIconDrawable;
|
||||
int iconOffset = getOffsetForIconBounds(finalDrawable);
|
||||
|
||||
new Handler(Looper.getMainLooper()).post(() -> {
|
||||
mLauncher.getMainExecutor().execute(() -> {
|
||||
if (isAdaptiveIcon) {
|
||||
mIsAdaptiveIcon = true;
|
||||
boolean isFolderIcon = finalDrawable instanceof FolderAdaptiveIcon;
|
||||
|
@ -505,6 +517,7 @@ public class FloatingIconView extends View implements
|
|||
}
|
||||
|
||||
@WorkerThread
|
||||
@SuppressWarnings("WrongThread")
|
||||
private int getOffsetForIconBounds(Drawable drawable) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O ||
|
||||
!(drawable instanceof AdaptiveIconDrawable)) {
|
||||
|
@ -515,7 +528,7 @@ public class FloatingIconView extends View implements
|
|||
Rect bounds = new Rect(0, 0, lp.width + mBlurSizeOutline, lp.height + mBlurSizeOutline);
|
||||
bounds.inset(mBlurSizeOutline / 2, mBlurSizeOutline / 2);
|
||||
|
||||
try (LauncherIcons li = LauncherIcons.obtain(getContext())) {
|
||||
try (LauncherIcons li = LauncherIcons.obtain(mLauncher)) {
|
||||
Utilities.scaleRectAboutCenter(bounds, li.getNormalizer().getScale(drawable, null));
|
||||
}
|
||||
|
||||
|
@ -604,11 +617,14 @@ public class FloatingIconView extends View implements
|
|||
* @param isOpening True if this view replaces the icon for app open animation.
|
||||
*/
|
||||
public static FloatingIconView getFloatingIconView(Launcher launcher, View originalView,
|
||||
boolean hideOriginal, RectF positionOut, boolean isOpening, FloatingIconView recycle) {
|
||||
if (recycle != null) {
|
||||
recycle.recycle();
|
||||
}
|
||||
FloatingIconView view = recycle != null ? recycle : new FloatingIconView(launcher);
|
||||
boolean hideOriginal, RectF positionOut, boolean isOpening) {
|
||||
final DragLayer dragLayer = launcher.getDragLayer();
|
||||
ViewGroup parent = (ViewGroup) dragLayer.getParent();
|
||||
|
||||
FloatingIconView view = launcher.getViewCache().getView(R.layout.floating_icon_view,
|
||||
launcher, parent);
|
||||
view.recycle();
|
||||
|
||||
view.mIsVerticalBarLayout = launcher.getDeviceProfile().isVerticalBarLayout();
|
||||
|
||||
view.mOriginalIcon = originalView;
|
||||
|
@ -626,16 +642,15 @@ public class FloatingIconView extends View implements
|
|||
originalView.setVisibility(INVISIBLE);
|
||||
};
|
||||
CancellationSignal loadIconSignal = view.mLoadIconSignal;
|
||||
new Handler(LauncherModel.getWorkerLooper()).postAtFrontOfQueue(() -> {
|
||||
new Handler(UiThreadHelper.getBackgroundLooper()).postAtFrontOfQueue(() -> {
|
||||
view.getIcon(originalView, (ItemInfo) originalView.getTag(), isOpening,
|
||||
onIconLoaded, loadIconSignal);
|
||||
});
|
||||
}
|
||||
|
||||
// We need to add it to the overlay, but keep it invisible until animation starts..
|
||||
final DragLayer dragLayer = launcher.getDragLayer();
|
||||
view.setVisibility(INVISIBLE);
|
||||
((ViewGroup) dragLayer.getParent()).addView(view);
|
||||
parent.addView(view);
|
||||
dragLayer.addView(view.mListenerView);
|
||||
view.mListenerView.setListener(view::onListenerViewClosed);
|
||||
|
||||
|
@ -714,6 +729,7 @@ public class FloatingIconView extends View implements
|
|||
((ViewGroup) dragLayer.getParent()).removeView(this);
|
||||
dragLayer.removeView(mListenerView);
|
||||
recycle();
|
||||
mLauncher.getViewCache().recycleView(R.layout.floating_icon_view, this);
|
||||
}
|
||||
|
||||
private void recycle() {
|
||||
|
|
Loading…
Reference in New Issue