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