Fix black flash when splitting task
- Draw the thumbnail view and align with the thumbnail bounds instead of the whole task bounds with the icon - Defer animating the task list until after the animation completes Bug: 73118672 Test: Enter split screen Change-Id: Ie10c079cb22ae82f3c5974296462abae335ef5a8
This commit is contained in:
@@ -198,8 +198,8 @@ public class OverviewSwipeController extends AnimatorListenerAdapter
|
||||
}
|
||||
} else {
|
||||
if (goingUp) {
|
||||
mPendingAnimation = mRecentsView
|
||||
.createTaskDismissAnimation(mTaskBeingDragged, maxDuration);
|
||||
mPendingAnimation = mRecentsView.createTaskDismissAnimation(mTaskBeingDragged,
|
||||
true /* animateTaskView */, true /* removeTask */, maxDuration);
|
||||
mCurrentAnimation = AnimatorPlaybackController
|
||||
.wrap(mPendingAnimation.anim, maxDuration);
|
||||
mEndDisplacement = -mTaskBeingDragged.getHeight();
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package com.android.quickstep;
|
||||
|
||||
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
@@ -31,12 +33,15 @@ import android.view.ViewTreeObserver.OnPreDrawListener;
|
||||
|
||||
import com.android.launcher3.AbstractFloatingView;
|
||||
import com.android.launcher3.BaseDraggingActivity;
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.ItemInfo;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.ShortcutInfo;
|
||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||
import com.android.launcher3.popup.SystemShortcut;
|
||||
import com.android.launcher3.util.InstantAppResolver;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
import com.android.quickstep.views.TaskThumbnailView;
|
||||
import com.android.quickstep.views.TaskView;
|
||||
import com.android.systemui.shared.recents.ISystemUiProxy;
|
||||
import com.android.systemui.shared.recents.model.Task;
|
||||
@@ -57,6 +62,7 @@ import java.util.function.Consumer;
|
||||
public class TaskSystemShortcut<T extends SystemShortcut> extends SystemShortcut {
|
||||
|
||||
private static final String TAG = "TaskSystemShortcut";
|
||||
private static final int DISMISS_TASK_DURATION = 300;
|
||||
|
||||
protected T mSystemShortcut;
|
||||
|
||||
@@ -99,10 +105,13 @@ public class TaskSystemShortcut<T extends SystemShortcut> extends SystemShortcut
|
||||
}
|
||||
}
|
||||
|
||||
public static class SplitScreen extends TaskSystemShortcut implements OnPreDrawListener {
|
||||
public static class SplitScreen extends TaskSystemShortcut implements OnPreDrawListener,
|
||||
DeviceProfile.OnDeviceProfileChangeListener, View.OnLayoutChangeListener {
|
||||
|
||||
private Handler mHandler;
|
||||
private RecentsView mRecentsView;
|
||||
private TaskView mTaskView;
|
||||
private BaseDraggingActivity mActivity;
|
||||
|
||||
public SplitScreen() {
|
||||
super(R.drawable.ic_split_screen, R.string.recent_task_option_split_screen);
|
||||
@@ -116,15 +125,19 @@ public class TaskSystemShortcut<T extends SystemShortcut> extends SystemShortcut
|
||||
return null;
|
||||
}
|
||||
final Task task = taskView.getTask();
|
||||
final int taskId = task.key.id;
|
||||
if (!task.isDockable) {
|
||||
return null;
|
||||
}
|
||||
mActivity = activity;
|
||||
mRecentsView = activity.getOverviewPanel();
|
||||
mTaskView = taskView;
|
||||
final TaskThumbnailView thumbnailView = taskView.getThumbnail();
|
||||
return (v -> {
|
||||
AbstractFloatingView.closeOpenViews(activity, true,
|
||||
AbstractFloatingView.TYPE_ALL & ~AbstractFloatingView.TYPE_REBIND_SAFE);
|
||||
|
||||
if (ActivityManagerWrapper.getInstance().startActivityFromRecents(task.key.id,
|
||||
if (ActivityManagerWrapper.getInstance().startActivityFromRecents(taskId,
|
||||
ActivityOptionsCompat.makeSplitScreenOptions(true))) {
|
||||
ISystemUiProxy sysUiProxy = RecentsModel.getInstance(activity).getSystemUiProxy();
|
||||
try {
|
||||
@@ -134,26 +147,35 @@ public class TaskSystemShortcut<T extends SystemShortcut> extends SystemShortcut
|
||||
return;
|
||||
}
|
||||
|
||||
// Add a device profile change listener to kick off animating the side tasks
|
||||
// once we enter multiwindow mode and relayout
|
||||
activity.addOnDeviceProfileChangeListener(this);
|
||||
|
||||
final Runnable animStartedListener = () -> {
|
||||
// Hide the task view and wait for the window to be resized
|
||||
// TODO: Consider animating in launcher and do an in-place start activity
|
||||
// afterwards
|
||||
mRecentsView.addIgnoreResetTask(mTaskView);
|
||||
mTaskView.setAlpha(0f);
|
||||
mTaskView.getViewTreeObserver().addOnPreDrawListener(SplitScreen.this);
|
||||
activity.<RecentsView>getOverviewPanel().removeView(taskView);
|
||||
};
|
||||
|
||||
final int[] position = new int[2];
|
||||
taskView.getLocationOnScreen(position);
|
||||
final int width = (int) (taskView.getWidth() * taskView.getScaleX());
|
||||
final int height = (int) (taskView.getHeight() * taskView.getScaleY());
|
||||
thumbnailView.getLocationOnScreen(position);
|
||||
final int width = (int) (thumbnailView.getWidth() * taskView.getScaleX());
|
||||
final int height = (int) (thumbnailView.getHeight() * taskView.getScaleY());
|
||||
final Rect taskBounds = new Rect(position[0], position[1],
|
||||
position[0] + width, position[1] + height);
|
||||
|
||||
Bitmap thumbnail = RecentsTransition.drawViewIntoHardwareBitmap(
|
||||
taskBounds.width(), taskBounds.height(), taskView, 1f, Color.BLACK);
|
||||
taskBounds.width(), taskBounds.height(), thumbnailView, 1f,
|
||||
Color.BLACK);
|
||||
AppTransitionAnimationSpecsFuture future =
|
||||
new AppTransitionAnimationSpecsFuture(mHandler) {
|
||||
@Override
|
||||
public List<AppTransitionAnimationSpecCompat> composeSpecs() {
|
||||
return Collections.singletonList(new AppTransitionAnimationSpecCompat(
|
||||
task.key.id, thumbnail, taskBounds));
|
||||
taskId, thumbnail, taskBounds));
|
||||
}
|
||||
};
|
||||
WindowManagerWrapper.getInstance().overridePendingAppTransitionMultiThumbFuture(
|
||||
@@ -168,6 +190,31 @@ public class TaskSystemShortcut<T extends SystemShortcut> extends SystemShortcut
|
||||
WindowManagerWrapper.getInstance().endProlongedAnimations();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeviceProfileChanged(DeviceProfile dp) {
|
||||
mActivity.removeOnDeviceProfileChangeListener(this);
|
||||
if (dp.isMultiWindowMode) {
|
||||
mTaskView.getRootView().addOnLayoutChangeListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLayoutChange(View v, int l, int t, int r, int b,
|
||||
int oldL, int oldT, int oldR, int oldB) {
|
||||
mTaskView.getRootView().removeOnLayoutChangeListener(this);
|
||||
mRecentsView.removeIgnoreResetTask(mTaskView);
|
||||
|
||||
// Start animating in the side pages once launcher has been resized
|
||||
PendingAnimation pendingAnim = mRecentsView.createTaskDismissAnimation(mTaskView,
|
||||
false, false, DISMISS_TASK_DURATION);
|
||||
AnimatorPlaybackController controller = AnimatorPlaybackController.wrap(
|
||||
pendingAnim.anim, DISMISS_TASK_DURATION);
|
||||
controller.dispatchOnStart();
|
||||
controller.setEndAction(() -> pendingAnim.finish(true));
|
||||
controller.getAnimationPlayer().setInterpolator(FAST_OUT_SLOW_IN);
|
||||
controller.start();
|
||||
}
|
||||
}
|
||||
|
||||
public static class Pin extends TaskSystemShortcut {
|
||||
|
||||
@@ -30,6 +30,7 @@ import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Build;
|
||||
import android.util.ArraySet;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.SparseBooleanArray;
|
||||
import android.view.LayoutInflater;
|
||||
@@ -104,6 +105,9 @@ public abstract class RecentsView<T extends BaseActivity>
|
||||
|
||||
private PendingAnimation mPendingAnimation;
|
||||
|
||||
// Keeps track of task views whose visual state should not be reset
|
||||
private ArraySet<TaskView> mIgnoreResetTaskViews = new ArraySet<>();
|
||||
|
||||
public RecentsView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
setPageSpacing(getResources().getDimensionPixelSize(R.dimen.recents_page_spacing));
|
||||
@@ -261,7 +265,10 @@ public abstract class RecentsView<T extends BaseActivity>
|
||||
|
||||
public void resetTaskVisuals() {
|
||||
for (int i = getChildCount() - 1; i >= 0; i--) {
|
||||
((TaskView) getChildAt(i)).resetVisualProperties();
|
||||
TaskView taskView = (TaskView) getChildAt(i);
|
||||
if (!mIgnoreResetTaskViews.contains(taskView)) {
|
||||
taskView.resetVisualProperties();
|
||||
}
|
||||
}
|
||||
|
||||
updateCurveProperties();
|
||||
@@ -512,7 +519,16 @@ public abstract class RecentsView<T extends BaseActivity>
|
||||
public float linearInterpolation;
|
||||
}
|
||||
|
||||
public PendingAnimation createTaskDismissAnimation(TaskView taskView, long duration) {
|
||||
public void addIgnoreResetTask(TaskView taskView) {
|
||||
mIgnoreResetTaskViews.add(taskView);
|
||||
}
|
||||
|
||||
public void removeIgnoreResetTask(TaskView taskView) {
|
||||
mIgnoreResetTaskViews.remove(taskView);
|
||||
}
|
||||
|
||||
public PendingAnimation createTaskDismissAnimation(TaskView taskView, boolean animateTaskView,
|
||||
boolean removeTask, long duration) {
|
||||
if (FeatureFlags.IS_DOGFOOD_BUILD && mPendingAnimation != null) {
|
||||
throw new IllegalStateException("Another pending animation is still running");
|
||||
}
|
||||
@@ -543,9 +559,11 @@ public abstract class RecentsView<T extends BaseActivity>
|
||||
for (int i = 0; i < count; i++) {
|
||||
View child = getChildAt(i);
|
||||
if (child == taskView) {
|
||||
addAnim(ObjectAnimator.ofFloat(taskView, ALPHA, 0), duration, ACCEL_2, anim);
|
||||
addAnim(ObjectAnimator.ofFloat(taskView, TRANSLATION_Y, -taskView.getHeight()),
|
||||
duration, LINEAR, anim);
|
||||
if (animateTaskView) {
|
||||
addAnim(ObjectAnimator.ofFloat(taskView, ALPHA, 0), duration, ACCEL_2, anim);
|
||||
addAnim(ObjectAnimator.ofFloat(taskView, TRANSLATION_Y, -taskView.getHeight()),
|
||||
duration, LINEAR, anim);
|
||||
}
|
||||
} else {
|
||||
int scrollDiff = newScroll[i] - oldScroll[i] + maxScrollDiff;
|
||||
if (scrollDiff != 0) {
|
||||
@@ -563,12 +581,16 @@ public abstract class RecentsView<T extends BaseActivity>
|
||||
}
|
||||
|
||||
// Add a tiny bit of translation Z, so that it draws on top of other views
|
||||
taskView.setTranslationZ(0.1f);
|
||||
if (animateTaskView) {
|
||||
taskView.setTranslationZ(0.1f);
|
||||
}
|
||||
|
||||
mPendingAnimation = pendingAnimation;
|
||||
mPendingAnimation.addEndListener((isSuccess) -> {
|
||||
if (isSuccess) {
|
||||
ActivityManagerWrapper.getInstance().removeTask(taskView.getTask().key.id);
|
||||
if (removeTask) {
|
||||
ActivityManagerWrapper.getInstance().removeTask(taskView.getTask().key.id);
|
||||
}
|
||||
removeView(taskView);
|
||||
if (getChildCount() == 0) {
|
||||
onAllTasksRemoved();
|
||||
|
||||
@@ -98,9 +98,12 @@ public abstract class BaseActivity extends Activity {
|
||||
mDPChangeListeners.add(listener);
|
||||
}
|
||||
|
||||
public void removeOnDeviceProfileChangeListener(OnDeviceProfileChangeListener listener) {
|
||||
mDPChangeListeners.remove(listener);
|
||||
}
|
||||
|
||||
protected void dispatchDeviceProfileChanged() {
|
||||
int count = mDPChangeListeners.size();
|
||||
for (int i = 0; i < count; i++) {
|
||||
for (int i = mDPChangeListeners.size() - 1; i >= 0; i--) {
|
||||
mDPChangeListeners.get(i).onDeviceProfileChanged(mDeviceProfile);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user