Merge "Quick patch for PredictionUiStateManager.applyState interrupting allapps" into ub-launcher3-qt-dev
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java
index 90b5536..4b2e487 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java
@@ -118,7 +118,8 @@
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() {
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
index 0c997dd..6ba1bf5 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
@@ -331,16 +331,8 @@
defaultDisplay.getRealSize(realSize);
mSwipeTouchRegion.set(0, 0, realSize.x, realSize.y);
if (mMode == Mode.NO_BUTTON) {
- switch (defaultDisplay.getRotation()) {
- case Surface.ROTATION_90:
- case Surface.ROTATION_270:
- mSwipeTouchRegion.top = mSwipeTouchRegion.bottom - getNavbarSize(
- ResourceUtils.NAVBAR_LANDSCAPE_BOTTOM_SIZE);
- break;
- default:
- mSwipeTouchRegion.top = mSwipeTouchRegion.bottom - getNavbarSize(
- ResourceUtils.NAVBAR_PORTRAIT_BOTTOM_SIZE);
- }
+ mSwipeTouchRegion.top = mSwipeTouchRegion.bottom -
+ getNavbarSize(ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE);
} else {
switch (defaultDisplay.getRotation()) {
case Surface.ROTATION_90:
@@ -353,7 +345,7 @@
break;
default:
mSwipeTouchRegion.top = mSwipeTouchRegion.bottom
- - getNavbarSize(ResourceUtils.NAVBAR_PORTRAIT_BOTTOM_SIZE);
+ - getNavbarSize(ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE);
}
}
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java
index 2ff5c0c..bbc6eb3 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java
@@ -170,7 +170,8 @@
STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_DRAWN | STATE_LAUNCHER_STARTED;
public enum GestureEndTarget {
- HOME(1, STATE_SCALED_CONTROLLER_HOME, true, false, ContainerType.WORKSPACE, false),
+ HOME(1, STATE_SCALED_CONTROLLER_HOME | STATE_CAPTURE_SCREENSHOT, true, false,
+ ContainerType.WORKSPACE, false),
RECENTS(1, STATE_SCALED_CONTROLLER_RECENTS | STATE_CAPTURE_SCREENSHOT
| STATE_SCREENSHOT_VIEW_SHOWN, true, false, ContainerType.TASKSWITCHER, true),
@@ -331,9 +332,8 @@
| STATE_SCALED_CONTROLLER_RECENTS,
this::finishCurrentTransitionToRecents);
- mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_GESTURE_COMPLETED
- | STATE_SCALED_CONTROLLER_HOME | STATE_APP_CONTROLLER_RECEIVED
- | STATE_LAUNCHER_DRAWN,
+ mStateCallback.addCallback(STATE_SCREENSHOT_CAPTURED | STATE_GESTURE_COMPLETED
+ | STATE_SCALED_CONTROLLER_HOME,
this::finishCurrentTransitionToHome);
mStateCallback.addCallback(STATE_SCALED_CONTROLLER_HOME | STATE_CURRENT_TASK_FINISHED,
this::reset);
@@ -1251,7 +1251,14 @@
if (mTaskSnapshot == null) {
mTaskSnapshot = controller.screenshotTask(mRunningTaskId);
}
- TaskView taskView = mRecentsView.updateThumbnail(mRunningTaskId, mTaskSnapshot);
+ final TaskView taskView;
+ if (mGestureEndTarget == HOME) {
+ // Capture the screenshot before finishing the transition to home to ensure it's
+ // taken in the correct orientation, but no need to update the thumbnail.
+ taskView = null;
+ } else {
+ taskView = mRecentsView.updateThumbnail(mRunningTaskId, mTaskSnapshot);
+ }
if (taskView != null) {
// Defer finishing the animation until the next launcher frame with the
// new thumbnail
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RectFSpringAnim.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RectFSpringAnim.java
index 3f4ad58..77dc6f3 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RectFSpringAnim.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RectFSpringAnim.java
@@ -16,26 +16,22 @@
package com.android.quickstep.util;
import android.animation.Animator;
-import android.animation.ObjectAnimator;
-import android.animation.PropertyValuesHolder;
-import android.animation.ValueAnimator;
import android.content.res.Resources;
import android.graphics.PointF;
import android.graphics.RectF;
-import android.util.FloatProperty;
import androidx.dynamicanimation.animation.DynamicAnimation.OnAnimationEndListener;
import androidx.dynamicanimation.animation.FloatPropertyCompat;
+import androidx.dynamicanimation.animation.SpringAnimation;
+import androidx.dynamicanimation.animation.SpringForce;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
-import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.FlingSpringAnim;
import java.util.ArrayList;
import java.util.List;
-import static com.android.launcher3.anim.Interpolators.DEACCEL;
/**
* Applies spring forces to animate from a starting rect to a target rect,
@@ -43,14 +39,6 @@
*/
public class RectFSpringAnim {
- /**
- * Although the rect position animation takes an indefinite amount of time since it depends on
- * the initial velocity and applied forces, scaling from the starting rect to the target rect
- * can be done in parallel at a fixed duration. Update callbacks are sent based on the progress
- * of this animation, while the end callback is sent after all animations finish.
- */
- private static final long RECT_SCALE_DURATION = 250;
-
private static final FloatPropertyCompat<RectFSpringAnim> RECT_CENTER_X =
new FloatPropertyCompat<RectFSpringAnim>("rectCenterXSpring") {
@Override
@@ -79,17 +67,17 @@
}
};
- private static final FloatProperty<RectFSpringAnim> RECT_SCALE_PROGRESS =
- new FloatProperty<RectFSpringAnim>("rectScaleProgress") {
+ private static final FloatPropertyCompat<RectFSpringAnim> RECT_SCALE_PROGRESS =
+ new FloatPropertyCompat<RectFSpringAnim>("rectScaleProgress") {
@Override
- public Float get(RectFSpringAnim anim) {
- return anim.mCurrentScaleProgress;
+ public float getValue(RectFSpringAnim object) {
+ return object.mCurrentScaleProgress;
}
@Override
- public void setValue(RectFSpringAnim anim, float currentScaleProgress) {
- anim.mCurrentScaleProgress = currentScaleProgress;
- anim.onUpdate();
+ public void setValue(RectFSpringAnim object, float value) {
+ object.mCurrentScaleProgress = value;
+ object.onUpdate();
}
};
@@ -106,7 +94,7 @@
private float mCurrentScaleProgress;
private FlingSpringAnim mRectXAnim;
private FlingSpringAnim mRectYAnim;
- private ValueAnimator mRectScaleAnim;
+ private SpringAnimation mRectScaleAnim;
private boolean mAnimsStarted;
private boolean mRectXAnimEnded;
private boolean mRectYAnimEnded;
@@ -177,17 +165,18 @@
mRectYAnim = new FlingSpringAnim(this, RECT_Y, startY, endY, startVelocityY,
mMinVisChange, minYValue, maxYValue, springVelocityFactor, onYEndListener);
- mRectScaleAnim = ObjectAnimator.ofPropertyValuesHolder(this,
- PropertyValuesHolder.ofFloat(RECT_SCALE_PROGRESS, 1))
- .setDuration(RECT_SCALE_DURATION);
- mRectScaleAnim.setInterpolator(DEACCEL);
- mRectScaleAnim.addListener(new AnimationSuccessListener() {
- @Override
- public void onAnimationSuccess(Animator animator) {
- mRectScaleAnimEnded = true;
- maybeOnEnd();
- }
- });
+ float minVisibleChange = 1f / mStartRect.height();
+ mRectScaleAnim = new SpringAnimation(this, RECT_SCALE_PROGRESS)
+ .setSpring(new SpringForce(1f)
+ .setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY)
+ .setStiffness(SpringForce.STIFFNESS_LOW))
+ .setStartVelocity(velocityPxPerMs.y * minVisibleChange)
+ .setMaxValue(1f)
+ .setMinimumVisibleChange(minVisibleChange)
+ .addEndListener((animation, canceled, value, velocity) -> {
+ mRectScaleAnimEnded = true;
+ maybeOnEnd();
+ });
mRectXAnim.start();
mRectYAnim.start();
@@ -202,7 +191,9 @@
if (mAnimsStarted) {
mRectXAnim.end();
mRectYAnim.end();
- mRectScaleAnim.end();
+ if (mRectScaleAnim.canSkipToEnd()) {
+ mRectScaleAnim.skipToEnd();
+ }
}
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
index 661468a..1e1007e 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
@@ -66,7 +66,6 @@
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.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.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 @@
private Layout mEmptyTextLayout;
private LiveTileOverlay mLiveTileOverlay;
- private FloatingIconView mFloatingIconView;
-
private BaseActivity.MultiWindowModeChangedListener mMultiWindowModeChangedListener =
(inMultiWindowMode) -> {
if (!inMultiWindowMode && mOverviewStateEnabled) {
@@ -1687,12 +1682,6 @@
}
}
- 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;
}
diff --git a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
index 91c4601..95ae312 100644
--- a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
+++ b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
@@ -142,7 +142,6 @@
private final float mClosingWindowTransY;
private DeviceProfile mDeviceProfile;
- private FloatingIconView mFloatingView;
private RemoteAnimationProvider mRemoteAnimationProvider;
@@ -411,15 +410,15 @@
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 @@
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 @@
} 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);
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index 43d6311..f02859f 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -127,7 +127,7 @@
assertNotNull("OverviewTask.open returned null", task.open());
assertTrue("Test activity didn't open from Overview", mDevice.wait(Until.hasObject(
By.pkg(getAppPackageName()).text("TestActivity2")),
- LONG_WAIT_TIME_MS));
+ DEFAULT_UI_TIMEOUT));
executeOnLauncher(launcher -> assertTrue(
"Launcher activity is the top activity; expecting another activity to be the top "
+ "one",
diff --git a/res/layout/floating_icon_view.xml b/res/layout/floating_icon_view.xml
new file mode 100644
index 0000000..240c486
--- /dev/null
+++ b/res/layout/floating_icon_view.xml
@@ -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" />
diff --git a/res/values/config.xml b/res/values/config.xml
index 83aea8b..984729b 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -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" />
diff --git a/src/com/android/launcher3/BaseActivity.java b/src/com/android/launcher3/BaseActivity.java
index 7f72242..424ffde 100644
--- a/src/com/android/launcher3/BaseActivity.java
+++ b/src/com/android/launcher3/BaseActivity.java
@@ -36,6 +36,7 @@
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 @@
// animation
@InvisibilityFlags private int mForceInvisible;
+ private final ViewCache mViewCache = new ViewCache();
+
+ public ViewCache getViewCache() {
+ return mViewCache;
+ }
+
@Override
public DeviceProfile getDeviceProfile() {
return mDeviceProfile;
diff --git a/src/com/android/launcher3/ResourceUtils.java b/src/com/android/launcher3/ResourceUtils.java
index 0c80d13..73e705b 100644
--- a/src/com/android/launcher3/ResourceUtils.java
+++ b/src/com/android/launcher3/ResourceUtils.java
@@ -21,10 +21,9 @@
import android.util.TypedValue;
public class ResourceUtils {
- public static final String NAVBAR_PORTRAIT_BOTTOM_SIZE = "navigation_bar_frame_height";
public static final String NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE = "navigation_bar_width";
- public static final String NAVBAR_LANDSCAPE_BOTTOM_SIZE
- = "navigation_bar_frame_height_landscape";
+ public static final String NAVBAR_BOTTOM_GESTURE_SIZE = "navigation_bar_gesture_height";
+
public static int getNavbarSize(String resName, Resources res) {
return getDimenByName(resName, res, 48);
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index 41252aa..63682c7 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -41,6 +41,7 @@
import com.android.launcher3.InsettableFrameLayout;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherState;
import com.android.launcher3.R;
import com.android.launcher3.TestProtocol;
import com.android.launcher3.Utilities;
@@ -193,11 +194,18 @@
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
+
+ // The AllAppsContainerView houses the QSB and is hence visible from the Workspace
+ // Overview states. We shouldn't intercept for the scrubber in these cases.
+ if (!mLauncher.isInState(LauncherState.ALL_APPS)) return false;
+
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
AllAppsRecyclerView rv = getActiveRecyclerView();
if (rv != null &&
rv.getScrollbar().isHitInParent(ev.getX(), ev.getY(), mFastScrollerOffset)) {
mTouchHandler = rv.getScrollbar();
+ } else {
+ mTouchHandler = null;
}
}
if (mTouchHandler != null) {
diff --git a/src/com/android/launcher3/dragndrop/DragView.java b/src/com/android/launcher3/dragndrop/DragView.java
index 7af12c5..9d46cf2 100644
--- a/src/com/android/launcher3/dragndrop/DragView.java
+++ b/src/com/android/launcher3/dragndrop/DragView.java
@@ -44,7 +44,6 @@
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.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 @@
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];
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index 0a9bc72..250169c 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -102,7 +102,6 @@
private List<BubbleTextView> mCurrentPreviewItems = new ArrayList<>();
boolean mAnimating = false;
- private Rect mTempBounds = new Rect();
private float mSlop;
diff --git a/src/com/android/launcher3/util/ViewCache.java b/src/com/android/launcher3/util/ViewCache.java
new file mode 100644
index 0000000..08b8744
--- /dev/null
+++ b/src/com/android/launcher3/util/ViewCache.java
@@ -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;
+ }
+ }
+}
diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java
index 3d5877a..f63bcdd 100644
--- a/src/com/android/launcher3/views/FloatingIconView.java
+++ b/src/com/android/launcher3/views/FloatingIconView.java
@@ -27,6 +27,7 @@
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.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.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 @@
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 @@
}
@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 @@
&& 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 @@
}
@WorkerThread
+ @SuppressWarnings("WrongThread")
private int getOffsetForIconBounds(Drawable drawable) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O ||
!(drawable instanceof AdaptiveIconDrawable)) {
@@ -515,7 +528,7 @@
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 @@
* @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 @@
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 @@
((ViewGroup) dragLayer.getParent()).removeView(this);
dragLayer.removeView(mListenerView);
recycle();
+ mLauncher.getViewCache().recycleView(R.layout.floating_icon_view, this);
}
private void recycle() {
diff --git a/tests/AndroidManifest-common.xml b/tests/AndroidManifest-common.xml
index 75ff66e..61c7306 100644
--- a/tests/AndroidManifest-common.xml
+++ b/tests/AndroidManifest-common.xml
@@ -184,5 +184,13 @@
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity-alias>
+ <activity-alias android:name="Activity11"
+ android:label="TestActivity11"
+ android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity-alias>
</application>
</manifest>
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 74cece8..a19857c 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -91,7 +91,6 @@
public static final long SHORT_UI_TIMEOUT = 300;
public static final long DEFAULT_UI_TIMEOUT = 10000;
- protected static final int LONG_WAIT_TIME_MS = 60000;
private static final String TAG = "AbstractLauncherUiTest";
private static int sScreenshotCount = 0;
@@ -243,7 +242,7 @@
*/
protected UiObject2 scrollAndFind(UiObject2 container, BySelector condition) {
final int margin = ResourceUtils.getNavbarSize(
- ResourceUtils.NAVBAR_PORTRAIT_BOTTOM_SIZE, mLauncher.getResources()) + 1;
+ ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE, mLauncher.getResources()) + 1;
container.setGestureMargins(0, 0, 0, margin);
int i = 0;
@@ -394,7 +393,7 @@
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
instrumentation.getTargetContext().startActivity(intent);
assertTrue(packageName + " didn't start",
- mDevice.wait(Until.hasObject(By.pkg(packageName).depth(0)), LONG_WAIT_TIME_MS));
+ mDevice.wait(Until.hasObject(By.pkg(packageName).depth(0)), DEFAULT_UI_TIMEOUT));
}
protected void startTestActivity(int activityNumber) {
@@ -410,7 +409,7 @@
assertTrue(packageName + " didn't start",
mDevice.wait(
Until.hasObject(By.pkg(packageName).text("TestActivity" + activityNumber)),
- LONG_WAIT_TIME_MS));
+ DEFAULT_UI_TIMEOUT));
}
protected static String resolveSystemApp(String category) {
diff --git a/tests/tapl/com/android/launcher3/tapl/AllApps.java b/tests/tapl/com/android/launcher3/tapl/AllApps.java
index 70405fe..b2043cb 100644
--- a/tests/tapl/com/android/launcher3/tapl/AllApps.java
+++ b/tests/tapl/com/android/launcher3/tapl/AllApps.java
@@ -97,7 +97,7 @@
0,
getSearchBox(allAppsContainer).getVisibleBounds().bottom + 1,
0,
- ResourceUtils.getNavbarSize(ResourceUtils.NAVBAR_PORTRAIT_BOTTOM_SIZE,
+ ResourceUtils.getNavbarSize(ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE,
mLauncher.getResources()) + 1);
final BySelector appIconSelector = AppIcon.getAppIconSelector(appName, mLauncher);
if (!hasClickableIcon(allAppsContainer, appListRecycler, appIconSelector)) {
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index a4711f5..7978c79 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -115,7 +115,7 @@
private static final String APPS_RES_ID = "apps_view";
private static final String OVERVIEW_RES_ID = "overview_panel";
private static final String WIDGETS_RES_ID = "widgets_list_view";
- public static final int WAIT_TIME_MS = 60000;
+ public static final int WAIT_TIME_MS = 10000;
private static final String SYSTEMUI_PACKAGE = "com.android.systemui";
private static WeakReference<VisibleContainer> sActiveContainer = new WeakReference<>(null);
@@ -541,25 +541,22 @@
@NonNull
UiObject2 waitForLauncherObject(String resName) {
- final BySelector selector = getLauncherObjectSelector(resName);
- final UiObject2 object = mDevice.wait(Until.findObject(selector), WAIT_TIME_MS);
- assertNotNull("Can't find a launcher object; selector: " + selector, object);
- return object;
+ return waitForObjectBySelector(getLauncherObjectSelector(resName));
}
@NonNull
UiObject2 waitForLauncherObjectByClass(String clazz) {
- final BySelector selector = getLauncherObjectSelectorByClass(clazz);
- final UiObject2 object = mDevice.wait(Until.findObject(selector), WAIT_TIME_MS);
- assertNotNull("Can't find a launcher object; selector: " + selector, object);
- return object;
+ return waitForObjectBySelector(getLauncherObjectSelectorByClass(clazz));
}
@NonNull
UiObject2 waitForFallbackLauncherObject(String resName) {
- final BySelector selector = getFallbackLauncherObjectSelector(resName);
+ return waitForObjectBySelector(getFallbackLauncherObjectSelector(resName));
+ }
+
+ private UiObject2 waitForObjectBySelector(BySelector selector) {
final UiObject2 object = mDevice.wait(Until.findObject(selector), WAIT_TIME_MS);
- assertNotNull("Can't find a fallback launcher object; selector: " + selector, object);
+ assertNotNull("Can't find a launcher object; selector: " + selector, object);
return object;
}
diff --git a/tests/tapl/com/android/launcher3/tapl/Widgets.java b/tests/tapl/com/android/launcher3/tapl/Widgets.java
index b780df4..94003be 100644
--- a/tests/tapl/com/android/launcher3/tapl/Widgets.java
+++ b/tests/tapl/com/android/launcher3/tapl/Widgets.java
@@ -41,7 +41,7 @@
LauncherInstrumentation.log("Widgets.flingForward enter");
final UiObject2 widgetsContainer = verifyActiveContainer();
widgetsContainer.setGestureMargins(0, 0, 0,
- ResourceUtils.getNavbarSize(ResourceUtils.NAVBAR_PORTRAIT_BOTTOM_SIZE,
+ ResourceUtils.getNavbarSize(ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE,
mLauncher.getResources()) + 1);
widgetsContainer.fling(Direction.DOWN,
(int) (FLING_SPEED * mLauncher.getDisplayDensity()));