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     /** 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 */
    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 */
    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 */
    163     public static RecentsConfiguration getInstance() {
    164         return sInstance;
    165     }
    166 
    167     /** Updates the state, given the specified 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 */
    283     public void updateSystemInsets(Rect insets) {
    284         systemInsets.set(insets);
    285     }
    286 
    287     /** Updates the search bar app widget */
    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. */
    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. */
    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. */
    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. */
    321     public boolean shouldAnimateStatusBarScrim() {
    322         return launchedFromHome;
    323     }
    324 
    325     /** Returns whether the status bar scrim should be visible. */
    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. */
    331     public boolean shouldAnimateNavBarScrim() {
    332         return true;
    333     }
    334 
    335     /** Returns whether the nav bar scrim should be visible. */
    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. */
    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      */
    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      */
    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