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