1 /* 2 * Copyright (C) 2021 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.launcher3.taskbar; 17 18 import static com.android.launcher3.Utilities.isRunningInTestHarness; 19 import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_APP; 20 import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_STASHED_LAUNCHER_STATE; 21 22 import android.animation.Animator; 23 24 import androidx.annotation.Nullable; 25 26 import com.android.launcher3.popup.SystemShortcut; 27 import com.android.launcher3.statemanager.StateManager; 28 import com.android.launcher3.statemanager.StatefulContainer; 29 import com.android.quickstep.FallbackActivityInterface; 30 import com.android.quickstep.GestureState; 31 import com.android.quickstep.RecentsAnimationCallbacks; 32 import com.android.quickstep.TopTaskTracker; 33 import com.android.quickstep.fallback.RecentsState; 34 import com.android.quickstep.views.RecentsView; 35 import com.android.quickstep.views.RecentsViewContainer; 36 37 import java.io.PrintWriter; 38 import java.util.stream.Stream; 39 40 /** 41 * A data source which integrates with the fallback RecentsActivity instance (for 3P launchers). 42 * @param <T> The type of the RecentsViewContainer that will handle Recents state changes. 43 */ 44 public class FallbackTaskbarUIController 45 <T extends RecentsViewContainer & StatefulContainer<RecentsState>> 46 extends TaskbarUIController { 47 48 private final T mRecentsContainer; 49 50 private final StateManager.StateListener<RecentsState> mStateListener = 51 new StateManager.StateListener<RecentsState>() { 52 @Override 53 public void onStateTransitionStart(RecentsState toState) { 54 animateToRecentsState(toState); 55 56 RecentsView recentsView = getRecentsView(); 57 if (recentsView == null) { 58 return; 59 } 60 // Handle tapping on live tile. 61 recentsView.setTaskLaunchListener(toState == RecentsState.DEFAULT 62 ? (() -> animateToRecentsState(RecentsState.BACKGROUND_APP)) : null); 63 } 64 65 @Override 66 public void onStateTransitionComplete(RecentsState finalState) { 67 boolean finalStateDefault = finalState == RecentsState.DEFAULT; 68 // TODO(b/268120202) Taskbar shows up on 3P home, currently we don't go to 69 // overview from 3P home. Either implement that or it'll change w/ contextual? 70 boolean disallowLongClick = finalState == RecentsState.OVERVIEW_SPLIT_SELECT; 71 Utilities.setOverviewDragState(mControllers, 72 finalStateDefault /*disallowGlobalDrag*/, disallowLongClick, 73 finalStateDefault /*allowInitialSplitSelection*/); 74 } 75 }; 76 FallbackTaskbarUIController(T recentsContainer)77 public FallbackTaskbarUIController(T recentsContainer) { 78 mRecentsContainer = recentsContainer; 79 } 80 81 @Override init(TaskbarControllers taskbarControllers)82 protected void init(TaskbarControllers taskbarControllers) { 83 super.init(taskbarControllers); 84 mRecentsContainer.setTaskbarUIController(this); 85 mRecentsContainer.getStateManager().addStateListener(mStateListener); 86 } 87 88 @Override onDestroy()89 protected void onDestroy() { 90 super.onDestroy(); 91 RecentsView recentsView = getRecentsView(); 92 if (recentsView != null) { 93 recentsView.setTaskLaunchListener(null); 94 } 95 mRecentsContainer.setTaskbarUIController(null); 96 mRecentsContainer.getStateManager().removeStateListener(mStateListener); 97 } 98 99 @Nullable 100 @Override getParallelAnimationToGestureEndTarget(GestureState.GestureEndTarget endTarget, long duration, RecentsAnimationCallbacks callbacks)101 public Animator getParallelAnimationToGestureEndTarget(GestureState.GestureEndTarget endTarget, 102 long duration, RecentsAnimationCallbacks callbacks) { 103 return createAnimToRecentsState( 104 FallbackActivityInterface.INSTANCE.stateFromGestureEndTarget(endTarget), duration); 105 } 106 107 /** 108 * Creates an animation to animate the taskbar for the given state (but does not start it). 109 * Currently this animation just force stashes the taskbar in Overview. 110 */ createAnimToRecentsState(RecentsState toState, long duration)111 private Animator createAnimToRecentsState(RecentsState toState, long duration) { 112 // Force stash taskbar (disallow unstashing) when: 113 // - in a 3P launcher or overview task. 114 // - not running in a test harness (unstash is needed for tests) 115 boolean forceStash = isIn3pHomeOrRecents() && !isRunningInTestHarness(); 116 TaskbarStashController stashController = mControllers.taskbarStashController; 117 // Set both FLAG_IN_STASHED_LAUNCHER_STATE and FLAG_IN_APP to ensure the state is respected. 118 // For all other states, just use the current stashed-in-app setting (e.g. if long clicked). 119 stashController.updateStateForFlag(FLAG_IN_STASHED_LAUNCHER_STATE, forceStash); 120 stashController.updateStateForFlag(FLAG_IN_APP, !forceStash); 121 return stashController.createApplyStateAnimator(duration); 122 } 123 animateToRecentsState(RecentsState toState)124 private void animateToRecentsState(RecentsState toState) { 125 Animator anim = createAnimToRecentsState(toState, 126 mControllers.taskbarStashController.getStashDuration()); 127 if (anim != null) { 128 anim.start(); 129 } 130 } 131 132 @Override getRecentsView()133 public @Nullable RecentsView getRecentsView() { 134 return mRecentsContainer.getOverviewPanel(); 135 } 136 137 @Override getSplitMenuOptions()138 Stream<SystemShortcut.Factory<BaseTaskbarContext>> getSplitMenuOptions() { 139 if (isIn3pHomeOrRecents()) { 140 // Split from Taskbar is not supported in fallback launcher, so return empty stream 141 return Stream.empty(); 142 } else { 143 return super.getSplitMenuOptions(); 144 } 145 } 146 isIn3pHomeOrRecents()147 private boolean isIn3pHomeOrRecents() { 148 TopTaskTracker.CachedTaskInfo topTask = TopTaskTracker.INSTANCE 149 .get(mControllers.taskbarActivityContext).getCachedTopTask(true, 150 mRecentsContainer.asContext().getDisplayId()); 151 return topTask.isHomeTask() || topTask.isRecentsTask(); 152 } 153 154 @Override getTaskbarUIControllerName()155 protected String getTaskbarUIControllerName() { 156 return "FallbackTaskbarUIController<" + mRecentsContainer.getClass().getSimpleName() + ">"; 157 } 158 159 @Override dumpLogs(String prefix, PrintWriter pw)160 protected void dumpLogs(String prefix, PrintWriter pw) { 161 super.dumpLogs(prefix, pw); 162 163 pw.println(String.format("%s\tRecentsState=%s", prefix, 164 mRecentsContainer.getStateManager().getState())); 165 } 166 } 167