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