1 /*
2  * Copyright (C) 2017 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.uioverrides.states;
17 
18 import static com.android.app.animation.Interpolators.DECELERATE_2;
19 import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation;
20 import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_OVERVIEW;
21 import static com.android.wm.shell.Flags.enableSplitContextual;
22 
23 import android.content.Context;
24 import android.graphics.Rect;
25 import android.os.SystemProperties;
26 
27 import com.android.launcher3.DeviceProfile;
28 import com.android.launcher3.Launcher;
29 import com.android.launcher3.LauncherState;
30 import com.android.launcher3.R;
31 import com.android.launcher3.util.DisplayController;
32 import com.android.launcher3.util.Themes;
33 import com.android.quickstep.util.BaseDepthController;
34 import com.android.quickstep.util.LayoutUtils;
35 import com.android.quickstep.views.RecentsView;
36 import com.android.quickstep.views.TaskView;
37 
38 /**
39  * Definition for overview state
40  */
41 public class OverviewState extends LauncherState {
42 
43     private static final int OVERVIEW_SLIDE_IN_DURATION = 380;
44     private static final int OVERVIEW_POP_IN_DURATION = 250;
45     private static final int OVERVIEW_EXIT_DURATION = 250;
46 
47     protected static final Rect sTempRect = new Rect();
48 
49     private static final int STATE_FLAGS = FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED
50             | FLAG_DISABLE_RESTORE | FLAG_RECENTS_VIEW_VISIBLE | FLAG_WORKSPACE_INACCESSIBLE
51             | FLAG_CLOSE_POPUPS;
52 
OverviewState(int id)53     public OverviewState(int id) {
54         this(id, STATE_FLAGS);
55     }
56 
OverviewState(int id, int stateFlags)57     protected OverviewState(int id, int stateFlags) {
58         this(id, LAUNCHER_STATE_OVERVIEW, stateFlags);
59     }
60 
OverviewState(int id, int logContainer, int stateFlags)61     protected OverviewState(int id, int logContainer, int stateFlags) {
62         super(id, logContainer, stateFlags);
63     }
64 
65     @Override
getTransitionDuration(Context context, boolean isToState)66     public int getTransitionDuration(Context context, boolean isToState) {
67         if (isToState) {
68             // In gesture modes, overview comes in all the way from the side, so give it more time.
69             return DisplayController.getNavigationMode(context).hasGestures
70                     ? OVERVIEW_SLIDE_IN_DURATION
71                     : OVERVIEW_POP_IN_DURATION;
72         } else {
73             // When exiting Overview, exit quickly.
74             return OVERVIEW_EXIT_DURATION;
75         }
76     }
77 
78     @Override
getWorkspaceScaleAndTranslation(Launcher launcher)79     public ScaleAndTranslation getWorkspaceScaleAndTranslation(Launcher launcher) {
80         RecentsView recentsView = launcher.getOverviewPanel();
81         recentsView.getTaskSize(sTempRect);
82         float scale;
83         DeviceProfile deviceProfile = launcher.getDeviceProfile();
84         if (deviceProfile.isTwoPanels) {
85             // In two panel layout, width does not include both panels or space between them, so
86             // use height instead. We do not use height for handheld, as cell layout can be
87             // shorter than a task and we want the workspace to scale down to task size.
88             scale = (float) sTempRect.height() / deviceProfile.getCellLayoutHeight();
89         } else {
90             scale = (float) sTempRect.width() / deviceProfile.getCellLayoutWidth();
91         }
92         float parallaxFactor = 0.5f;
93         return new ScaleAndTranslation(scale, 0, -getDefaultSwipeHeight(launcher) * parallaxFactor);
94     }
95 
96     @Override
getOverviewScaleAndOffset(Launcher launcher)97     public float[] getOverviewScaleAndOffset(Launcher launcher) {
98         return new float[] {NO_SCALE, NO_OFFSET};
99     }
100 
101     @Override
getWorkspacePageAlphaProvider(Launcher launcher)102     public PageAlphaProvider getWorkspacePageAlphaProvider(Launcher launcher) {
103         return new PageAlphaProvider(DECELERATE_2) {
104             @Override
105             public float getPageAlpha(int pageIndex) {
106                 return 0;
107             }
108         };
109     }
110 
111     @Override
112     public int getVisibleElements(Launcher launcher) {
113         int elements = CLEAR_ALL_BUTTON | OVERVIEW_ACTIONS;
114         DeviceProfile dp = launcher.getDeviceProfile();
115         boolean showFloatingSearch;
116         if (dp.isPhone) {
117             // Only show search in phone overview in portrait mode.
118             showFloatingSearch = !dp.isLandscape;
119         } else {
120             // Only show search in tablet overview if taskbar is not visible.
121             showFloatingSearch = !dp.isTaskbarPresent || isTaskbarStashed(launcher);
122         }
123         if (showFloatingSearch) {
124             elements |= FLOATING_SEARCH_BAR;
125         }
126         if (enableSplitContextual() && launcher.isSplitSelectionActive()) {
127             elements &= ~CLEAR_ALL_BUTTON;
128         }
129         return elements;
130     }
131 
132     @Override
133     public float getSplitSelectTranslation(Launcher launcher) {
134         if (!enableSplitContextual() || !launcher.isSplitSelectionActive()) {
135             return 0f;
136         }
137         RecentsView recentsView = launcher.getOverviewPanel();
138         return recentsView.getSplitSelectTranslation();
139     }
140 
141     @Override
142     public int getFloatingSearchBarRestingMarginBottom(Launcher launcher) {
143         return areElementsVisible(launcher, FLOATING_SEARCH_BAR) ? 0
144                 : super.getFloatingSearchBarRestingMarginBottom(launcher);
145     }
146 
147     @Override
148     public boolean shouldFloatingSearchBarUsePillWhenUnfocused(Launcher launcher) {
149         DeviceProfile dp = launcher.getDeviceProfile();
150         return dp.isPhone && !dp.isLandscape;
151     }
152 
153     @Override
154     public boolean isTaskbarAlignedWithHotseat(Launcher launcher) {
155         return false;
156     }
157 
158     @Override
159     public int getWorkspaceScrimColor(Launcher launcher) {
160         return Themes.getAttrColor(launcher, R.attr.overviewScrimColor);
161     }
162 
163     @Override
164     public boolean displayOverviewTasksAsGrid(DeviceProfile deviceProfile) {
165         return deviceProfile.isTablet;
166     }
167 
168     @Override
169     public boolean disallowTaskbarGlobalDrag() {
170         // Disable global drag in overview
171         return true;
172     }
173 
174     @Override
175     public boolean allowTaskbarInitialSplitSelection() {
176         // Allow split select from taskbar items in overview
177         return true;
178     }
179 
180     @Override
181     public String getDescription(Launcher launcher) {
182         return launcher.getString(R.string.accessibility_recent_apps);
183     }
184 
185     @Override
186     public int getTitle() {
187         return R.string.accessibility_recent_apps;
188     }
189 
190     public static float getDefaultSwipeHeight(Launcher launcher) {
191         return LayoutUtils.getDefaultSwipeHeight(launcher, launcher.getDeviceProfile());
192     }
193 
194     @Override
195     protected float getDepthUnchecked(Context context) {
196         // TODO(178661709): revert to always scaled
197         if (enableScalingRevealHomeAnimation()) {
198             return SystemProperties.getBoolean("ro.launcher.depth.overview", true)
199                     ? BaseDepthController.DEPTH_70_PERCENT
200                     : BaseDepthController.DEPTH_0_PERCENT;
201         } else {
202             return SystemProperties.getBoolean("ro.launcher.depth.overview", true) ? 1 : 0;
203         }
204     }
205 
206     @Override
207     public void onBackInvoked(Launcher launcher) {
208         RecentsView recentsView = launcher.getOverviewPanel();
209         TaskView taskView = recentsView.getRunningTaskView();
210         if (taskView != null) {
211             if (recentsView.isTaskViewFullyVisible(taskView)) {
212                 taskView.launchTasks();
213             } else {
214                 recentsView.snapToPage(recentsView.indexOfChild(taskView));
215             }
216         } else {
217             super.onBackInvoked(launcher);
218         }
219     }
220 
221     public static OverviewState newBackgroundState(int id) {
222         return new BackgroundAppState(id);
223     }
224 
225     public static OverviewState newSwitchState(int id) {
226         return new QuickSwitchState(id);
227     }
228 
229     /**
230      *  New Overview substate that represents the overview in modal mode (one task shown on its own)
231      */
232     public static OverviewState newModalTaskState(int id) {
233         return new OverviewModalTaskState(id);
234     }
235 
236     /**
237      * New Overview substate representing state where 1 app for split screen has been selected and
238      * pinned and user is selecting the second one
239      */
240     public static OverviewState newSplitSelectState(int id) {
241         return new SplitScreenSelectState(id);
242     }
243 }
244