• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 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 
17 package com.android.systemui.recents;
18 
19 import android.app.ActivityManager;
20 import android.content.Context;
21 import android.content.SharedPreferences;
22 import android.content.res.Configuration;
23 import android.content.res.Resources;
24 import android.graphics.Rect;
25 import android.provider.Settings;
26 import android.util.DisplayMetrics;
27 import android.util.TypedValue;
28 import android.view.animation.AnimationUtils;
29 import android.view.animation.Interpolator;
30 import com.android.systemui.R;
31 import com.android.systemui.recents.misc.Console;
32 import com.android.systemui.recents.misc.SystemServicesProxy;
33 
34 
35 /** A static Recents configuration for the current context
36  * NOTE: We should not hold any references to a Context from a static instance */
37 public class RecentsConfiguration {
38     static RecentsConfiguration sInstance;
39     static int sPrevConfigurationHashCode;
40 
41     /** Animations */
42     public float animationPxMovementPerSecond;
43 
44     /** Interpolators */
45     public Interpolator fastOutSlowInInterpolator;
46     public Interpolator fastOutLinearInInterpolator;
47     public Interpolator linearOutSlowInInterpolator;
48     public Interpolator quintOutInterpolator;
49 
50     /** Filtering */
51     public int filteringCurrentViewsAnimDuration;
52     public int filteringNewViewsAnimDuration;
53 
54     /** Insets */
55     public Rect systemInsets = new Rect();
56     public Rect displayRect = new Rect();
57 
58     /** Layout */
59     boolean isLandscape;
60     boolean hasTransposedSearchBar;
61     boolean hasTransposedNavBar;
62 
63     /** Loading */
64     public int maxNumTasksToLoad;
65 
66     /** Search bar */
67     int searchBarAppWidgetId = -1;
68     public int searchBarSpaceHeightPx;
69 
70     /** Task stack */
71     public int taskStackScrollDuration;
72     public int taskStackMaxDim;
73     public int taskStackTopPaddingPx;
74     public float taskStackWidthPaddingPct;
75     public float taskStackOverscrollPct;
76 
77     /** Task view animation and styles */
78     public int taskViewEnterFromHomeDelay;
79     public int taskViewEnterFromHomeDuration;
80     public int taskViewEnterFromHomeStaggerDelay;
81     public int taskViewEnterFromHomeStaggerDuration;
82     public int taskViewExitToHomeDuration;
83     public int taskViewRemoveAnimDuration;
84     public int taskViewRemoveAnimTranslationXPx;
85     public int taskViewTranslationZMinPx;
86     public int taskViewTranslationZMaxPx;
87     public int taskViewRoundedCornerRadiusPx;
88     public int taskViewHighlightPx;
89     public int taskViewAffiliateGroupEnterOffsetPx;
90     public float taskViewThumbnailAlpha;
91 
92     /** Task bar colors */
93     public int taskBarViewDefaultBackgroundColor;
94     public int taskBarViewLightTextColor;
95     public int taskBarViewDarkTextColor;
96     public int taskBarViewHighlightColor;
97     public float taskBarViewAffiliationColorMinAlpha;
98 
99     /** Task bar size & animations */
100     public int taskBarHeight;
101     public int taskBarEnterAnimDuration;
102     public int taskBarEnterAnimDelay;
103     public int taskBarExitAnimDuration;
104     public int taskBarDismissDozeDelaySeconds;
105 
106     /** Lock to app */
107     public int taskViewLockToAppButtonHeight;
108     public int taskViewLockToAppShortAnimDuration;
109     public int taskViewLockToAppLongAnimDuration;
110 
111     /** Nav bar scrim */
112     public int navBarScrimEnterDuration;
113 
114     /** Launch states */
115     public boolean launchedWithAltTab;
116     public boolean launchedWithNoRecentTasks;
117     public boolean launchedFromAppWithThumbnail;
118     public boolean launchedFromAppWithScreenshot;
119     public boolean launchedFromHome;
120     public int launchedToTaskId;
121 
122     /** Misc **/
123     public boolean useHardwareLayers;
124     public int altTabKeyDelay;
125     public boolean fakeShadows;
126 
127     /** Dev options and global settings */
128     public boolean lockToAppEnabled;
129     public boolean developerOptionsEnabled;
130     public boolean debugModeEnabled;
131 
132     /** Private constructor */
RecentsConfiguration(Context context)133     private RecentsConfiguration(Context context) {
134         // Properties that don't have to be reloaded with each configuration change can be loaded
135         // here.
136 
137         // Interpolators
138         fastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
139                 com.android.internal.R.interpolator.fast_out_slow_in);
140         fastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context,
141                 com.android.internal.R.interpolator.fast_out_linear_in);
142         linearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
143                 com.android.internal.R.interpolator.linear_out_slow_in);
144         quintOutInterpolator = AnimationUtils.loadInterpolator(context,
145                 com.android.internal.R.interpolator.decelerate_quint);
146     }
147 
148     /** Updates the configuration to the current context */
reinitialize(Context context, SystemServicesProxy ssp)149     public static RecentsConfiguration reinitialize(Context context, SystemServicesProxy ssp) {
150         if (sInstance == null) {
151             sInstance = new RecentsConfiguration(context);
152         }
153         int configHashCode = context.getResources().getConfiguration().hashCode();
154         if (sPrevConfigurationHashCode != configHashCode) {
155             sInstance.update(context);
156             sPrevConfigurationHashCode = configHashCode;
157         }
158         sInstance.updateOnReinitialize(context, ssp);
159         return sInstance;
160     }
161 
162     /** Returns the current recents configuration */
getInstance()163     public static RecentsConfiguration getInstance() {
164         return sInstance;
165     }
166 
167     /** Updates the state, given the specified context */
update(Context context)168     void update(Context context) {
169         SharedPreferences settings = context.getSharedPreferences(context.getPackageName(), 0);
170         Resources res = context.getResources();
171         DisplayMetrics dm = res.getDisplayMetrics();
172 
173         // Debug mode
174         debugModeEnabled = settings.getBoolean(Constants.Values.App.Key_DebugModeEnabled, false);
175         if (debugModeEnabled) {
176             Console.Enabled = true;
177         }
178 
179         // Layout
180         isLandscape = res.getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE;
181         hasTransposedSearchBar = res.getBoolean(R.bool.recents_has_transposed_search_bar);
182         hasTransposedNavBar = res.getBoolean(R.bool.recents_has_transposed_nav_bar);
183 
184         // Insets
185         displayRect.set(0, 0, dm.widthPixels, dm.heightPixels);
186 
187         // Animations
188         animationPxMovementPerSecond =
189                 res.getDimensionPixelSize(R.dimen.recents_animation_movement_in_dps_per_second);
190 
191         // Filtering
192         filteringCurrentViewsAnimDuration =
193                 res.getInteger(R.integer.recents_filter_animate_current_views_duration);
194         filteringNewViewsAnimDuration =
195                 res.getInteger(R.integer.recents_filter_animate_new_views_duration);
196 
197         // Loading
198         maxNumTasksToLoad = ActivityManager.getMaxRecentTasksStatic();
199 
200         // Search Bar
201         searchBarSpaceHeightPx = res.getDimensionPixelSize(R.dimen.recents_search_bar_space_height);
202         searchBarAppWidgetId = settings.getInt(Constants.Values.App.Key_SearchAppWidgetId, -1);
203 
204         // Task stack
205         taskStackScrollDuration =
206                 res.getInteger(R.integer.recents_animate_task_stack_scroll_duration);
207         TypedValue widthPaddingPctValue = new TypedValue();
208         res.getValue(R.dimen.recents_stack_width_padding_percentage, widthPaddingPctValue, true);
209         taskStackWidthPaddingPct = widthPaddingPctValue.getFloat();
210         TypedValue stackOverscrollPctValue = new TypedValue();
211         res.getValue(R.dimen.recents_stack_overscroll_percentage, stackOverscrollPctValue, true);
212         taskStackOverscrollPct = stackOverscrollPctValue.getFloat();
213         taskStackMaxDim = res.getInteger(R.integer.recents_max_task_stack_view_dim);
214         taskStackTopPaddingPx = res.getDimensionPixelSize(R.dimen.recents_stack_top_padding);
215 
216         // Task view animation and styles
217         taskViewEnterFromHomeDelay =
218                 res.getInteger(R.integer.recents_animate_task_enter_from_home_delay);
219         taskViewEnterFromHomeDuration =
220                 res.getInteger(R.integer.recents_animate_task_enter_from_home_duration);
221         taskViewEnterFromHomeStaggerDelay =
222                 res.getInteger(R.integer.recents_animate_task_enter_from_home_stagger_delay);
223         taskViewExitToHomeDuration =
224                 res.getInteger(R.integer.recents_animate_task_exit_to_home_duration);
225         taskViewRemoveAnimDuration =
226                 res.getInteger(R.integer.recents_animate_task_view_remove_duration);
227         taskViewRemoveAnimTranslationXPx =
228                 res.getDimensionPixelSize(R.dimen.recents_task_view_remove_anim_translation_x);
229         taskViewRoundedCornerRadiusPx =
230                 res.getDimensionPixelSize(R.dimen.recents_task_view_rounded_corners_radius);
231         taskViewHighlightPx = res.getDimensionPixelSize(R.dimen.recents_task_view_highlight);
232         taskViewTranslationZMinPx = res.getDimensionPixelSize(R.dimen.recents_task_view_z_min);
233         taskViewTranslationZMaxPx = res.getDimensionPixelSize(R.dimen.recents_task_view_z_max);
234         taskViewAffiliateGroupEnterOffsetPx =
235                 res.getDimensionPixelSize(R.dimen.recents_task_view_affiliate_group_enter_offset);
236         TypedValue thumbnailAlphaValue = new TypedValue();
237         res.getValue(R.dimen.recents_task_view_thumbnail_alpha, thumbnailAlphaValue, true);
238         taskViewThumbnailAlpha = thumbnailAlphaValue.getFloat();
239 
240         // Task bar colors
241         taskBarViewDefaultBackgroundColor =
242                 res.getColor(R.color.recents_task_bar_default_background_color);
243         taskBarViewLightTextColor =
244                 res.getColor(R.color.recents_task_bar_light_text_color);
245         taskBarViewDarkTextColor =
246                 res.getColor(R.color.recents_task_bar_dark_text_color);
247         taskBarViewHighlightColor =
248                 res.getColor(R.color.recents_task_bar_highlight_color);
249         TypedValue affMinAlphaPctValue = new TypedValue();
250         res.getValue(R.dimen.recents_task_affiliation_color_min_alpha_percentage, affMinAlphaPctValue, true);
251         taskBarViewAffiliationColorMinAlpha = affMinAlphaPctValue.getFloat();
252 
253         // Task bar size & animations
254         taskBarHeight = res.getDimensionPixelSize(R.dimen.recents_task_bar_height);
255         taskBarEnterAnimDuration =
256                 res.getInteger(R.integer.recents_animate_task_bar_enter_duration);
257         taskBarEnterAnimDelay =
258                 res.getInteger(R.integer.recents_animate_task_bar_enter_delay);
259         taskBarExitAnimDuration =
260                 res.getInteger(R.integer.recents_animate_task_bar_exit_duration);
261         taskBarDismissDozeDelaySeconds =
262                 res.getInteger(R.integer.recents_task_bar_dismiss_delay_seconds);
263 
264         // Lock to app
265         taskViewLockToAppButtonHeight =
266                 res.getDimensionPixelSize(R.dimen.recents_task_view_lock_to_app_button_height);
267         taskViewLockToAppShortAnimDuration =
268                 res.getInteger(R.integer.recents_animate_lock_to_app_button_short_duration);
269         taskViewLockToAppLongAnimDuration =
270                 res.getInteger(R.integer.recents_animate_lock_to_app_button_long_duration);
271 
272         // Nav bar scrim
273         navBarScrimEnterDuration =
274                 res.getInteger(R.integer.recents_nav_bar_scrim_enter_duration);
275 
276         // Misc
277         useHardwareLayers = res.getBoolean(R.bool.config_recents_use_hardware_layers);
278         altTabKeyDelay = res.getInteger(R.integer.recents_alt_tab_key_delay);
279         fakeShadows = res.getBoolean(R.bool.config_recents_fake_shadows);
280     }
281 
282     /** Updates the system insets */
updateSystemInsets(Rect insets)283     public void updateSystemInsets(Rect insets) {
284         systemInsets.set(insets);
285     }
286 
287     /** Updates the search bar app widget */
updateSearchBarAppWidgetId(Context context, int appWidgetId)288     public void updateSearchBarAppWidgetId(Context context, int appWidgetId) {
289         searchBarAppWidgetId = appWidgetId;
290         SharedPreferences settings = context.getSharedPreferences(context.getPackageName(), 0);
291         settings.edit().putInt(Constants.Values.App.Key_SearchAppWidgetId,
292                 appWidgetId).apply();
293     }
294 
295     /** Updates the states that need to be re-read whenever we re-initialize. */
updateOnReinitialize(Context context, SystemServicesProxy ssp)296     void updateOnReinitialize(Context context, SystemServicesProxy ssp) {
297         // Check if the developer options are enabled
298         developerOptionsEnabled = ssp.getGlobalSetting(context,
299                 Settings.Global.DEVELOPMENT_SETTINGS_ENABLED) != 0;
300         lockToAppEnabled = ssp.getSystemSetting(context,
301                 Settings.System.LOCK_TO_APP_ENABLED) != 0;
302     }
303 
304     /** Called when the configuration has changed, and we want to reset any configuration specific
305      * members. */
updateOnConfigurationChange()306     public void updateOnConfigurationChange() {
307         launchedWithAltTab = false;
308         launchedWithNoRecentTasks = false;
309         launchedFromAppWithThumbnail = false;
310         launchedFromAppWithScreenshot = false;
311         launchedFromHome = false;
312         launchedToTaskId = -1;
313     }
314 
315     /** Returns whether the search bar app widget exists. */
hasSearchBarAppWidget()316     public boolean hasSearchBarAppWidget() {
317         return searchBarAppWidgetId >= 0;
318     }
319 
320     /** Returns whether the status bar scrim should be animated when shown for the first time. */
shouldAnimateStatusBarScrim()321     public boolean shouldAnimateStatusBarScrim() {
322         return launchedFromHome;
323     }
324 
325     /** Returns whether the status bar scrim should be visible. */
hasStatusBarScrim()326     public boolean hasStatusBarScrim() {
327         return !launchedWithNoRecentTasks;
328     }
329 
330     /** Returns whether the nav bar scrim should be animated when shown for the first time. */
shouldAnimateNavBarScrim()331     public boolean shouldAnimateNavBarScrim() {
332         return true;
333     }
334 
335     /** Returns whether the nav bar scrim should be visible. */
hasNavBarScrim()336     public boolean hasNavBarScrim() {
337         // Only show the scrim if we have recent tasks, and if the nav bar is not transposed
338         return !launchedWithNoRecentTasks && (!hasTransposedNavBar || !isLandscape);
339     }
340 
341     /** Returns whether the current layout is horizontal. */
hasHorizontalLayout()342     public boolean hasHorizontalLayout() {
343         return isLandscape && hasTransposedSearchBar;
344     }
345 
346     /**
347      * Returns the task stack bounds in the current orientation. These bounds do not account for
348      * the system insets.
349      */
getTaskStackBounds(int windowWidth, int windowHeight, int topInset, int rightInset, Rect taskStackBounds)350     public void getTaskStackBounds(int windowWidth, int windowHeight, int topInset, int rightInset,
351                                    Rect taskStackBounds) {
352         Rect searchBarBounds = new Rect();
353         getSearchBarBounds(windowWidth, windowHeight, topInset, searchBarBounds);
354         if (isLandscape && hasTransposedSearchBar) {
355             // In landscape, the search bar appears on the left, but we overlay it on top
356             taskStackBounds.set(0, topInset, windowWidth - rightInset, windowHeight);
357         } else {
358             // In portrait, the search bar appears on the top (which already has the inset)
359             taskStackBounds.set(0, searchBarBounds.bottom, windowWidth, windowHeight);
360         }
361     }
362 
363     /**
364      * Returns the search bar bounds in the current orientation.  These bounds do not account for
365      * the system insets.
366      */
getSearchBarBounds(int windowWidth, int windowHeight, int topInset, Rect searchBarSpaceBounds)367     public void getSearchBarBounds(int windowWidth, int windowHeight, int topInset,
368                                    Rect searchBarSpaceBounds) {
369         // Return empty rects if search is not enabled
370         int searchBarSize = searchBarSpaceHeightPx;
371         if (!Constants.DebugFlags.App.EnableSearchLayout || !hasSearchBarAppWidget()) {
372             searchBarSize = 0;
373         }
374 
375         if (isLandscape && hasTransposedSearchBar) {
376             // In landscape, the search bar appears on the left
377             searchBarSpaceBounds.set(0, topInset, searchBarSize, windowHeight);
378         } else {
379             // In portrait, the search bar appears on the top
380             searchBarSpaceBounds.set(0, topInset, windowWidth, topInset + searchBarSize);
381         }
382     }
383 }
384