1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.quickstep.interaction; 17 18 import static com.android.launcher3.anim.Interpolators.ACCEL; 19 20 import android.animation.Animator; 21 import android.animation.AnimatorSet; 22 import android.annotation.TargetApi; 23 import android.graphics.PointF; 24 import android.os.Build; 25 26 import com.android.launcher3.R; 27 import com.android.launcher3.anim.PendingAnimation; 28 import com.android.quickstep.AnimatedFloat; 29 import com.android.quickstep.SwipeUpAnimationLogic; 30 import com.android.quickstep.interaction.EdgeBackGestureHandler.BackGestureResult; 31 import com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult; 32 33 import java.util.ArrayList; 34 35 /** A {@link TutorialController} for the Overview tutorial. */ 36 @TargetApi(Build.VERSION_CODES.R) 37 final class OverviewGestureTutorialController extends SwipeUpGestureTutorialController { 38 OverviewGestureTutorialController(OverviewGestureTutorialFragment fragment, TutorialType tutorialType)39 OverviewGestureTutorialController(OverviewGestureTutorialFragment fragment, 40 TutorialType tutorialType) { 41 super(fragment, tutorialType); 42 } 43 44 @Override getIntroductionTitle()45 public Integer getIntroductionTitle() { 46 return R.string.overview_gesture_intro_title; 47 } 48 49 @Override getIntroductionSubtitle()50 public Integer getIntroductionSubtitle() { 51 return R.string.overview_gesture_intro_subtitle; 52 } 53 54 @Override getSuccessFeedbackSubtitle()55 public Integer getSuccessFeedbackSubtitle() { 56 return mTutorialFragment.getNumSteps() > 1 && mTutorialFragment.isAtFinalStep() 57 ? R.string.overview_gesture_feedback_complete_with_follow_up 58 : R.string.overview_gesture_feedback_complete_without_follow_up; 59 } 60 61 @Override getMockAppTaskLayoutResId()62 protected int getMockAppTaskLayoutResId() { 63 return mTutorialFragment.isLargeScreen() 64 ? R.layout.gesture_tutorial_foldable_mock_conversation_list 65 : R.layout.gesture_tutorial_mock_conversation_list; 66 } 67 68 @Override onBackGestureAttempted(BackGestureResult result)69 public void onBackGestureAttempted(BackGestureResult result) { 70 if (isGestureCompleted()) { 71 return; 72 } 73 switch (mTutorialType) { 74 case OVERVIEW_NAVIGATION: 75 switch (result) { 76 case BACK_COMPLETED_FROM_LEFT: 77 case BACK_COMPLETED_FROM_RIGHT: 78 case BACK_CANCELLED_FROM_LEFT: 79 case BACK_CANCELLED_FROM_RIGHT: 80 showFeedback(R.string.overview_gesture_feedback_swipe_too_far_from_edge); 81 break; 82 } 83 break; 84 case OVERVIEW_NAVIGATION_COMPLETE: 85 if (result == BackGestureResult.BACK_COMPLETED_FROM_LEFT 86 || result == BackGestureResult.BACK_COMPLETED_FROM_RIGHT) { 87 mTutorialFragment.closeTutorial(); 88 } 89 break; 90 } 91 } 92 93 @Override onNavBarGestureAttempted(NavBarGestureResult result, PointF finalVelocity)94 public void onNavBarGestureAttempted(NavBarGestureResult result, PointF finalVelocity) { 95 if (isGestureCompleted()) { 96 return; 97 } 98 switch (mTutorialType) { 99 case OVERVIEW_NAVIGATION: 100 switch (result) { 101 case HOME_GESTURE_COMPLETED: { 102 animateFakeTaskViewHome(finalVelocity, () -> { 103 showFeedback(R.string.overview_gesture_feedback_home_detected); 104 resetFakeTaskView(true); 105 }); 106 break; 107 } 108 case HOME_NOT_STARTED_TOO_FAR_FROM_EDGE: 109 case OVERVIEW_NOT_STARTED_TOO_FAR_FROM_EDGE: 110 showFeedback(R.string.overview_gesture_feedback_swipe_too_far_from_edge); 111 break; 112 case OVERVIEW_GESTURE_COMPLETED: 113 mTutorialFragment.releaseFeedbackAnimation(); 114 animateTaskViewToOverview(); 115 onMotionPaused(true /*arbitrary value*/); 116 showSuccessFeedback(); 117 break; 118 case HOME_OR_OVERVIEW_NOT_STARTED_WRONG_SWIPE_DIRECTION: 119 case HOME_OR_OVERVIEW_CANCELLED: 120 fadeOutFakeTaskView(false, true, null); 121 showFeedback(R.string.overview_gesture_feedback_wrong_swipe_direction); 122 break; 123 } 124 break; 125 case OVERVIEW_NAVIGATION_COMPLETE: 126 if (result == NavBarGestureResult.HOME_GESTURE_COMPLETED) { 127 mTutorialFragment.closeTutorial(); 128 } 129 break; 130 } 131 } 132 animateTaskViewToOverview()133 public void animateTaskViewToOverview() { 134 PendingAnimation anim = new PendingAnimation(TASK_VIEW_END_ANIMATION_DURATION_MILLIS); 135 anim.setFloat(mTaskViewSwipeUpAnimation 136 .getCurrentShift(), AnimatedFloat.VALUE, 1, ACCEL); 137 138 ArrayList<Animator> animators = new ArrayList<>(); 139 140 if (mTutorialFragment.isLargeScreen()) { 141 Animator multiRowAnimation = mFakePreviousTaskView.createAnimationToMultiRowLayout(); 142 143 if (multiRowAnimation != null) { 144 multiRowAnimation.setDuration(TASK_VIEW_END_ANIMATION_DURATION_MILLIS); 145 animators.add(multiRowAnimation); 146 } 147 } 148 animators.add(anim.buildAnim()); 149 150 AnimatorSet animset = new AnimatorSet(); 151 animset.playTogether(animators); 152 hideFakeTaskbar(/* animateToHotseat= */ false); 153 animset.start(); 154 mRunningWindowAnim = SwipeUpAnimationLogic.RunningWindowAnim.wrap(animset); 155 } 156 } 157