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