5c5472ff96
This change fixes the bug where the view for the fake task in the overview gesture was not being reset correctly. This was leading to UI issues such as lack of rounded corners and incorrect animations in the gesture navigation tutorial. Flag: ENABLE_NEW_GESTURE_NAV_TUTORIAL Fix: 281121451 Fix: 281121699 Fix: 281785378 Test: Manually went through the tutorial on handheld, foldable, and tablet devices Change-Id: I424a471013d2b8667724f790618d142ba7ae9a7b
228 lines
9.2 KiB
Java
228 lines
9.2 KiB
Java
/*
|
|
* Copyright (C) 2020 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.quickstep.interaction;
|
|
|
|
import static com.android.launcher3.anim.Interpolators.ACCEL;
|
|
import static com.android.launcher3.config.FeatureFlags.ENABLE_NEW_GESTURE_NAV_TUTORIAL;
|
|
|
|
import android.animation.Animator;
|
|
import android.animation.AnimatorListenerAdapter;
|
|
import android.animation.AnimatorSet;
|
|
import android.annotation.Nullable;
|
|
import android.annotation.TargetApi;
|
|
import android.graphics.PointF;
|
|
import android.os.Build;
|
|
import android.os.Handler;
|
|
import android.view.View;
|
|
|
|
import com.android.launcher3.R;
|
|
import com.android.launcher3.anim.AnimatedFloat;
|
|
import com.android.launcher3.anim.PendingAnimation;
|
|
import com.android.quickstep.SwipeUpAnimationLogic;
|
|
import com.android.quickstep.interaction.EdgeBackGestureHandler.BackGestureResult;
|
|
import com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult;
|
|
|
|
import java.util.ArrayList;
|
|
|
|
/** A {@link TutorialController} for the Overview tutorial. */
|
|
@TargetApi(Build.VERSION_CODES.R)
|
|
final class OverviewGestureTutorialController extends SwipeUpGestureTutorialController {
|
|
|
|
OverviewGestureTutorialController(OverviewGestureTutorialFragment fragment,
|
|
TutorialType tutorialType) {
|
|
super(fragment, tutorialType);
|
|
}
|
|
@Override
|
|
public int getIntroductionTitle() {
|
|
return ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
|
|
? R.string.overview_gesture_tutorial_title
|
|
: R.string.overview_gesture_intro_title;
|
|
}
|
|
|
|
@Override
|
|
public int getIntroductionSubtitle() {
|
|
return R.string.overview_gesture_intro_subtitle;
|
|
}
|
|
|
|
@Override
|
|
public int getSpokenIntroductionSubtitle() {
|
|
return R.string.overview_gesture_spoken_intro_subtitle;
|
|
}
|
|
|
|
@Override
|
|
public int getSuccessFeedbackSubtitle() {
|
|
return mTutorialFragment.getNumSteps() > 1 && mTutorialFragment.isAtFinalStep()
|
|
? R.string.overview_gesture_feedback_complete_with_follow_up
|
|
: R.string.overview_gesture_feedback_complete_without_follow_up;
|
|
}
|
|
|
|
@Override
|
|
protected int getMockAppTaskLayoutResId() {
|
|
return ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
|
|
? R.layout.gesture_tutorial_mock_task_view
|
|
: mTutorialFragment.isLargeScreen()
|
|
? R.layout.gesture_tutorial_tablet_mock_conversation_list
|
|
: R.layout.gesture_tutorial_mock_conversation_list;
|
|
}
|
|
|
|
@Override
|
|
protected int getGestureLottieAnimationId() {
|
|
return mTutorialFragment.isLargeScreen()
|
|
? mTutorialFragment.isFoldable()
|
|
? R.raw.overview_gesture_tutorial_open_foldable_animation
|
|
: R.raw.overview_gesture_tutorial_tablet_animation
|
|
: R.raw.overview_gesture_tutorial_animation;
|
|
}
|
|
|
|
@Override
|
|
protected int getSwipeActionColorResId() {
|
|
return R.color.gesture_overview_background;
|
|
}
|
|
|
|
@Override
|
|
protected int getMockPreviousAppTaskThumbnailColorResId() {
|
|
return ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
|
|
? R.color.gesture_overview_tutorial_swipe_rect
|
|
: R.color.gesture_tutorial_fake_previous_task_view_color;
|
|
}
|
|
|
|
@Override
|
|
public void onBackGestureAttempted(BackGestureResult result) {
|
|
if (isGestureCompleted()) {
|
|
return;
|
|
}
|
|
switch (mTutorialType) {
|
|
case OVERVIEW_NAVIGATION:
|
|
switch (result) {
|
|
case BACK_COMPLETED_FROM_LEFT:
|
|
case BACK_COMPLETED_FROM_RIGHT:
|
|
case BACK_CANCELLED_FROM_LEFT:
|
|
case BACK_CANCELLED_FROM_RIGHT:
|
|
case BACK_NOT_STARTED_TOO_FAR_FROM_EDGE:
|
|
resetTaskView();
|
|
showFeedback(R.string.overview_gesture_feedback_swipe_too_far_from_edge);
|
|
break;
|
|
}
|
|
break;
|
|
case OVERVIEW_NAVIGATION_COMPLETE:
|
|
if (result == BackGestureResult.BACK_COMPLETED_FROM_LEFT
|
|
|| result == BackGestureResult.BACK_COMPLETED_FROM_RIGHT) {
|
|
mTutorialFragment.close();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onNavBarGestureAttempted(NavBarGestureResult result, PointF finalVelocity) {
|
|
if (isGestureCompleted()) {
|
|
return;
|
|
}
|
|
switch (mTutorialType) {
|
|
case OVERVIEW_NAVIGATION:
|
|
switch (result) {
|
|
case HOME_GESTURE_COMPLETED: {
|
|
animateFakeTaskViewHome(finalVelocity, () -> {
|
|
showFeedback(R.string.overview_gesture_feedback_home_detected);
|
|
resetFakeTaskView(true);
|
|
});
|
|
break;
|
|
}
|
|
case HOME_NOT_STARTED_TOO_FAR_FROM_EDGE:
|
|
case OVERVIEW_NOT_STARTED_TOO_FAR_FROM_EDGE:
|
|
resetTaskView();
|
|
showFeedback(R.string.overview_gesture_feedback_swipe_too_far_from_edge);
|
|
break;
|
|
case OVERVIEW_GESTURE_COMPLETED:
|
|
mTutorialFragment.releaseFeedbackAnimation();
|
|
if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) {
|
|
onMotionPaused(true /*arbitrary value*/);
|
|
animateTaskViewToOverview(() -> {
|
|
mFakeTaskView.setVisibility(View.INVISIBLE);
|
|
if(!mTutorialFragment.isLargeScreen()){
|
|
mFakePreviousTaskView.animateToFillScreen(() -> {
|
|
mFakeLauncherView.setBackgroundColor(
|
|
mContext.getColor(
|
|
R.color.gesture_overview_tutorial_swipe_rect
|
|
));
|
|
showSuccessFeedback();
|
|
});
|
|
} else {
|
|
mFakeLauncherView.setBackgroundColor(
|
|
mContext.getColor(
|
|
R.color.gesture_overview_tutorial_swipe_rect
|
|
));
|
|
showSuccessFeedback();
|
|
}
|
|
});
|
|
} else {
|
|
animateTaskViewToOverview(null);
|
|
onMotionPaused(true /*arbitrary value*/);
|
|
showSuccessFeedback();
|
|
}
|
|
break;
|
|
case HOME_OR_OVERVIEW_NOT_STARTED_WRONG_SWIPE_DIRECTION:
|
|
case HOME_OR_OVERVIEW_CANCELLED:
|
|
fadeOutFakeTaskView(false, true, null);
|
|
showFeedback(R.string.overview_gesture_feedback_wrong_swipe_direction);
|
|
break;
|
|
}
|
|
break;
|
|
case OVERVIEW_NAVIGATION_COMPLETE:
|
|
if (result == NavBarGestureResult.HOME_GESTURE_COMPLETED) {
|
|
mTutorialFragment.close();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* runnable executed with slight delay to ease the swipe animation after landing on overview
|
|
* @param runnable
|
|
*/
|
|
public void animateTaskViewToOverview(@Nullable Runnable runnable) {
|
|
PendingAnimation anim = new PendingAnimation(TASK_VIEW_END_ANIMATION_DURATION_MILLIS);
|
|
anim.setFloat(mTaskViewSwipeUpAnimation
|
|
.getCurrentShift(), AnimatedFloat.VALUE, 1, ACCEL);
|
|
|
|
anim.addListener(new AnimatorListenerAdapter() {
|
|
@Override
|
|
public void onAnimationEnd(Animator animator) {
|
|
if (runnable != null) {
|
|
new Handler().postDelayed(runnable, 300);
|
|
}
|
|
}
|
|
});
|
|
|
|
ArrayList<Animator> animators = new ArrayList<>();
|
|
|
|
if (mTutorialFragment.isLargeScreen()) {
|
|
Animator multiRowAnimation = mFakePreviousTaskView.createAnimationToMultiRowLayout();
|
|
|
|
if (multiRowAnimation != null) {
|
|
multiRowAnimation.setDuration(TASK_VIEW_END_ANIMATION_DURATION_MILLIS);
|
|
animators.add(multiRowAnimation);
|
|
}
|
|
}
|
|
animators.add(anim.buildAnim());
|
|
|
|
AnimatorSet animset = new AnimatorSet();
|
|
animset.playTogether(animators);
|
|
animset.start();
|
|
mRunningWindowAnim = SwipeUpAnimationLogic.RunningWindowAnim.wrap(animset);
|
|
}
|
|
}
|