1 /* 2 * Copyright (C) 2019 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; 17 18 import static com.android.launcher3.util.NavigationMode.NO_BUTTON; 19 import static com.android.quickstep.fallback.RecentsState.BACKGROUND_APP; 20 import static com.android.quickstep.fallback.RecentsState.DEFAULT; 21 import static com.android.quickstep.fallback.RecentsState.HOME; 22 23 import android.animation.Animator; 24 import android.animation.AnimatorSet; 25 import android.content.Context; 26 import android.graphics.Rect; 27 import android.view.MotionEvent; 28 import android.view.RemoteAnimationTarget; 29 30 import androidx.annotation.Nullable; 31 32 import com.android.launcher3.DeviceProfile; 33 import com.android.launcher3.statemanager.StateManager; 34 import com.android.launcher3.taskbar.FallbackTaskbarUIController; 35 import com.android.launcher3.util.DisplayController; 36 import com.android.quickstep.GestureState.GestureEndTarget; 37 import com.android.quickstep.fallback.RecentsState; 38 import com.android.quickstep.orientation.RecentsPagedOrientationHandler; 39 import com.android.quickstep.util.ActivityInitListener; 40 import com.android.quickstep.util.AnimatorControllerWithResistance; 41 import com.android.quickstep.views.RecentsView; 42 43 import java.util.function.Consumer; 44 import java.util.function.Predicate; 45 46 /** 47 * {@link BaseActivityInterface} for recents when the default launcher is different than the 48 * currently running one and apps should interact with the {@link RecentsActivity} as opposed 49 * to the in-launcher one. 50 */ 51 public final class FallbackActivityInterface extends 52 BaseActivityInterface<RecentsState, RecentsActivity> { 53 54 public static final FallbackActivityInterface INSTANCE = new FallbackActivityInterface(); 55 FallbackActivityInterface()56 private FallbackActivityInterface() { 57 super(false, DEFAULT, BACKGROUND_APP); 58 } 59 60 /** 2 */ 61 @Override getSwipeUpDestinationAndLength(DeviceProfile dp, Context context, Rect outRect, RecentsPagedOrientationHandler orientationHandler)62 public int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context, Rect outRect, 63 RecentsPagedOrientationHandler orientationHandler) { 64 calculateTaskSize(context, dp, outRect, orientationHandler); 65 if (dp.isVerticalBarLayout() && DisplayController.getNavigationMode(context) != NO_BUTTON) { 66 return dp.isSeascape() ? outRect.left : (dp.widthPx - outRect.right); 67 } else { 68 return dp.heightPx - outRect.bottom; 69 } 70 } 71 72 /** 5 */ 73 @Override onAssistantVisibilityChanged(float visibility)74 public void onAssistantVisibilityChanged(float visibility) { 75 // This class becomes active when the screen is locked. 76 // Rather than having it handle assistant visibility changes, the assistant visibility is 77 // set to zero prior to this class becoming active. 78 } 79 80 /** 6 */ 81 @Override prepareRecentsUI(RecentsAnimationDeviceState deviceState, boolean activityVisible, Consumer<AnimatorControllerWithResistance> callback)82 public AnimationFactory prepareRecentsUI(RecentsAnimationDeviceState deviceState, 83 boolean activityVisible, Consumer<AnimatorControllerWithResistance> callback) { 84 notifyRecentsOfOrientation(deviceState.getRotationTouchHelper()); 85 DefaultAnimationFactory factory = new DefaultAnimationFactory(callback); 86 factory.initBackgroundStateUI(); 87 return factory; 88 } 89 90 @Override createActivityInitListener( Predicate<Boolean> onInitListener)91 public ActivityInitListener createActivityInitListener( 92 Predicate<Boolean> onInitListener) { 93 return new ActivityInitListener<>((activity, alreadyOnHome) -> 94 onInitListener.test(alreadyOnHome), RecentsActivity.ACTIVITY_TRACKER); 95 } 96 97 @Nullable 98 @Override getCreatedContainer()99 public RecentsActivity getCreatedContainer() { 100 return RecentsActivity.ACTIVITY_TRACKER.getCreatedActivity(); 101 } 102 103 @Override getTaskbarController()104 public FallbackTaskbarUIController getTaskbarController() { 105 RecentsActivity activity = getCreatedContainer(); 106 if (activity == null) { 107 return null; 108 } 109 return activity.getTaskbarUIController(); 110 } 111 112 @Nullable 113 @Override getVisibleRecentsView()114 public RecentsView getVisibleRecentsView() { 115 RecentsActivity activity = getCreatedContainer(); 116 if (activity != null) { 117 if (activity.hasBeenResumed() || isInLiveTileMode()) { 118 return activity.getOverviewPanel(); 119 } 120 } 121 return null; 122 } 123 124 @Override switchToRecentsIfVisible(Animator.AnimatorListener animatorListener)125 public boolean switchToRecentsIfVisible(Animator.AnimatorListener animatorListener) { 126 return false; 127 } 128 129 @Override getOverviewWindowBounds(Rect homeBounds, RemoteAnimationTarget target)130 public Rect getOverviewWindowBounds(Rect homeBounds, RemoteAnimationTarget target) { 131 // TODO: Remove this once b/77875376 is fixed 132 return target.screenSpaceBounds; 133 } 134 135 @Override allowMinimizeSplitScreen()136 public boolean allowMinimizeSplitScreen() { 137 // TODO: Remove this once b/77875376 is fixed 138 return false; 139 } 140 141 @Override allowAllAppsFromOverview()142 public boolean allowAllAppsFromOverview() { 143 return false; 144 } 145 146 @Override deferStartingActivity(RecentsAnimationDeviceState deviceState, MotionEvent ev)147 public boolean deferStartingActivity(RecentsAnimationDeviceState deviceState, MotionEvent ev) { 148 // In non-gesture mode, user might be clicking on the home button which would directly 149 // start the home activity instead of going through recents. In that case, defer starting 150 // recents until we are sure it is a gesture. 151 return !deviceState.isFullyGesturalNavMode() 152 || super.deferStartingActivity(deviceState, ev); 153 } 154 155 @Override onExitOverview(RotationTouchHelper deviceState, Runnable exitRunnable)156 public void onExitOverview(RotationTouchHelper deviceState, Runnable exitRunnable) { 157 final StateManager<RecentsState, RecentsActivity> stateManager = 158 getCreatedContainer().getStateManager(); 159 if (stateManager.getState() == HOME) { 160 exitRunnable.run(); 161 notifyRecentsOfOrientation(deviceState); 162 return; 163 } 164 165 stateManager.addStateListener( 166 new StateManager.StateListener<RecentsState>() { 167 @Override 168 public void onStateTransitionComplete(RecentsState toState) { 169 // Are we going from Recents to Workspace? 170 if (toState == HOME) { 171 exitRunnable.run(); 172 notifyRecentsOfOrientation(deviceState); 173 stateManager.removeStateListener(this); 174 } 175 } 176 }); 177 } 178 179 @Override isInLiveTileMode()180 public boolean isInLiveTileMode() { 181 RecentsActivity activity = getCreatedContainer(); 182 return activity != null && activity.getStateManager().getState() == DEFAULT && 183 activity.isStarted(); 184 } 185 186 @Override onLaunchTaskFailed()187 public void onLaunchTaskFailed() { 188 // TODO: probably go back to overview instead. 189 RecentsActivity activity = getCreatedContainer(); 190 if (activity == null) { 191 return; 192 } 193 activity.<RecentsView>getOverviewPanel().startHome(); 194 } 195 196 @Override stateFromGestureEndTarget(GestureEndTarget endTarget)197 public RecentsState stateFromGestureEndTarget(GestureEndTarget endTarget) { 198 switch (endTarget) { 199 case RECENTS: 200 return DEFAULT; 201 case NEW_TASK: 202 case LAST_TASK: 203 return BACKGROUND_APP; 204 case HOME: 205 case ALL_APPS: 206 default: 207 return HOME; 208 } 209 } 210 notifyRecentsOfOrientation(RotationTouchHelper rotationTouchHelper)211 private void notifyRecentsOfOrientation(RotationTouchHelper rotationTouchHelper) { 212 // reset layout on swipe to home 213 RecentsView recentsView = getCreatedContainer().getOverviewPanel(); 214 recentsView.setLayoutRotation(rotationTouchHelper.getCurrentActiveRotation(), 215 rotationTouchHelper.getDisplayRotation()); 216 } 217 218 @Override getParallelAnimationToLauncher(GestureEndTarget endTarget, long duration, RecentsAnimationCallbacks callbacks)219 public @Nullable Animator getParallelAnimationToLauncher(GestureEndTarget endTarget, 220 long duration, RecentsAnimationCallbacks callbacks) { 221 FallbackTaskbarUIController uiController = getTaskbarController(); 222 Animator superAnimator = super.getParallelAnimationToLauncher( 223 endTarget, duration, callbacks); 224 if (uiController == null) { 225 return superAnimator; 226 } 227 RecentsState toState = stateFromGestureEndTarget(endTarget); 228 Animator taskbarAnimator = uiController.createAnimToRecentsState(toState, duration); 229 if (taskbarAnimator == null) { 230 return superAnimator; 231 } 232 if (superAnimator == null) { 233 return taskbarAnimator; 234 } 235 AnimatorSet animatorSet = new AnimatorSet(); 236 animatorSet.playTogether(superAnimator, taskbarAnimator); 237 return animatorSet; 238 } 239 240 @Override getOverviewScrimColorForState(RecentsActivity activity, RecentsState state)241 protected int getOverviewScrimColorForState(RecentsActivity activity, RecentsState state) { 242 return state.getScrimColor(activity); 243 } 244 } 245