Merge "Add task content animation property" into ub-launcher3-master
diff --git a/go/quickstep/src/com/android/quickstep/TouchInteractionService.java b/go/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 734425e..39f8448 100644
--- a/go/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/go/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -88,6 +88,10 @@
boolean gestureSwipeLeft) {
}
+ public void onSystemUiStateChanged(int stateFlags) {
+ // To be implemented
+ }
+
/** Deprecated methods **/
public void onQuickStep(MotionEvent motionEvent) { }
diff --git a/go/quickstep/src/com/android/quickstep/views/IconRecentsView.java b/go/quickstep/src/com/android/quickstep/views/IconRecentsView.java
index c06b6ec..7f77b6c 100644
--- a/go/quickstep/src/com/android/quickstep/views/IconRecentsView.java
+++ b/go/quickstep/src/com/android/quickstep/views/IconRecentsView.java
@@ -24,14 +24,12 @@
import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
import android.content.Context;
+import android.util.ArraySet;
import android.util.AttributeSet;
import android.util.FloatProperty;
import android.view.View;
import android.view.ViewDebug;
-import android.view.animation.AlphaAnimation;
-import android.view.animation.Animation;
-import android.view.animation.AnimationSet;
-import android.view.animation.LayoutAnimationController;
+import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
import androidx.annotation.NonNull;
@@ -40,6 +38,7 @@
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.RecyclerView.AdapterDataObserver;
+import androidx.recyclerview.widget.RecyclerView.OnChildAttachStateChangeListener;
import com.android.launcher3.R;
import com.android.quickstep.RecentsToActivityHelper;
@@ -90,7 +89,6 @@
private final TaskListLoader mTaskLoader;
private final TaskAdapter mTaskAdapter;
private final TaskActionController mTaskActionController;
- private final LayoutAnimationController mLayoutAnimation;
private RecentsToActivityHelper mActivityHelper;
private RecyclerView mTaskRecyclerView;
@@ -98,6 +96,9 @@
private View mContentView;
private View mClearAllView;
private boolean mTransitionedFromApp;
+ private AnimatorSet mLayoutAnimation;
+ private final ArraySet<View> mLayingOutViews = new ArraySet<>();
+
public IconRecentsView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -106,7 +107,6 @@
mTaskAdapter = new TaskAdapter(mTaskLoader);
mTaskActionController = new TaskActionController(mTaskLoader, mTaskAdapter);
mTaskAdapter.setActionController(mTaskActionController);
- mLayoutAnimation = createLayoutAnimation();
}
@Override
@@ -120,7 +120,20 @@
ItemTouchHelper helper = new ItemTouchHelper(
new TaskSwipeCallback(mTaskActionController));
helper.attachToRecyclerView(mTaskRecyclerView);
- mTaskRecyclerView.setLayoutAnimation(mLayoutAnimation);
+ mTaskRecyclerView.addOnChildAttachStateChangeListener(
+ new OnChildAttachStateChangeListener() {
+ @Override
+ public void onChildViewAttachedToWindow(@NonNull View view) {
+ if (mLayoutAnimation != null && !mLayingOutViews.contains(view)) {
+ // Child view was added that is not part of current layout animation
+ // so restart the animation.
+ animateFadeInLayoutAnimation();
+ }
+ }
+
+ @Override
+ public void onChildViewDetachedFromWindow(@NonNull View view) { }
+ });
mEmptyView = findViewById(R.id.recent_task_empty_view);
mContentView = findViewById(R.id.recent_task_content_view);
@@ -165,8 +178,7 @@
* becomes visible.
*/
public void onBeginTransitionToOverview() {
- mTaskRecyclerView.scheduleLayoutAnimation();
-
+ scheduleFadeInLayoutAnimation();
// Load any task changes
if (!mTaskLoader.needsToLoad()) {
return;
@@ -338,17 +350,56 @@
});
}
- private static LayoutAnimationController createLayoutAnimation() {
- AnimationSet anim = new AnimationSet(false /* shareInterpolator */);
+ /**
+ * Schedule a one-shot layout animation on the next layout. Separate from
+ * {@link #scheduleLayoutAnimation()} as the animation is {@link Animator} based and acts on the
+ * view properties themselves, allowing more controllable behavior and making it easier to
+ * manage when the animation conflicts with another animation.
+ */
+ private void scheduleFadeInLayoutAnimation() {
+ ViewTreeObserver viewTreeObserver = mTaskRecyclerView.getViewTreeObserver();
+ viewTreeObserver.addOnGlobalLayoutListener(
+ new ViewTreeObserver.OnGlobalLayoutListener() {
+ @Override
+ public void onGlobalLayout() {
+ animateFadeInLayoutAnimation();
+ viewTreeObserver.removeOnGlobalLayoutListener(this);
+ }
+ });
+ }
- Animation alphaAnim = new AlphaAnimation(0, 1);
- alphaAnim.setDuration(LAYOUT_ITEM_ANIMATE_IN_DURATION);
- anim.addAnimation(alphaAnim);
-
- LayoutAnimationController layoutAnim = new LayoutAnimationController(anim);
- layoutAnim.setDelay(
- (float) LAYOUT_ITEM_ANIMATE_IN_DELAY_BETWEEN / LAYOUT_ITEM_ANIMATE_IN_DURATION);
-
- return layoutAnim;
+ /**
+ * Start animating the layout animation where items fade in.
+ */
+ private void animateFadeInLayoutAnimation() {
+ if (mLayoutAnimation != null) {
+ // If layout animation still in progress, cancel and restart.
+ mLayoutAnimation.cancel();
+ }
+ TaskItemView[] views = getTaskViews();
+ int delay = 0;
+ mLayoutAnimation = new AnimatorSet();
+ for (TaskItemView view : views) {
+ view.setAlpha(0.0f);
+ Animator alphaAnim = ObjectAnimator.ofFloat(view, ALPHA, 0.0f, 1.0f);
+ alphaAnim.setDuration(LAYOUT_ITEM_ANIMATE_IN_DURATION).setStartDelay(delay);
+ alphaAnim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ view.setAlpha(1.0f);
+ mLayingOutViews.remove(view);
+ }
+ });
+ delay += LAYOUT_ITEM_ANIMATE_IN_DELAY_BETWEEN;
+ mLayoutAnimation.play(alphaAnim);
+ mLayingOutViews.add(view);
+ }
+ mLayoutAnimation.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mLayoutAnimation = null;
+ }
+ });
+ mLayoutAnimation.start();
}
}
diff --git a/go/quickstep/src/com/android/quickstep/views/TaskLayerDrawable.java b/go/quickstep/src/com/android/quickstep/views/TaskLayerDrawable.java
index 3a23048..98b66b9 100644
--- a/go/quickstep/src/com/android/quickstep/views/TaskLayerDrawable.java
+++ b/go/quickstep/src/com/android/quickstep/views/TaskLayerDrawable.java
@@ -31,6 +31,7 @@
*/
public final class TaskLayerDrawable extends LayerDrawable {
private final Drawable mEmptyDrawable;
+ private float mProgress;
public TaskLayerDrawable(Context context) {
super(new Drawable[0]);
@@ -50,6 +51,7 @@
*/
public void setCurrentDrawable(@NonNull Drawable drawable) {
setDrawable(0, drawable);
+ applyTransitionProgress(mProgress);
}
/**
@@ -82,9 +84,18 @@
if (progress > 1 || progress < 0) {
throw new IllegalArgumentException("Transition progress should be between 0 and 1");
}
+ mProgress = progress;
+ applyTransitionProgress(progress);
+ }
+
+ private void applyTransitionProgress(float progress) {
int drawableAlpha = (int) (progress * 255);
getDrawable(0).setAlpha(drawableAlpha);
- getDrawable(1).setAlpha(255 - drawableAlpha);
+ if (getDrawable(0) != getDrawable(1)) {
+ // Only do this if it's a different drawable so that it fades out.
+ // Otherwise, we'd just be overwriting the front drawable's alpha.
+ getDrawable(1).setAlpha(255 - drawableAlpha);
+ }
invalidateSelf();
}
}
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 3ea8de0..e591177 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
@@ -159,6 +159,10 @@
isButton, gestureSwipeLeft, activityControl.getContainerType());
}
+ public void onSystemUiStateChanged(int stateFlags) {
+ // To be implemented
+ }
+
/** Deprecated methods **/
public void onQuickStep(MotionEvent motionEvent) { }
diff --git a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
index c1727cc..dfb0edf 100644
--- a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
+++ b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
@@ -321,7 +321,7 @@
final AppIconMenuItem menuItem = menu.getMenuItem(1);
final String itemName = menuItem.getText();
- menuItem.launch(getAppPackageName(), APP_NAME);
+ menuItem.launch(getAppPackageName());
}
@Test
@@ -337,7 +337,7 @@
getAppIcon(APP_NAME).
dragToWorkspace().
getWorkspaceAppIcon(APP_NAME).
- launch(getAppPackageName(), APP_NAME);
+ launch(getAppPackageName());
} finally {
TestProtocol.sDebugTracing = false;
}
@@ -365,7 +365,7 @@
menuItem.
dragToWorkspace().
getWorkspaceAppIcon(shortcutName).
- launch(getAppPackageName(), APP_NAME);
+ launch(getAppPackageName());
}
private static String getAppPackageName() {
diff --git a/tests/tapl/com/android/launcher3/tapl/AppIcon.java b/tests/tapl/com/android/launcher3/tapl/AppIcon.java
index fbeb3a2..44fc3f7 100644
--- a/tests/tapl/com/android/launcher3/tapl/AppIcon.java
+++ b/tests/tapl/com/android/launcher3/tapl/AppIcon.java
@@ -50,4 +50,9 @@
downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, iconCenter);
return new AppIconMenu(mLauncher, deepShortcutsContainer);
}
+
+ @Override
+ protected String getLongPressIndicator() {
+ return "deep_shortcuts_container";
+ }
}
diff --git a/tests/tapl/com/android/launcher3/tapl/AppIconMenuItem.java b/tests/tapl/com/android/launcher3/tapl/AppIconMenuItem.java
index c39f8d1..ba9c10e 100644
--- a/tests/tapl/com/android/launcher3/tapl/AppIconMenuItem.java
+++ b/tests/tapl/com/android/launcher3/tapl/AppIconMenuItem.java
@@ -32,4 +32,9 @@
public String getText() {
return mObject.getText();
}
+
+ @Override
+ protected String getLongPressIndicator() {
+ return "drop_target_bar";
+ }
}
diff --git a/tests/tapl/com/android/launcher3/tapl/Launchable.java b/tests/tapl/com/android/launcher3/tapl/Launchable.java
index 16ddba8..1b372ec 100644
--- a/tests/tapl/com/android/launcher3/tapl/Launchable.java
+++ b/tests/tapl/com/android/launcher3/tapl/Launchable.java
@@ -27,7 +27,7 @@
/**
* Ancestor for AppIcon and AppMenuItem.
*/
-class Launchable {
+abstract class Launchable {
protected final LauncherInstrumentation mLauncher;
protected final UiObject2 mObject;
@@ -45,24 +45,17 @@
* Clicks the object to launch its app.
*/
public Background launch(String expectedPackageName) {
- return launch(expectedPackageName, By.pkg(expectedPackageName).depth(0));
+ return launch(By.pkg(expectedPackageName));
}
- /**
- * Clicks the object to launch its app.
- */
- public Background launch(String expectedPackageName, String expectedAppText) {
- return launch(expectedPackageName, By.pkg(expectedPackageName).text(expectedAppText));
- }
-
- private Background launch(String errorMessage, BySelector selector) {
+ private Background launch(BySelector selector) {
LauncherInstrumentation.log("Launchable.launch before click " +
mObject.getVisibleCenter());
mLauncher.assertTrue(
"Launching an app didn't open a new window: " + mObject.getText(),
mObject.clickAndWait(Until.newWindow(), LauncherInstrumentation.WAIT_TIME_MS));
mLauncher.assertTrue(
- "App didn't start: " + errorMessage,
+ "App didn't start: " + selector,
mLauncher.getDevice().wait(Until.hasObject(selector),
LauncherInstrumentation.WAIT_TIME_MS));
return new Background(mLauncher);
@@ -76,10 +69,13 @@
Workspace.dragIconToWorkspace(
mLauncher,
this,
- new Point(device.getDisplayWidth() / 2, device.getDisplayHeight() / 2));
+ new Point(device.getDisplayWidth() / 2, device.getDisplayHeight() / 2),
+ getLongPressIndicator());
try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
"dragged launchable to workspace")) {
return new Workspace(mLauncher);
}
}
+
+ protected abstract String getLongPressIndicator();
}
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 3a45e93..08f2681 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -201,13 +201,19 @@
Closable addContextLayer(String piece) {
mDiagnosticContext.addLast(piece);
- return () -> mDiagnosticContext.removeLast();
+ log("Added context: " + getContextDescription());
+ return () -> {
+ log("Removing context: " + getContextDescription());
+ mDiagnosticContext.removeLast();
+ };
}
private void fail(String message) {
- final String ctxt = mDiagnosticContext.isEmpty() ? "" : String.join(", ",
- mDiagnosticContext) + "; ";
- Assert.fail("http://go/tapl : " + ctxt + message);
+ Assert.fail("http://go/tapl : " + getContextDescription() + message);
+ }
+
+ private String getContextDescription() {
+ return mDiagnosticContext.isEmpty() ? "" : String.join(", ", mDiagnosticContext) + "; ";
}
void assertTrue(String message, boolean condition) {
diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java
index 943332e..46562ce 100644
--- a/tests/tapl/com/android/launcher3/tapl/Workspace.java
+++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java
@@ -118,7 +118,7 @@
mLauncher,
getHotseatAppIcon("Chrome"),
new Point(mLauncher.getDevice().getDisplayWidth(),
- workspace.getVisibleBounds().centerY()));
+ workspace.getVisibleBounds().centerY()), "deep_shortcuts_container");
verifyActiveContainer();
}
assertTrue("Home screen workspace didn't become scrollable",
@@ -136,12 +136,13 @@
}
static void dragIconToWorkspace(
- LauncherInstrumentation launcher, Launchable launchable, Point dest) {
+ LauncherInstrumentation launcher, Launchable launchable, Point dest,
+ String longPressIndicator) {
LauncherInstrumentation.log("dragIconToWorkspace: begin");
final Point launchableCenter = launchable.getObject().getVisibleCenter();
final long downTime = SystemClock.uptimeMillis();
launcher.sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN, launchableCenter);
- launcher.waitForLauncherObject("deep_shortcuts_container");
+ launcher.waitForLauncherObject(longPressIndicator);
launcher.movePointer(downTime, DRAG_DURACTION, launchableCenter, dest);
launcher.sendPointer(
downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, dest);