Merge "Add app to overview anim for Recents Go." into ub-launcher3-master
This commit is contained in:
commit
0825e414f0
|
@ -21,15 +21,15 @@
|
|||
android:orientation="horizontal">
|
||||
<FrameLayout
|
||||
android:id="@+id/task_icon_and_thumbnail"
|
||||
android:layout_width="@dimen/task_item_height"
|
||||
android:layout_height="@dimen/task_item_height"
|
||||
android:layout_width="@dimen/task_thumbnail_and_icon_view_size"
|
||||
android:layout_height="@dimen/task_thumbnail_and_icon_view_size"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginHorizontal="8dp"
|
||||
android:layout_marginVertical="@dimen/task_item_half_vert_margin">
|
||||
<ImageView
|
||||
android:id="@+id/task_thumbnail"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="@dimen/task_thumbnail_width"
|
||||
android:layout_height="@dimen/task_thumbnail_height"
|
||||
android:layout_gravity="top|start"/>
|
||||
<ImageView
|
||||
android:id="@+id/task_icon"
|
||||
|
|
|
@ -15,7 +15,9 @@
|
|||
limitations under the License.
|
||||
-->
|
||||
<resources>
|
||||
<dimen name="task_item_height">60dp</dimen>
|
||||
<dimen name="task_item_half_vert_margin">8dp</dimen>
|
||||
<dimen name="task_thumbnail_and_icon_view_size">60dp</dimen>
|
||||
<dimen name="task_thumbnail_height">60dp</dimen>
|
||||
<dimen name="task_thumbnail_width">36dp</dimen>
|
||||
<dimen name="task_icon_size">36dp</dimen>
|
||||
</resources>
|
|
@ -15,15 +15,29 @@
|
|||
*/
|
||||
package com.android.quickstep;
|
||||
|
||||
import static com.android.launcher3.anim.Interpolators.ACCEL_2;
|
||||
import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
|
||||
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
|
||||
import static com.android.quickstep.util.RemoteAnimationProvider.getLayer;
|
||||
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
|
||||
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING;
|
||||
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Rect;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.android.launcher3.BaseDraggingActivity;
|
||||
import com.android.quickstep.util.MultiValueUpdateListener;
|
||||
import com.android.quickstep.util.RemoteAnimationProvider;
|
||||
import com.android.quickstep.views.IconRecentsView;
|
||||
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
|
||||
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat;
|
||||
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
|
||||
|
||||
/**
|
||||
* Provider for the atomic remote window animation from the app to the overview.
|
||||
|
@ -33,13 +47,17 @@ import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
|
|||
final class AppToOverviewAnimationProvider<T extends BaseDraggingActivity> implements
|
||||
RemoteAnimationProvider {
|
||||
|
||||
private static final long RECENTS_LAUNCH_DURATION = 250;
|
||||
private static final long APP_TO_THUMBNAIL_FADE_DURATION = 50;
|
||||
private static final long APP_SCALE_DOWN_DURATION = 400;
|
||||
private static final String TAG = "AppToOverviewAnimationProvider";
|
||||
|
||||
private final ActivityControlHelper<T> mHelper;
|
||||
private final int mTargetTaskId;
|
||||
private IconRecentsView mRecentsView;
|
||||
|
||||
AppToOverviewAnimationProvider(ActivityControlHelper<T> helper, int targetTaskId) {
|
||||
mHelper = helper;
|
||||
mTargetTaskId = targetTaskId;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -54,35 +72,157 @@ final class AppToOverviewAnimationProvider<T extends BaseDraggingActivity> imple
|
|||
false /* animate activity */, (controller) -> {
|
||||
controller.dispatchOnStart();
|
||||
ValueAnimator anim = controller.getAnimationPlayer()
|
||||
.setDuration(RECENTS_LAUNCH_DURATION);
|
||||
.setDuration(getRecentsLaunchDuration());
|
||||
anim.setInterpolator(FAST_OUT_SLOW_IN);
|
||||
anim.start();
|
||||
});
|
||||
factory.onRemoteAnimationReceived(null);
|
||||
factory.createActivityController(RECENTS_LAUNCH_DURATION);
|
||||
factory.createActivityController(getRecentsLaunchDuration());
|
||||
mRecentsView = activity.getOverviewPanel();
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create remote window animation from the currently running app to the overview panel.
|
||||
* Create remote window animation from the currently running app to the overview panel. Should
|
||||
* be called after {@link #onActivityReady}.
|
||||
*
|
||||
* @param targetCompats the target apps
|
||||
* @return animation from app to overview
|
||||
*/
|
||||
@Override
|
||||
public AnimatorSet createWindowAnimation(RemoteAnimationTargetCompat[] targetCompats) {
|
||||
//TODO: Implement the overview to app window animation for Go.
|
||||
AnimatorSet anim = new AnimatorSet();
|
||||
anim.play(ValueAnimator.ofInt(0, 1).setDuration(RECENTS_LAUNCH_DURATION));
|
||||
if (mRecentsView == null) {
|
||||
if (Log.isLoggable(TAG, Log.WARN)) {
|
||||
Log.w(TAG, "No recents view. Using stub animation.");
|
||||
}
|
||||
anim.play(ValueAnimator.ofInt(0, 1).setDuration(getRecentsLaunchDuration()));
|
||||
return anim;
|
||||
}
|
||||
|
||||
RemoteAnimationTargetCompat recentsTarget = null;
|
||||
RemoteAnimationTargetCompat closingAppTarget = null;
|
||||
|
||||
for (RemoteAnimationTargetCompat target : targetCompats) {
|
||||
if (target.mode == MODE_OPENING) {
|
||||
recentsTarget = target;
|
||||
} else if (target.mode == MODE_CLOSING && target.taskId == mTargetTaskId) {
|
||||
closingAppTarget = target;
|
||||
}
|
||||
}
|
||||
|
||||
if (closingAppTarget == null) {
|
||||
if (Log.isLoggable(TAG, Log.WARN)) {
|
||||
Log.w(TAG, "No closing app target. Using stub animation.");
|
||||
}
|
||||
anim.play(ValueAnimator.ofInt(0, 1).setDuration(getRecentsLaunchDuration()));
|
||||
return anim;
|
||||
}
|
||||
if (recentsTarget == null) {
|
||||
if (Log.isLoggable(TAG, Log.WARN)) {
|
||||
Log.w(TAG, "No recents target. Using stub animation.");
|
||||
}
|
||||
anim.play(ValueAnimator.ofInt(0, 1).setDuration(getRecentsLaunchDuration()));
|
||||
return anim;
|
||||
}
|
||||
|
||||
View thumbnailView = mRecentsView.getThumbnailViewForTask(mTargetTaskId);
|
||||
if (thumbnailView == null) {
|
||||
// TODO: We should either 1) guarantee the view is loaded before attempting this
|
||||
// or 2) have a backup animation.
|
||||
if (Log.isLoggable(TAG, Log.WARN)) {
|
||||
Log.w(TAG, "No thumbnail view for running task. Using stub animation.");
|
||||
}
|
||||
anim.play(ValueAnimator.ofInt(0, 1).setDuration(getRecentsLaunchDuration()));
|
||||
return anim;
|
||||
}
|
||||
|
||||
playAppScaleDownAnim(anim, closingAppTarget, recentsTarget, thumbnailView);
|
||||
|
||||
return anim;
|
||||
}
|
||||
|
||||
/**
|
||||
* Animate a closing app to scale down to the location of the thumbnail view in recents.
|
||||
*
|
||||
* @param anim animator set
|
||||
* @param appTarget the app surface thats closing
|
||||
* @param recentsTarget the surface containing recents
|
||||
* @param thumbnailView the thumbnail view to animate to
|
||||
*/
|
||||
private void playAppScaleDownAnim(@NonNull AnimatorSet anim,
|
||||
@NonNull RemoteAnimationTargetCompat appTarget,
|
||||
@NonNull RemoteAnimationTargetCompat recentsTarget, @NonNull View thumbnailView) {
|
||||
|
||||
// Identify where the entering remote app should animate to.
|
||||
Rect endRect = new Rect();
|
||||
thumbnailView.getGlobalVisibleRect(endRect);
|
||||
|
||||
Rect appBounds = appTarget.sourceContainerBounds;
|
||||
|
||||
ValueAnimator valueAnimator = ValueAnimator.ofInt(0, 1);
|
||||
valueAnimator.setDuration(APP_SCALE_DOWN_DURATION);
|
||||
|
||||
SyncRtSurfaceTransactionApplierCompat surfaceApplier =
|
||||
new SyncRtSurfaceTransactionApplierCompat(thumbnailView);
|
||||
|
||||
// Keep recents visible throughout the animation.
|
||||
SurfaceParams[] params = new SurfaceParams[2];
|
||||
params[0] = new SurfaceParams(recentsTarget.leash, 1f, null /* matrix */,
|
||||
null /* windowCrop */, getLayer(recentsTarget, MODE_OPENING), 0 /* cornerRadius */);
|
||||
|
||||
valueAnimator.addUpdateListener(new MultiValueUpdateListener() {
|
||||
private final FloatProp mScaleX;
|
||||
private final FloatProp mScaleY;
|
||||
private final FloatProp mTranslationX;
|
||||
private final FloatProp mTranslationY;
|
||||
private final FloatProp mAlpha;
|
||||
|
||||
{
|
||||
// Scale down and move to view location.
|
||||
float endScaleX = ((float) endRect.width()) / appBounds.width();
|
||||
mScaleX = new FloatProp(1f, endScaleX, 0, APP_SCALE_DOWN_DURATION,
|
||||
ACCEL_DEACCEL);
|
||||
float endScaleY = ((float) endRect.height()) / appBounds.height();
|
||||
mScaleY = new FloatProp(1f, endScaleY, 0, APP_SCALE_DOWN_DURATION,
|
||||
ACCEL_DEACCEL);
|
||||
float endTranslationX = endRect.left -
|
||||
(appBounds.width() - thumbnailView.getWidth()) / 2.0f;
|
||||
mTranslationX = new FloatProp(0, endTranslationX, 0, APP_SCALE_DOWN_DURATION,
|
||||
ACCEL_DEACCEL);
|
||||
float endTranslationY = endRect.top -
|
||||
(appBounds.height() - thumbnailView.getHeight()) / 2.0f;
|
||||
mTranslationY = new FloatProp(0, endTranslationY, 0, APP_SCALE_DOWN_DURATION,
|
||||
ACCEL_DEACCEL);
|
||||
|
||||
// Fade out quietly near the end to be replaced by the real view.
|
||||
mAlpha = new FloatProp(1.0f, 0,
|
||||
APP_SCALE_DOWN_DURATION - APP_TO_THUMBNAIL_FADE_DURATION,
|
||||
APP_TO_THUMBNAIL_FADE_DURATION, ACCEL_2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdate(float percent) {
|
||||
Matrix m = new Matrix();
|
||||
m.setScale(mScaleX.value, mScaleY.value,
|
||||
appBounds.width() / 2.0f, appBounds.height() / 2.0f);
|
||||
m.postTranslate(mTranslationX.value, mTranslationY.value);
|
||||
|
||||
params[1] = new SurfaceParams(appTarget.leash, mAlpha.value, m,
|
||||
null /* windowCrop */, getLayer(appTarget, MODE_CLOSING),
|
||||
0 /* cornerRadius */);
|
||||
surfaceApplier.scheduleApply(params);
|
||||
}
|
||||
});
|
||||
anim.play(valueAnimator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get duration of animation from app to overview.
|
||||
*
|
||||
* @return duration of animation
|
||||
*/
|
||||
long getRecentsLaunchDuration() {
|
||||
return RECENTS_LAUNCH_DURATION;
|
||||
return APP_SCALE_DOWN_DURATION;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ import static com.android.launcher3.LauncherState.OVERVIEW;
|
|||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
import com.android.launcher3.LauncherInitListener;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||
import com.android.quickstep.views.IconRecentsView;
|
||||
|
@ -38,10 +39,14 @@ public final class LauncherActivityControllerHelper extends GoActivityControlHel
|
|||
public AnimationFactory prepareRecentsUI(Launcher activity,
|
||||
boolean activityVisible, boolean animateActivity,
|
||||
Consumer<AnimatorPlaybackController> callback) {
|
||||
LauncherState fromState = activity.getStateManager().getState();
|
||||
//TODO: Implement this based off where the recents view needs to be for app => recents anim.
|
||||
return new AnimationFactory() {
|
||||
@Override
|
||||
public void createActivityController(long transitionLength) {}
|
||||
public void createActivityController(long transitionLength) {
|
||||
callback.accept(activity.getStateManager().createAnimationToNewWorkspace(
|
||||
fromState, OVERVIEW, transitionLength));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTransitionCancelled() {}
|
||||
|
|
|
@ -15,10 +15,12 @@
|
|||
*/
|
||||
package com.android.quickstep;
|
||||
|
||||
import android.util.ArrayMap;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.RecyclerView.Adapter;
|
||||
|
||||
import com.android.launcher3.R;
|
||||
|
@ -36,6 +38,7 @@ public final class TaskAdapter extends Adapter<TaskHolder> {
|
|||
private static final int MAX_TASKS_TO_DISPLAY = 6;
|
||||
private static final String TAG = "TaskAdapter";
|
||||
private final TaskListLoader mLoader;
|
||||
private final ArrayMap<Integer, TaskItemView> mTaskIdToViewMap = new ArrayMap<>();
|
||||
private TaskInputController mInputController;
|
||||
|
||||
public TaskAdapter(@NonNull TaskListLoader loader) {
|
||||
|
@ -46,6 +49,16 @@ public final class TaskAdapter extends Adapter<TaskHolder> {
|
|||
mInputController = inputController;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get task item view for a given task id if it's attached to the view.
|
||||
*
|
||||
* @param taskId task id to search for
|
||||
* @return corresponding task item view if it's attached, null otherwise
|
||||
*/
|
||||
public @Nullable TaskItemView getTaskItemView(int taskId) {
|
||||
return mTaskIdToViewMap.get(taskId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
TaskItemView itemView = (TaskItemView) LayoutInflater.from(parent.getContext())
|
||||
|
@ -63,6 +76,17 @@ public final class TaskAdapter extends Adapter<TaskHolder> {
|
|||
return;
|
||||
}
|
||||
holder.bindTask(tasks.get(position));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewAttachedToWindow(@NonNull TaskHolder holder) {
|
||||
mTaskIdToViewMap.put(holder.getTask().key.id, (TaskItemView) holder.itemView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewDetachedFromWindow(@NonNull TaskHolder holder) {
|
||||
mTaskIdToViewMap.remove(holder.getTask().key.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -27,6 +27,7 @@ import android.view.ViewDebug;
|
|||
import android.widget.FrameLayout;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
@ -155,6 +156,20 @@ public final class IconRecentsView extends FrameLayout {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the thumbnail view associated with a task for the purposes of animation.
|
||||
*
|
||||
* @param taskId task id of thumbnail view to get
|
||||
* @return the thumbnail view for the task if attached, null otherwise
|
||||
*/
|
||||
public @Nullable View getThumbnailViewForTask(int taskId) {
|
||||
TaskItemView view = mTaskAdapter.getTaskItemView(taskId);
|
||||
if (view == null) {
|
||||
return null;
|
||||
}
|
||||
return view.getThumbnailView();
|
||||
}
|
||||
|
||||
public void setTranslationYFactor(float translationFactor) {
|
||||
mTranslationYFactor = translationFactor;
|
||||
setTranslationY(computeTranslationYForFactor(mTranslationYFactor));
|
||||
|
|
|
@ -19,6 +19,7 @@ import android.content.Context;
|
|||
import android.graphics.Bitmap;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
@ -76,4 +77,8 @@ public final class TaskItemView extends LinearLayout {
|
|||
public void setThumbnail(Bitmap thumbnail) {
|
||||
mThumbnailView.setImageBitmap(thumbnail);
|
||||
}
|
||||
|
||||
public View getThumbnailView() {
|
||||
return mThumbnailView;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue