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