RecentsConfiguration.java revision 96d704186621f6310e0e7d39db57caff67baa96c
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.SharedPreferences; 22import android.content.res.Configuration; 23import android.content.res.Resources; 24import android.graphics.Rect; 25import android.provider.Settings; 26import android.util.DisplayMetrics; 27import android.util.TypedValue; 28import android.view.animation.AnimationUtils; 29import android.view.animation.Interpolator; 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 /** 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 /** Task view animation and styles */ 90 public int taskViewEnterFromHomeDelay; 91 public int taskViewEnterFromHomeDuration; 92 public int taskViewEnterFromHomeStaggerDelay; 93 public int taskViewEnterFromHomeStaggerDuration; 94 public int taskViewExitToHomeDuration; 95 public int taskViewRemoveAnimDuration; 96 public int taskViewRemoveAnimTranslationXPx; 97 public int taskViewTranslationZMinPx; 98 public int taskViewTranslationZMaxPx; 99 public int taskViewRoundedCornerRadiusPx; 100 public int taskViewHighlightPx; 101 public int taskViewAffiliateGroupEnterOffsetPx; 102 public float taskViewThumbnailAlpha; 103 104 /** Task bar colors */ 105 public int taskBarViewDefaultBackgroundColor; 106 public int taskBarViewLightTextColor; 107 public int taskBarViewDarkTextColor; 108 public int taskBarViewHighlightColor; 109 public float taskBarViewAffiliationColorMinAlpha; 110 111 /** Task bar size & animations */ 112 public int taskBarHeight; 113 public int taskBarEnterAnimDuration; 114 public int taskBarEnterAnimDelay; 115 public int taskBarExitAnimDuration; 116 public int taskBarDismissDozeDelaySeconds; 117 118 /** Lock to app */ 119 public int taskViewLockToAppButtonHeight; 120 public int taskViewLockToAppShortAnimDuration; 121 public int taskViewLockToAppLongAnimDuration; 122 123 /** Nav bar scrim */ 124 public int navBarScrimEnterDuration; 125 126 /** Launch states */ 127 public boolean launchedWithAltTab; 128 public boolean launchedWithNoRecentTasks; 129 public boolean launchedFromAppWithThumbnail; 130 public boolean launchedFromHome; 131 public boolean launchedReuseTaskStackViews; 132 public int launchedToTaskId; 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 // Task view animation and styles 230 taskViewEnterFromHomeDelay = 231 res.getInteger(R.integer.recents_animate_task_enter_from_home_delay); 232 taskViewEnterFromHomeDuration = 233 res.getInteger(R.integer.recents_animate_task_enter_from_home_duration); 234 taskViewEnterFromHomeStaggerDelay = 235 res.getInteger(R.integer.recents_animate_task_enter_from_home_stagger_delay); 236 taskViewExitToHomeDuration = 237 res.getInteger(R.integer.recents_animate_task_exit_to_home_duration); 238 taskViewRemoveAnimDuration = 239 res.getInteger(R.integer.recents_animate_task_view_remove_duration); 240 taskViewRemoveAnimTranslationXPx = 241 res.getDimensionPixelSize(R.dimen.recents_task_view_remove_anim_translation_x); 242 taskViewRoundedCornerRadiusPx = 243 res.getDimensionPixelSize(R.dimen.recents_task_view_rounded_corners_radius); 244 taskViewHighlightPx = res.getDimensionPixelSize(R.dimen.recents_task_view_highlight); 245 taskViewTranslationZMinPx = res.getDimensionPixelSize(R.dimen.recents_task_view_z_min); 246 taskViewTranslationZMaxPx = res.getDimensionPixelSize(R.dimen.recents_task_view_z_max); 247 taskViewAffiliateGroupEnterOffsetPx = 248 res.getDimensionPixelSize(R.dimen.recents_task_view_affiliate_group_enter_offset); 249 TypedValue thumbnailAlphaValue = new TypedValue(); 250 res.getValue(R.dimen.recents_task_view_thumbnail_alpha, thumbnailAlphaValue, true); 251 taskViewThumbnailAlpha = thumbnailAlphaValue.getFloat(); 252 253 // Task bar colors 254 taskBarViewDefaultBackgroundColor = 255 res.getColor(R.color.recents_task_bar_default_background_color); 256 taskBarViewLightTextColor = 257 res.getColor(R.color.recents_task_bar_light_text_color); 258 taskBarViewDarkTextColor = 259 res.getColor(R.color.recents_task_bar_dark_text_color); 260 taskBarViewHighlightColor = 261 res.getColor(R.color.recents_task_bar_highlight_color); 262 TypedValue affMinAlphaPctValue = new TypedValue(); 263 res.getValue(R.dimen.recents_task_affiliation_color_min_alpha_percentage, affMinAlphaPctValue, true); 264 taskBarViewAffiliationColorMinAlpha = affMinAlphaPctValue.getFloat(); 265 266 // Task bar size & animations 267 taskBarHeight = res.getDimensionPixelSize(R.dimen.recents_task_bar_height); 268 taskBarEnterAnimDuration = 269 res.getInteger(R.integer.recents_animate_task_bar_enter_duration); 270 taskBarEnterAnimDelay = 271 res.getInteger(R.integer.recents_animate_task_bar_enter_delay); 272 taskBarExitAnimDuration = 273 res.getInteger(R.integer.recents_animate_task_bar_exit_duration); 274 taskBarDismissDozeDelaySeconds = 275 res.getInteger(R.integer.recents_task_bar_dismiss_delay_seconds); 276 277 // Lock to app 278 taskViewLockToAppButtonHeight = 279 res.getDimensionPixelSize(R.dimen.recents_task_view_lock_to_app_button_height); 280 taskViewLockToAppShortAnimDuration = 281 res.getInteger(R.integer.recents_animate_lock_to_app_button_short_duration); 282 taskViewLockToAppLongAnimDuration = 283 res.getInteger(R.integer.recents_animate_lock_to_app_button_long_duration); 284 285 // Nav bar scrim 286 navBarScrimEnterDuration = 287 res.getInteger(R.integer.recents_nav_bar_scrim_enter_duration); 288 289 // Misc 290 useHardwareLayers = res.getBoolean(R.bool.config_recents_use_hardware_layers); 291 altTabKeyDelay = res.getInteger(R.integer.recents_alt_tab_key_delay); 292 fakeShadows = res.getBoolean(R.bool.config_recents_fake_shadows); 293 svelteLevel = res.getInteger(R.integer.recents_svelte_level); 294 } 295 296 /** Updates the system insets */ 297 public void updateSystemInsets(Rect insets) { 298 systemInsets.set(insets); 299 } 300 301 /** Updates the search bar app widget */ 302 public void updateSearchBarAppWidgetId(Context context, int appWidgetId) { 303 searchBarAppWidgetId = appWidgetId; 304 SharedPreferences settings = context.getSharedPreferences(context.getPackageName(), 0); 305 settings.edit().putInt(Constants.Values.App.Key_SearchAppWidgetId, 306 appWidgetId).apply(); 307 } 308 309 /** Updates the states that need to be re-read whenever we re-initialize. */ 310 void updateOnReinitialize(Context context, SystemServicesProxy ssp) { 311 // Check if the developer options are enabled 312 developerOptionsEnabled = ssp.getGlobalSetting(context, 313 Settings.Global.DEVELOPMENT_SETTINGS_ENABLED) != 0; 314 lockToAppEnabled = ssp.getSystemSetting(context, 315 Settings.System.LOCK_TO_APP_ENABLED) != 0; 316 } 317 318 /** Called when the configuration has changed, and we want to reset any configuration specific 319 * members. */ 320 public void updateOnConfigurationChange() { 321 launchedWithAltTab = false; 322 launchedWithNoRecentTasks = false; 323 launchedFromAppWithThumbnail = false; 324 launchedFromHome = false; 325 launchedReuseTaskStackViews = false; 326 launchedToTaskId = -1; 327 } 328 329 /** Returns whether the search bar app widget exists. */ 330 public boolean hasSearchBarAppWidget() { 331 return searchBarAppWidgetId >= 0; 332 } 333 334 /** Returns whether the status bar scrim should be animated when shown for the first time. */ 335 public boolean shouldAnimateStatusBarScrim() { 336 return launchedFromHome; 337 } 338 339 /** Returns whether the status bar scrim should be visible. */ 340 public boolean hasStatusBarScrim() { 341 return !launchedWithNoRecentTasks; 342 } 343 344 /** Returns whether the nav bar scrim should be animated when shown for the first time. */ 345 public boolean shouldAnimateNavBarScrim() { 346 return true; 347 } 348 349 /** Returns whether the nav bar scrim should be visible. */ 350 public boolean hasNavBarScrim() { 351 // Only show the scrim if we have recent tasks, and if the nav bar is not transposed 352 return !launchedWithNoRecentTasks && (!hasTransposedNavBar || !isLandscape); 353 } 354 355 /** Returns whether the current layout is horizontal. */ 356 public boolean hasHorizontalLayout() { 357 return isLandscape && hasTransposedSearchBar; 358 } 359 360 /** 361 * Returns the task stack bounds in the current orientation. These bounds do not account for 362 * the system insets. 363 */ 364 public void getTaskStackBounds(int windowWidth, int windowHeight, int topInset, int rightInset, 365 Rect taskStackBounds) { 366 Rect searchBarBounds = new Rect(); 367 getSearchBarBounds(windowWidth, windowHeight, topInset, searchBarBounds); 368 if (isLandscape && hasTransposedSearchBar) { 369 // In landscape, the search bar appears on the left, but we overlay it on top 370 taskStackBounds.set(0, topInset, windowWidth - rightInset, windowHeight); 371 } else { 372 // In portrait, the search bar appears on the top (which already has the inset) 373 taskStackBounds.set(0, searchBarBounds.bottom, windowWidth, windowHeight); 374 } 375 } 376 377 /** 378 * Returns the search bar bounds in the current orientation. These bounds do not account for 379 * the system insets. 380 */ 381 public void getSearchBarBounds(int windowWidth, int windowHeight, int topInset, 382 Rect searchBarSpaceBounds) { 383 // Return empty rects if search is not enabled 384 int searchBarSize = searchBarSpaceHeightPx; 385 if (!Constants.DebugFlags.App.EnableSearchLayout || !hasSearchBarAppWidget()) { 386 searchBarSize = 0; 387 } 388 389 if (isLandscape && hasTransposedSearchBar) { 390 // In landscape, the search bar appears on the left 391 searchBarSpaceBounds.set(0, topInset, searchBarSize, windowHeight); 392 } else { 393 // In portrait, the search bar appears on the top 394 searchBarSpaceBounds.set(0, topInset, windowWidth, topInset + searchBarSize); 395 } 396 } 397} 398