Merge "Optimize hot launching recents" into oc-dev
This commit is contained in:
@@ -38,6 +38,7 @@ import android.transition.TransitionManager;
|
|||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
import android.view.AppTransitionAnimationSpec;
|
import android.view.AppTransitionAnimationSpec;
|
||||||
|
import android.view.IAppTransitionAnimationSpecsFuture;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.Window;
|
import android.view.Window;
|
||||||
@@ -213,6 +214,7 @@ public class ActivityOptions {
|
|||||||
|
|
||||||
private static final String KEY_INSTANT_APP_VERIFICATION_BUNDLE
|
private static final String KEY_INSTANT_APP_VERIFICATION_BUNDLE
|
||||||
= "android:instantapps.installerbundle";
|
= "android:instantapps.installerbundle";
|
||||||
|
private static final String KEY_SPECS_FUTURE = "android:activity.specsFuture";
|
||||||
|
|
||||||
/** @hide */
|
/** @hide */
|
||||||
public static final int ANIM_NONE = 0;
|
public static final int ANIM_NONE = 0;
|
||||||
@@ -268,6 +270,7 @@ public class ActivityOptions {
|
|||||||
private AppTransitionAnimationSpec mAnimSpecs[];
|
private AppTransitionAnimationSpec mAnimSpecs[];
|
||||||
private int mRotationAnimationHint = -1;
|
private int mRotationAnimationHint = -1;
|
||||||
private Bundle mAppVerificationBundle;
|
private Bundle mAppVerificationBundle;
|
||||||
|
private IAppTransitionAnimationSpecsFuture mSpecsFuture;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an ActivityOptions specifying a custom animation to run when
|
* Create an ActivityOptions specifying a custom animation to run when
|
||||||
@@ -492,35 +495,12 @@ public class ActivityOptions {
|
|||||||
* is not executed, the callback will happen immediately.
|
* is not executed, the callback will happen immediately.
|
||||||
* @return Returns a new ActivityOptions object that you can use to
|
* @return Returns a new ActivityOptions object that you can use to
|
||||||
* supply these options as the options Bundle when starting an activity.
|
* supply these options as the options Bundle when starting an activity.
|
||||||
* @hide
|
|
||||||
*/
|
*/
|
||||||
public static ActivityOptions makeThumbnailScaleUpAnimation(View source,
|
private static ActivityOptions makeThumbnailScaleUpAnimation(View source,
|
||||||
Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener) {
|
Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener) {
|
||||||
return makeThumbnailAnimation(source, thumbnail, startX, startY, listener, true);
|
return makeThumbnailAnimation(source, thumbnail, startX, startY, listener, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an ActivityOptions specifying an animation where an activity window
|
|
||||||
* is scaled from a given position to a thumbnail at a specified location.
|
|
||||||
*
|
|
||||||
* @param source The View that this thumbnail is animating to. This
|
|
||||||
* defines the coordinate space for <var>startX</var> and <var>startY</var>.
|
|
||||||
* @param thumbnail The bitmap that will be shown as the final thumbnail
|
|
||||||
* of the animation.
|
|
||||||
* @param startX The x end location of the bitmap, relative to <var>source</var>.
|
|
||||||
* @param startY The y end location of the bitmap, relative to <var>source</var>.
|
|
||||||
* @param listener Optional OnAnimationStartedListener to find out when the
|
|
||||||
* requested animation has started running. If for some reason the animation
|
|
||||||
* is not executed, the callback will happen immediately.
|
|
||||||
* @return Returns a new ActivityOptions object that you can use to
|
|
||||||
* supply these options as the options Bundle when starting an activity.
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
public static ActivityOptions makeThumbnailScaleDownAnimation(View source,
|
|
||||||
Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener) {
|
|
||||||
return makeThumbnailAnimation(source, thumbnail, startX, startY, listener, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ActivityOptions makeThumbnailAnimation(View source,
|
private static ActivityOptions makeThumbnailAnimation(View source,
|
||||||
Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener,
|
Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener,
|
||||||
boolean scaleUp) {
|
boolean scaleUp) {
|
||||||
@@ -537,29 +517,21 @@ public class ActivityOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an ActivityOptions specifying an animation where the new activity
|
* Create an ActivityOptions specifying an animation where a list of activity windows and
|
||||||
* window and a thumbnail is aspect-scaled to a new location.
|
* thumbnails are aspect scaled to/from a new location.
|
||||||
*
|
|
||||||
* @param source The View that this thumbnail is animating from. This
|
|
||||||
* defines the coordinate space for <var>startX</var> and <var>startY</var>.
|
|
||||||
* @param thumbnail The bitmap that will be shown as the initial thumbnail
|
|
||||||
* of the animation.
|
|
||||||
* @param startX The x starting location of the bitmap, relative to <var>source</var>.
|
|
||||||
* @param startY The y starting location of the bitmap, relative to <var>source</var>.
|
|
||||||
* @param handler If <var>listener</var> is non-null this must be a valid
|
|
||||||
* Handler on which to dispatch the callback; otherwise it should be null.
|
|
||||||
* @param listener Optional OnAnimationStartedListener to find out when the
|
|
||||||
* requested animation has started running. If for some reason the animation
|
|
||||||
* is not executed, the callback will happen immediately.
|
|
||||||
* @return Returns a new ActivityOptions object that you can use to
|
|
||||||
* supply these options as the options Bundle when starting an activity.
|
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
public static ActivityOptions makeThumbnailAspectScaleUpAnimation(View source,
|
public static ActivityOptions makeMultiThumbFutureAspectScaleAnimation(Context context,
|
||||||
Bitmap thumbnail, int startX, int startY, int targetWidth, int targetHeight,
|
Handler handler, IAppTransitionAnimationSpecsFuture specsFuture,
|
||||||
Handler handler, OnAnimationStartedListener listener) {
|
OnAnimationStartedListener listener, boolean scaleUp) {
|
||||||
return makeAspectScaledThumbnailAnimation(source, thumbnail, startX, startY,
|
ActivityOptions opts = new ActivityOptions();
|
||||||
targetWidth, targetHeight, handler, listener, true);
|
opts.mPackageName = context.getPackageName();
|
||||||
|
opts.mAnimationType = scaleUp
|
||||||
|
? ANIM_THUMBNAIL_ASPECT_SCALE_UP
|
||||||
|
: ANIM_THUMBNAIL_ASPECT_SCALE_DOWN;
|
||||||
|
opts.mSpecsFuture = specsFuture;
|
||||||
|
opts.setOnAnimationStartedListener(handler, listener);
|
||||||
|
return opts;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -891,6 +863,10 @@ public class ActivityOptions {
|
|||||||
}
|
}
|
||||||
mRotationAnimationHint = opts.getInt(KEY_ROTATION_ANIMATION_HINT);
|
mRotationAnimationHint = opts.getInt(KEY_ROTATION_ANIMATION_HINT);
|
||||||
mAppVerificationBundle = opts.getBundle(KEY_INSTANT_APP_VERIFICATION_BUNDLE);
|
mAppVerificationBundle = opts.getBundle(KEY_INSTANT_APP_VERIFICATION_BUNDLE);
|
||||||
|
if (opts.containsKey(KEY_SPECS_FUTURE)) {
|
||||||
|
mSpecsFuture = IAppTransitionAnimationSpecsFuture.Stub.asInterface(opts.getBinder(
|
||||||
|
KEY_SPECS_FUTURE));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1028,6 +1004,11 @@ public class ActivityOptions {
|
|||||||
/** @hide */
|
/** @hide */
|
||||||
public AppTransitionAnimationSpec[] getAnimSpecs() { return mAnimSpecs; }
|
public AppTransitionAnimationSpec[] getAnimSpecs() { return mAnimSpecs; }
|
||||||
|
|
||||||
|
/** @hide */
|
||||||
|
public IAppTransitionAnimationSpecsFuture getSpecsFuture() {
|
||||||
|
return mSpecsFuture;
|
||||||
|
}
|
||||||
|
|
||||||
/** @hide */
|
/** @hide */
|
||||||
public static ActivityOptions fromBundle(Bundle bOptions) {
|
public static ActivityOptions fromBundle(Bundle bOptions) {
|
||||||
return bOptions != null ? new ActivityOptions(bOptions) : null;
|
return bOptions != null ? new ActivityOptions(bOptions) : null;
|
||||||
@@ -1205,6 +1186,7 @@ public class ActivityOptions {
|
|||||||
}
|
}
|
||||||
mAnimSpecs = otherOptions.mAnimSpecs;
|
mAnimSpecs = otherOptions.mAnimSpecs;
|
||||||
mAnimationFinishedListener = otherOptions.mAnimationFinishedListener;
|
mAnimationFinishedListener = otherOptions.mAnimationFinishedListener;
|
||||||
|
mSpecsFuture = otherOptions.mSpecsFuture;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1279,6 +1261,9 @@ public class ActivityOptions {
|
|||||||
if (mAnimationFinishedListener != null) {
|
if (mAnimationFinishedListener != null) {
|
||||||
b.putBinder(KEY_ANIMATION_FINISHED_LISTENER, mAnimationFinishedListener.asBinder());
|
b.putBinder(KEY_ANIMATION_FINISHED_LISTENER, mAnimationFinishedListener.asBinder());
|
||||||
}
|
}
|
||||||
|
if (mSpecsFuture != null) {
|
||||||
|
b.putBinder(KEY_SPECS_FUTURE, mSpecsFuture.asBinder());
|
||||||
|
}
|
||||||
b.putInt(KEY_ROTATION_ANIMATION_HINT, mRotationAnimationHint);
|
b.putInt(KEY_ROTATION_ANIMATION_HINT, mRotationAnimationHint);
|
||||||
if (mAppVerificationBundle != null) {
|
if (mAppVerificationBundle != null) {
|
||||||
b.putBundle(KEY_INSTANT_APP_VERIFICATION_BUNDLE, mAppVerificationBundle);
|
b.putBundle(KEY_INSTANT_APP_VERIFICATION_BUNDLE, mAppVerificationBundle);
|
||||||
|
|||||||
@@ -477,7 +477,8 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
|
|||||||
|
|
||||||
// Launch the task
|
// Launch the task
|
||||||
ssp.startActivityFromRecents(
|
ssp.startActivityFromRecents(
|
||||||
mContext, toTask.key, toTask.title, launchOpts, INVALID_STACK_ID);
|
mContext, toTask.key, toTask.title, launchOpts, INVALID_STACK_ID,
|
||||||
|
null /* resultListener */);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -550,7 +551,8 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
|
|||||||
|
|
||||||
// Launch the task
|
// Launch the task
|
||||||
ssp.startActivityFromRecents(
|
ssp.startActivityFromRecents(
|
||||||
mContext, toTask.key, toTask.title, launchOpts, INVALID_STACK_ID);
|
mContext, toTask.key, toTask.title, launchOpts, INVALID_STACK_ID,
|
||||||
|
null /* resultListener */);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void showNextAffiliatedTask() {
|
public void showNextAffiliatedTask() {
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import static android.app.ActivityManager.StackId.RECENTS_STACK_ID;
|
|||||||
import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
|
import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
|
||||||
|
|
||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
|
import android.annotation.Nullable;
|
||||||
import android.app.ActivityManager;
|
import android.app.ActivityManager;
|
||||||
import android.app.ActivityManager.StackInfo;
|
import android.app.ActivityManager.StackInfo;
|
||||||
import android.app.ActivityManager.TaskSnapshot;
|
import android.app.ActivityManager.TaskSnapshot;
|
||||||
@@ -70,6 +71,7 @@ import android.util.ArraySet;
|
|||||||
import android.util.IconDrawableFactory;
|
import android.util.IconDrawableFactory;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.MutableBoolean;
|
import android.util.MutableBoolean;
|
||||||
|
import android.view.AppTransitionAnimationSpec;
|
||||||
import android.view.Display;
|
import android.view.Display;
|
||||||
import android.view.IAppTransitionAnimationSpecsFuture;
|
import android.view.IAppTransitionAnimationSpecsFuture;
|
||||||
import android.view.IDockedStackListener;
|
import android.view.IDockedStackListener;
|
||||||
@@ -89,6 +91,7 @@ import com.android.systemui.recents.RecentsDebugFlags;
|
|||||||
import com.android.systemui.recents.RecentsImpl;
|
import com.android.systemui.recents.RecentsImpl;
|
||||||
import com.android.systemui.recents.model.Task;
|
import com.android.systemui.recents.model.Task;
|
||||||
import com.android.systemui.recents.model.ThumbnailData;
|
import com.android.systemui.recents.model.ThumbnailData;
|
||||||
|
import com.android.systemui.recents.views.RecentsTransitionHelper.AnimationSpecComposer;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -1116,31 +1119,44 @@ public class SystemServicesProxy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Starts an activity from recents. */
|
/** Starts an activity from recents. */
|
||||||
public boolean startActivityFromRecents(Context context, Task.TaskKey taskKey, String taskName,
|
public void startActivityFromRecents(Context context, Task.TaskKey taskKey, String taskName,
|
||||||
ActivityOptions options, int stackId) {
|
ActivityOptions options, int stackId,
|
||||||
if (mIam != null) {
|
@Nullable final StartActivityFromRecentsResultListener resultListener) {
|
||||||
try {
|
if (mIam == null) {
|
||||||
if (taskKey.stackId == DOCKED_STACK_ID) {
|
return;
|
||||||
// We show non-visible docked tasks in Recents, but we always want to launch
|
|
||||||
// them in the fullscreen stack.
|
|
||||||
if (options == null) {
|
|
||||||
options = ActivityOptions.makeBasic();
|
|
||||||
}
|
|
||||||
options.setLaunchStackId(FULLSCREEN_WORKSPACE_STACK_ID);
|
|
||||||
} else if (stackId != INVALID_STACK_ID){
|
|
||||||
if (options == null) {
|
|
||||||
options = ActivityOptions.makeBasic();
|
|
||||||
}
|
|
||||||
options.setLaunchStackId(stackId);
|
|
||||||
}
|
|
||||||
mIam.startActivityFromRecents(
|
|
||||||
taskKey.id, options == null ? null : options.toBundle());
|
|
||||||
return true;
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.e(TAG, context.getString(R.string.recents_launch_error_message, taskName), e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
if (taskKey.stackId == DOCKED_STACK_ID) {
|
||||||
|
// We show non-visible docked tasks in Recents, but we always want to launch
|
||||||
|
// them in the fullscreen stack.
|
||||||
|
if (options == null) {
|
||||||
|
options = ActivityOptions.makeBasic();
|
||||||
|
}
|
||||||
|
options.setLaunchStackId(FULLSCREEN_WORKSPACE_STACK_ID);
|
||||||
|
} else if (stackId != INVALID_STACK_ID) {
|
||||||
|
if (options == null) {
|
||||||
|
options = ActivityOptions.makeBasic();
|
||||||
|
}
|
||||||
|
options.setLaunchStackId(stackId);
|
||||||
|
}
|
||||||
|
final ActivityOptions finalOptions = options;
|
||||||
|
|
||||||
|
// Execute this from another thread such that we can do other things (like caching the
|
||||||
|
// bitmap for the thumbnail) while AM is busy starting our activity.
|
||||||
|
mOnewayExecutor.submit(() -> {
|
||||||
|
try {
|
||||||
|
mIam.startActivityFromRecents(
|
||||||
|
taskKey.id, finalOptions == null ? null : finalOptions.toBundle());
|
||||||
|
if (resultListener != null) {
|
||||||
|
mHandler.post(() -> resultListener.onStartActivityResult(true));
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, context.getString(
|
||||||
|
R.string.recents_launch_error_message, taskName), e);
|
||||||
|
if (resultListener != null) {
|
||||||
|
mHandler.post(() -> resultListener.onStartActivityResult(false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Starts an in-place animation on the front most application windows. */
|
/** Starts an in-place animation on the front most application windows. */
|
||||||
@@ -1258,6 +1274,10 @@ public class SystemServicesProxy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public interface StartActivityFromRecentsResultListener {
|
||||||
|
void onStartActivityResult(boolean succeeded);
|
||||||
|
}
|
||||||
|
|
||||||
private final class H extends Handler {
|
private final class H extends Handler {
|
||||||
private static final int ON_TASK_STACK_CHANGED = 1;
|
private static final int ON_TASK_STACK_CHANGED = 1;
|
||||||
private static final int ON_TASK_SNAPSHOT_CHANGED = 2;
|
private static final int ON_TASK_SNAPSHOT_CHANGED = 2;
|
||||||
|
|||||||
@@ -101,57 +101,49 @@ public class RecentsTransitionHelper {
|
|||||||
*/
|
*/
|
||||||
public void launchTaskFromRecents(final TaskStack stack, @Nullable final Task task,
|
public void launchTaskFromRecents(final TaskStack stack, @Nullable final Task task,
|
||||||
final TaskStackView stackView, final TaskView taskView,
|
final TaskStackView stackView, final TaskView taskView,
|
||||||
final boolean screenPinningRequested, final Rect bounds, final int destinationStack) {
|
final boolean screenPinningRequested, final int destinationStack) {
|
||||||
final ActivityOptions opts = ActivityOptions.makeBasic();
|
|
||||||
if (bounds != null) {
|
|
||||||
opts.setLaunchBounds(bounds.isEmpty() ? null : bounds);
|
|
||||||
}
|
|
||||||
|
|
||||||
final ActivityOptions.OnAnimationStartedListener animStartedListener;
|
final ActivityOptions.OnAnimationStartedListener animStartedListener;
|
||||||
final IAppTransitionAnimationSpecsFuture transitionFuture;
|
final AppTransitionAnimationSpecsFuture transitionFuture;
|
||||||
if (taskView != null) {
|
if (taskView != null) {
|
||||||
transitionFuture = getAppTransitionFuture(new AnimationSpecComposer() {
|
|
||||||
@Override
|
|
||||||
public List<AppTransitionAnimationSpec> composeSpecs() {
|
|
||||||
return composeAnimationSpecs(task, stackView, destinationStack);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
animStartedListener = new ActivityOptions.OnAnimationStartedListener() {
|
|
||||||
@Override
|
|
||||||
public void onAnimationStarted() {
|
|
||||||
// If we are launching into another task, cancel the previous task's
|
|
||||||
// window transition
|
|
||||||
EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(task));
|
|
||||||
EventBus.getDefault().send(new ExitRecentsWindowFirstAnimationFrameEvent());
|
|
||||||
stackView.cancelAllTaskViewAnimations();
|
|
||||||
|
|
||||||
if (screenPinningRequested) {
|
// Fetch window rect here already in order not to be blocked on lock contention in WM
|
||||||
// Request screen pinning after the animation runs
|
// when the future calls it.
|
||||||
mStartScreenPinningRunnable.taskId = task.key.id;
|
final Rect windowRect = Recents.getSystemServices().getWindowRect();
|
||||||
mHandler.postDelayed(mStartScreenPinningRunnable, 350);
|
transitionFuture = getAppTransitionFuture(
|
||||||
}
|
() -> composeAnimationSpecs(task, stackView, destinationStack, windowRect));
|
||||||
|
animStartedListener = () -> {
|
||||||
|
// If we are launching into another task, cancel the previous task's
|
||||||
|
// window transition
|
||||||
|
EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(task));
|
||||||
|
EventBus.getDefault().send(new ExitRecentsWindowFirstAnimationFrameEvent());
|
||||||
|
stackView.cancelAllTaskViewAnimations();
|
||||||
|
|
||||||
|
if (screenPinningRequested) {
|
||||||
|
// Request screen pinning after the animation runs
|
||||||
|
mStartScreenPinningRunnable.taskId = task.key.id;
|
||||||
|
mHandler.postDelayed(mStartScreenPinningRunnable, 350);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
// This is only the case if the task is not on screen (scrolled offscreen for example)
|
// This is only the case if the task is not on screen (scrolled offscreen for example)
|
||||||
transitionFuture = null;
|
transitionFuture = null;
|
||||||
animStartedListener = new ActivityOptions.OnAnimationStartedListener() {
|
animStartedListener = () -> {
|
||||||
@Override
|
// If we are launching into another task, cancel the previous task's
|
||||||
public void onAnimationStarted() {
|
// window transition
|
||||||
// If we are launching into another task, cancel the previous task's
|
EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(task));
|
||||||
// window transition
|
EventBus.getDefault().send(new ExitRecentsWindowFirstAnimationFrameEvent());
|
||||||
EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(task));
|
stackView.cancelAllTaskViewAnimations();
|
||||||
EventBus.getDefault().send(new ExitRecentsWindowFirstAnimationFrameEvent());
|
|
||||||
stackView.cancelAllTaskViewAnimations();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final ActivityOptions opts = ActivityOptions.makeMultiThumbFutureAspectScaleAnimation(mContext,
|
||||||
|
mHandler, transitionFuture != null ? transitionFuture.future : null,
|
||||||
|
animStartedListener, true /* scaleUp */);
|
||||||
if (taskView == null) {
|
if (taskView == null) {
|
||||||
// If there is no task view, then we do not need to worry about animating out occluding
|
// If there is no task view, then we do not need to worry about animating out occluding
|
||||||
// task views, and we can launch immediately
|
// task views, and we can launch immediately
|
||||||
startTaskActivity(stack, task, taskView, opts, transitionFuture, animStartedListener,
|
startTaskActivity(stack, task, taskView, opts, transitionFuture, destinationStack);
|
||||||
destinationStack);
|
|
||||||
} else {
|
} else {
|
||||||
LaunchTaskStartedEvent launchStartedEvent = new LaunchTaskStartedEvent(taskView,
|
LaunchTaskStartedEvent launchStartedEvent = new LaunchTaskStartedEvent(taskView,
|
||||||
screenPinningRequested);
|
screenPinningRequested);
|
||||||
@@ -160,14 +152,13 @@ public class RecentsTransitionHelper {
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
startTaskActivity(stack, task, taskView, opts, transitionFuture,
|
startTaskActivity(stack, task, taskView, opts, transitionFuture,
|
||||||
animStartedListener, destinationStack);
|
destinationStack);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
EventBus.getDefault().send(launchStartedEvent);
|
EventBus.getDefault().send(launchStartedEvent);
|
||||||
} else {
|
} else {
|
||||||
EventBus.getDefault().send(launchStartedEvent);
|
EventBus.getDefault().send(launchStartedEvent);
|
||||||
startTaskActivity(stack, task, taskView, opts, transitionFuture,
|
startTaskActivity(stack, task, taskView, opts, transitionFuture, destinationStack);
|
||||||
animStartedListener, destinationStack);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Recents.getSystemServices().sendCloseSystemWindows(
|
Recents.getSystemServices().sendCloseSystemWindows(
|
||||||
@@ -199,30 +190,31 @@ public class RecentsTransitionHelper {
|
|||||||
* @param destinationStack id of the stack to put the task into.
|
* @param destinationStack id of the stack to put the task into.
|
||||||
*/
|
*/
|
||||||
private void startTaskActivity(TaskStack stack, Task task, @Nullable TaskView taskView,
|
private void startTaskActivity(TaskStack stack, Task task, @Nullable TaskView taskView,
|
||||||
ActivityOptions opts, IAppTransitionAnimationSpecsFuture transitionFuture,
|
ActivityOptions opts, AppTransitionAnimationSpecsFuture transitionFuture,
|
||||||
final OnAnimationStartedListener animStartedListener, int destinationStack) {
|
int destinationStack) {
|
||||||
SystemServicesProxy ssp = Recents.getSystemServices();
|
SystemServicesProxy ssp = Recents.getSystemServices();
|
||||||
if (ssp.startActivityFromRecents(mContext, task.key, task.title, opts, destinationStack)) {
|
ssp.startActivityFromRecents(mContext, task.key, task.title, opts, destinationStack,
|
||||||
// Keep track of the index of the task launch
|
succeeded -> {
|
||||||
int taskIndexFromFront = 0;
|
if (succeeded) {
|
||||||
int taskIndex = stack.indexOfStackTask(task);
|
// Keep track of the index of the task launch
|
||||||
if (taskIndex > -1) {
|
int taskIndexFromFront = 0;
|
||||||
taskIndexFromFront = stack.getTaskCount() - taskIndex - 1;
|
int taskIndex = stack.indexOfStackTask(task);
|
||||||
}
|
if (taskIndex > -1) {
|
||||||
EventBus.getDefault().send(new LaunchTaskSucceededEvent(taskIndexFromFront));
|
taskIndexFromFront = stack.getTaskCount() - taskIndex - 1;
|
||||||
} else {
|
}
|
||||||
// Dismiss the task if we fail to launch it
|
EventBus.getDefault().send(new LaunchTaskSucceededEvent(taskIndexFromFront));
|
||||||
if (taskView != null) {
|
} else {
|
||||||
taskView.dismissTask();
|
// Dismiss the task if we fail to launch it
|
||||||
}
|
if (taskView != null) {
|
||||||
|
taskView.dismissTask();
|
||||||
// Keep track of failed launches
|
}
|
||||||
EventBus.getDefault().send(new LaunchTaskFailedEvent());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Keep track of failed launches
|
||||||
|
EventBus.getDefault().send(new LaunchTaskFailedEvent());
|
||||||
|
}
|
||||||
|
});
|
||||||
if (transitionFuture != null) {
|
if (transitionFuture != null) {
|
||||||
ssp.overridePendingAppTransitionMultiThumbFuture(transitionFuture,
|
mHandler.post(transitionFuture::precacheSpecs);
|
||||||
wrapStartedListener(animStartedListener), true /* scaleUp */);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,21 +223,18 @@ public class RecentsTransitionHelper {
|
|||||||
*
|
*
|
||||||
* @param composer The implementation that composes the specs on the UI thread.
|
* @param composer The implementation that composes the specs on the UI thread.
|
||||||
*/
|
*/
|
||||||
public IAppTransitionAnimationSpecsFuture getAppTransitionFuture(
|
public AppTransitionAnimationSpecsFuture getAppTransitionFuture(
|
||||||
final AnimationSpecComposer composer) {
|
final AnimationSpecComposer composer) {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
mAppTransitionAnimationSpecs = SPECS_WAITING;
|
mAppTransitionAnimationSpecs = SPECS_WAITING;
|
||||||
}
|
}
|
||||||
return new IAppTransitionAnimationSpecsFuture.Stub() {
|
IAppTransitionAnimationSpecsFuture future = new IAppTransitionAnimationSpecsFuture.Stub() {
|
||||||
@Override
|
@Override
|
||||||
public AppTransitionAnimationSpec[] get() throws RemoteException {
|
public AppTransitionAnimationSpec[] get() throws RemoteException {
|
||||||
mHandler.post(new Runnable() {
|
mHandler.post(() -> {
|
||||||
@Override
|
synchronized (RecentsTransitionHelper.this) {
|
||||||
public void run() {
|
mAppTransitionAnimationSpecs = composer.composeSpecs();
|
||||||
synchronized (RecentsTransitionHelper.this) {
|
RecentsTransitionHelper.this.notifyAll();
|
||||||
mAppTransitionAnimationSpecs = composer.composeSpecs();
|
|
||||||
RecentsTransitionHelper.this.notifyAll();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
synchronized (RecentsTransitionHelper.this) {
|
synchronized (RecentsTransitionHelper.this) {
|
||||||
@@ -265,6 +254,7 @@ public class RecentsTransitionHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
return new AppTransitionAnimationSpecsFuture(composer, future);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -283,7 +273,7 @@ public class RecentsTransitionHelper {
|
|||||||
* Composes the animation specs for all the tasks in the target stack.
|
* Composes the animation specs for all the tasks in the target stack.
|
||||||
*/
|
*/
|
||||||
private List<AppTransitionAnimationSpec> composeAnimationSpecs(final Task task,
|
private List<AppTransitionAnimationSpec> composeAnimationSpecs(final Task task,
|
||||||
final TaskStackView stackView, final int destinationStack) {
|
final TaskStackView stackView, final int destinationStack, Rect windowRect) {
|
||||||
// Ensure we have a valid target stack id
|
// Ensure we have a valid target stack id
|
||||||
final int targetStackId = destinationStack != INVALID_STACK_ID ?
|
final int targetStackId = destinationStack != INVALID_STACK_ID ?
|
||||||
destinationStack : task.key.stackId;
|
destinationStack : task.key.stackId;
|
||||||
@@ -309,8 +299,7 @@ public class RecentsTransitionHelper {
|
|||||||
specs.add(composeOffscreenAnimationSpec(task, offscreenTaskRect));
|
specs.add(composeOffscreenAnimationSpec(task, offscreenTaskRect));
|
||||||
} else {
|
} else {
|
||||||
mTmpTransform.fillIn(taskView);
|
mTmpTransform.fillIn(taskView);
|
||||||
stackLayout.transformToScreenCoordinates(mTmpTransform,
|
stackLayout.transformToScreenCoordinates(mTmpTransform, windowRect);
|
||||||
null /* windowOverrideRect */);
|
|
||||||
AppTransitionAnimationSpec spec = composeAnimationSpec(stackView, taskView,
|
AppTransitionAnimationSpec spec = composeAnimationSpec(stackView, taskView,
|
||||||
mTmpTransform, true /* addHeaderBitmap */);
|
mTmpTransform, true /* addHeaderBitmap */);
|
||||||
if (spec != null) {
|
if (spec != null) {
|
||||||
@@ -430,4 +419,34 @@ public class RecentsTransitionHelper {
|
|||||||
public interface AnimationSpecComposer {
|
public interface AnimationSpecComposer {
|
||||||
List<AppTransitionAnimationSpec> composeSpecs();
|
List<AppTransitionAnimationSpec> composeSpecs();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class to be returned from {@link #composeAnimationSpec} that gives access to both the future
|
||||||
|
* and the anonymous class used for composing.
|
||||||
|
*/
|
||||||
|
public class AppTransitionAnimationSpecsFuture {
|
||||||
|
|
||||||
|
private final AnimationSpecComposer composer;
|
||||||
|
private final IAppTransitionAnimationSpecsFuture future;
|
||||||
|
|
||||||
|
private AppTransitionAnimationSpecsFuture(AnimationSpecComposer composer,
|
||||||
|
IAppTransitionAnimationSpecsFuture future) {
|
||||||
|
this.composer = composer;
|
||||||
|
this.future = future;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IAppTransitionAnimationSpecsFuture getFuture() {
|
||||||
|
return future;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manually generates and caches the spec such that they are already available when the
|
||||||
|
* future needs.
|
||||||
|
*/
|
||||||
|
public void precacheSpecs() {
|
||||||
|
synchronized (RecentsTransitionHelper.this) {
|
||||||
|
mAppTransitionAnimationSpecs = composer.composeSpecs();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,19 +24,16 @@ import android.app.ActivityOptions.OnAnimationStartedListener;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.graphics.Outline;
|
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.graphics.drawable.ColorDrawable;
|
import android.graphics.drawable.ColorDrawable;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.util.ArraySet;
|
import android.util.ArraySet;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.AppTransitionAnimationSpec;
|
import android.view.AppTransitionAnimationSpec;
|
||||||
import android.view.IAppTransitionAnimationSpecsFuture;
|
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewDebug;
|
import android.view.ViewDebug;
|
||||||
import android.view.ViewOutlineProvider;
|
|
||||||
import android.view.ViewPropertyAnimator;
|
import android.view.ViewPropertyAnimator;
|
||||||
import android.view.WindowInsets;
|
import android.view.WindowInsets;
|
||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
@@ -73,10 +70,10 @@ import com.android.systemui.recents.misc.Utilities;
|
|||||||
import com.android.systemui.recents.model.Task;
|
import com.android.systemui.recents.model.Task;
|
||||||
import com.android.systemui.recents.model.TaskStack;
|
import com.android.systemui.recents.model.TaskStack;
|
||||||
import com.android.systemui.recents.views.RecentsTransitionHelper.AnimationSpecComposer;
|
import com.android.systemui.recents.views.RecentsTransitionHelper.AnimationSpecComposer;
|
||||||
|
import com.android.systemui.recents.views.RecentsTransitionHelper.AppTransitionAnimationSpecsFuture;
|
||||||
import com.android.systemui.stackdivider.WindowManagerProxy;
|
import com.android.systemui.stackdivider.WindowManagerProxy;
|
||||||
import com.android.systemui.statusbar.FlingAnimationUtils;
|
import com.android.systemui.statusbar.FlingAnimationUtils;
|
||||||
|
|
||||||
import java.io.FileDescriptor;
|
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -440,8 +437,7 @@ public class RecentsView extends FrameLayout {
|
|||||||
public final void onBusEvent(LaunchTaskEvent event) {
|
public final void onBusEvent(LaunchTaskEvent event) {
|
||||||
mLastTaskLaunchedWasFreeform = event.task.isFreeformTask();
|
mLastTaskLaunchedWasFreeform = event.task.isFreeformTask();
|
||||||
mTransitionHelper.launchTaskFromRecents(getStack(), event.task, mTaskStackView,
|
mTransitionHelper.launchTaskFromRecents(getStack(), event.task, mTaskStackView,
|
||||||
event.taskView, event.screenPinningRequested, event.targetTaskBounds,
|
event.taskView, event.screenPinningRequested, event.targetTaskStack);
|
||||||
event.targetTaskStack);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void onBusEvent(DismissRecentsToHomeAnimationStarted event) {
|
public final void onBusEvent(DismissRecentsToHomeAnimationStarted event) {
|
||||||
@@ -523,7 +519,7 @@ public class RecentsView extends FrameLayout {
|
|||||||
};
|
};
|
||||||
|
|
||||||
final Rect taskRect = getTaskRect(event.taskView);
|
final Rect taskRect = getTaskRect(event.taskView);
|
||||||
IAppTransitionAnimationSpecsFuture future =
|
AppTransitionAnimationSpecsFuture future =
|
||||||
mTransitionHelper.getAppTransitionFuture(
|
mTransitionHelper.getAppTransitionFuture(
|
||||||
new AnimationSpecComposer() {
|
new AnimationSpecComposer() {
|
||||||
@Override
|
@Override
|
||||||
@@ -532,7 +528,7 @@ public class RecentsView extends FrameLayout {
|
|||||||
event.taskView, taskRect);
|
event.taskView, taskRect);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
ssp.overridePendingAppTransitionMultiThumbFuture(future,
|
ssp.overridePendingAppTransitionMultiThumbFuture(future.getFuture(),
|
||||||
mTransitionHelper.wrapStartedListener(startedListener),
|
mTransitionHelper.wrapStartedListener(startedListener),
|
||||||
true /* scaleUp */);
|
true /* scaleUp */);
|
||||||
|
|
||||||
|
|||||||
@@ -149,6 +149,7 @@ import android.util.MergedConfiguration;
|
|||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
import android.util.TimeUtils;
|
import android.util.TimeUtils;
|
||||||
import android.view.AppTransitionAnimationSpec;
|
import android.view.AppTransitionAnimationSpec;
|
||||||
|
import android.view.IAppTransitionAnimationSpecsFuture;
|
||||||
import android.view.IApplicationToken;
|
import android.view.IApplicationToken;
|
||||||
import android.view.WindowManager.LayoutParams;
|
import android.view.WindowManager.LayoutParams;
|
||||||
|
|
||||||
@@ -1437,7 +1438,13 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
|
|||||||
case ANIM_THUMBNAIL_ASPECT_SCALE_UP:
|
case ANIM_THUMBNAIL_ASPECT_SCALE_UP:
|
||||||
case ANIM_THUMBNAIL_ASPECT_SCALE_DOWN:
|
case ANIM_THUMBNAIL_ASPECT_SCALE_DOWN:
|
||||||
final AppTransitionAnimationSpec[] specs = pendingOptions.getAnimSpecs();
|
final AppTransitionAnimationSpec[] specs = pendingOptions.getAnimSpecs();
|
||||||
if (animationType == ANIM_THUMBNAIL_ASPECT_SCALE_DOWN
|
final IAppTransitionAnimationSpecsFuture specsFuture =
|
||||||
|
pendingOptions.getSpecsFuture();
|
||||||
|
if (specsFuture != null) {
|
||||||
|
service.mWindowManager.overridePendingAppTransitionMultiThumbFuture(
|
||||||
|
specsFuture, pendingOptions.getOnAnimationStartListener(),
|
||||||
|
animationType == ANIM_THUMBNAIL_ASPECT_SCALE_UP);
|
||||||
|
} else if (animationType == ANIM_THUMBNAIL_ASPECT_SCALE_DOWN
|
||||||
&& specs != null) {
|
&& specs != null) {
|
||||||
service.mWindowManager.overridePendingAppTransitionMultiThumb(
|
service.mWindowManager.overridePendingAppTransitionMultiThumb(
|
||||||
specs, pendingOptions.getOnAnimationStartListener(),
|
specs, pendingOptions.getOnAnimationStartListener(),
|
||||||
|
|||||||
Reference in New Issue
Block a user