Moving resources out of ResourceConfiguration.

- We can no longer make assumptions about the ability to
  get resources for the RecentsActivity before the activity
  is launched (the configuration of the launched activity
  can differ than the current configuration if a window
  is docked).  As such, we reduce RecentsConfiguration
  to the set of values that are context agnostic, or can
  be calculated directly given an application context.
  This ensures that we will continue to be able to compute
  the target task bounds given any context.

Change-Id: I423c90635eb294aa2d78a6f56771b98ee2b9d5e4
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
index 2893b99..6ef1ada 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -19,9 +19,6 @@
     <!-- thickness (width) of the navigation bar on phones that require it -->
     <dimen name="navigation_bar_size">@*android:dimen/navigation_bar_width</dimen>
 
-    <!-- The side padding for the task stack as a percentage of the width. -->
-    <item name="recents_stack_width_padding_percentage" format="float" type="dimen">0.26</item>
-
     <!-- Standard notification width + gravity -->
     <dimen name="notification_panel_width">@dimen/standard_notification_panel_width</dimen>
     <integer name="notification_panel_layout_gravity">@integer/standard_notification_panel_layout_gravity</integer>
diff --git a/packages/SystemUI/res/values-sw600dp-land/dimens.xml b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
index 81ca86b..f084bc2 100644
--- a/packages/SystemUI/res/values-sw600dp-land/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
@@ -16,10 +16,6 @@
 */
 -->
 <resources>
-    <!-- Recent Applications parameters -->
-    <!-- The side padding for the task stack as a percentage of the width. -->
-    <item name="recents_stack_width_padding_percentage" format="float" type="dimen">0.25</item>
-
     <fraction name="keyguard_clock_y_fraction_max">37%</fraction>
     <fraction name="keyguard_clock_y_fraction_min">20%</fraction>
 
diff --git a/packages/SystemUI/res/values-sw600dp/config.xml b/packages/SystemUI/res/values-sw600dp/config.xml
index 83477c0..4f6d209 100644
--- a/packages/SystemUI/res/values-sw600dp/config.xml
+++ b/packages/SystemUI/res/values-sw600dp/config.xml
@@ -32,9 +32,4 @@
 
     <!-- Set to true to enable the user switcher on the keyguard. -->
     <bool name="config_keyguardUserSwitcher">true</bool>
-
-    <!-- Transposes the search bar layout in landscape. -->
-    <bool name="recents_has_transposed_search_bar">true</bool>
-    <!-- Transposes the nav bar in landscape (only used for purposes of layout). -->
-    <bool name="recents_has_transposed_nav_bar">false</bool>
 </resources>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index 6deb818..49dbac2 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -39,12 +39,6 @@
     <!-- On tablets this is just the close_handle_height -->
     <dimen name="peek_height">@dimen/close_handle_height</dimen>
 
-    <!-- The side padding for the task stack as a percentage of the width. -->
-    <item name="recents_stack_width_padding_percentage" format="float" type="dimen">0.075</item>
-
-    <!-- The height of the search bar space. -->
-    <dimen name="recents_search_bar_space_height">72dp</dimen>
-
     <!-- The fraction of the screen height where the clock on the Keyguard has its center. The
          max value is used when no notifications are displaying, and the min value is when the
          highest possible number of notifications are showing. -->
diff --git a/packages/SystemUI/res/values-sw720dp/config.xml b/packages/SystemUI/res/values-sw720dp/config.xml
index 1efae42..64e2760 100644
--- a/packages/SystemUI/res/values-sw720dp/config.xml
+++ b/packages/SystemUI/res/values-sw720dp/config.xml
@@ -25,10 +25,5 @@
     <!-- The maximum count of notifications on Keyguard. The rest will be collapsed in an overflow
          card. -->
     <integer name="keyguard_max_notification_count">5</integer>
-
-    <!-- Transposes the search bar layout in landscape. -->
-    <bool name="recents_has_transposed_search_bar">false</bool>
-    <!-- Transposes the nav bar in landscape (only used for purposes of layout). -->
-    <bool name="recents_has_transposed_nav_bar">false</bool>
 </resources>
 
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index f28c9d3..1d19589 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -189,12 +189,6 @@
     <!-- The delay to enforce between each alt-tab key press. -->
     <integer name="recents_alt_tab_key_delay">200</integer>
 
-    <!-- Transposes the search bar layout in landscape. -->
-    <bool name="recents_has_transposed_search_bar">true</bool>
-
-    <!-- Transposes the nav bar in landscape (only used for purposes of layout). -->
-    <bool name="recents_has_transposed_nav_bar">true</bool>
-
     <!-- Svelte specific logic, see RecentsConfiguration.SVELTE_* constants. -->
     <integer name="recents_svelte_level">0</integer>
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index a3e89f2..3e23ed8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -38,7 +38,6 @@
 import android.view.Display;
 import android.view.LayoutInflater;
 import android.view.View;
-
 import com.android.internal.logging.MetricsLogger;
 import com.android.systemui.Prefs;
 import com.android.systemui.R;
@@ -500,9 +499,8 @@
         mStatusBarHeight = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
         mNavBarHeight = res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_height);
         mNavBarWidth = res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_width);
-        // TODO: We can't rely on this anymore since the activity context will yield different
-        //      resources while multiwindow is enabled
-        mConfig = RecentsConfiguration.reinitialize(mContext, mSystemServicesProxy);
+        mConfig = RecentsConfiguration.initialize(mContext, mSystemServicesProxy);
+        mConfig.update(mContext, mSystemServicesProxy, mSystemServicesProxy.getWindowRect());
         mConfig.updateOnConfigurationChange();
         Rect searchBarBounds = new Rect();
         // Try and pre-emptively bind the search widget on startup to ensure that we
@@ -515,7 +513,7 @@
         mConfig.getAvailableTaskStackBounds(windowRect,
                 mStatusBarHeight, (mConfig.hasTransposedNavBar ? mNavBarWidth : 0), searchBarBounds,
                 mTaskStackBounds);
-        if (mConfig.isLandscape && mConfig.hasTransposedNavBar) {
+        if (mConfig.hasTransposedNavBar) {
             mSystemInsets.set(0, mStatusBarHeight, mNavBarWidth, 0);
         } else {
             mSystemInsets.set(0, mStatusBarHeight, 0, mNavBarHeight);
@@ -740,7 +738,7 @@
         // Don't reinitialize the configuration completely here, since it has the wrong context,
         // only update the parts that we can get from any context
         RecentsConfiguration config = RecentsConfiguration.getInstance();
-        config.reinitializeWithApplicationContext(mContext, mSystemServicesProxy);
+        config.update(mContext, mSystemServicesProxy, mSystemServicesProxy.getWindowRect());
 
         if (sInstanceLoadPlan == null) {
             // Create a new load plan if onPreloadRecents() was never triggered
@@ -816,15 +814,16 @@
             ActivityOptions opts, boolean fromHome, boolean fromSearchHome, boolean fromThumbnail,
             TaskStackViewLayoutAlgorithm.VisibilityReport vr) {
         // Update the configuration based on the launch options
-        mConfig.launchedFromHome = fromSearchHome || fromHome;
-        mConfig.launchedFromSearchHome = fromSearchHome;
-        mConfig.launchedFromAppWithThumbnail = fromThumbnail;
-        mConfig.launchedToTaskId = (topTask != null) ? topTask.id : -1;
-        mConfig.launchedWithAltTab = mTriggeredFromAltTab;
-        mConfig.launchedReuseTaskStackViews = mCanReuseTaskStackViews;
-        mConfig.launchedNumVisibleTasks = vr.numVisibleTasks;
-        mConfig.launchedNumVisibleThumbnails = vr.numVisibleThumbnails;
-        mConfig.launchedHasConfigurationChanged = false;
+        RecentsActivityLaunchState launchState = mConfig.getLaunchState();
+        launchState.launchedFromHome = fromSearchHome || fromHome;
+        launchState.launchedFromSearchHome = fromSearchHome;
+        launchState.launchedFromAppWithThumbnail = fromThumbnail;
+        launchState.launchedToTaskId = (topTask != null) ? topTask.id : -1;
+        launchState.launchedWithAltTab = mTriggeredFromAltTab;
+        launchState.launchedReuseTaskStackViews = mCanReuseTaskStackViews;
+        launchState.launchedNumVisibleTasks = vr.numVisibleTasks;
+        launchState.launchedNumVisibleThumbnails = vr.numVisibleThumbnails;
+        launchState.launchedHasConfigurationChanged = false;
 
         Intent intent = new Intent(sToggleRecentsAction);
         intent.setClassName(sRecentsPackage, sRecentsActivity);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index c53e573..9ce6b2c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -25,17 +25,13 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.res.Configuration;
 import android.os.Bundle;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.view.KeyEvent;
 import android.view.View;
 import android.view.ViewStub;
-import android.widget.Toast;
-
 import com.android.internal.logging.MetricsLogger;
-import com.android.systemui.Prefs;
 import com.android.systemui.R;
 import com.android.systemui.recents.misc.Console;
 import com.android.systemui.recents.misc.ReferenceCountedTrigger;
@@ -182,18 +178,19 @@
         }
 
         // Start loading tasks according to the load plan
+        RecentsActivityLaunchState launchState = mConfig.getLaunchState();
         if (!plan.hasTasks()) {
-            loader.preloadTasks(plan, mConfig.launchedFromHome);
+            loader.preloadTasks(plan, launchState.launchedFromHome);
         }
         RecentsTaskLoadPlan.Options loadOpts = new RecentsTaskLoadPlan.Options();
-        loadOpts.runningTaskId = mConfig.launchedToTaskId;
-        loadOpts.numVisibleTasks = mConfig.launchedNumVisibleTasks;
-        loadOpts.numVisibleTaskThumbnails = mConfig.launchedNumVisibleThumbnails;
+        loadOpts.runningTaskId = launchState.launchedToTaskId;
+        loadOpts.numVisibleTasks = launchState.launchedNumVisibleTasks;
+        loadOpts.numVisibleTaskThumbnails = launchState.launchedNumVisibleThumbnails;
         loader.loadTasks(this, plan, loadOpts);
 
         TaskStack stack = plan.getTaskStack();
-        mConfig.launchedWithNoRecentTasks = !plan.hasTasks();
-        if (!mConfig.launchedWithNoRecentTasks) {
+        launchState.launchedWithNoRecentTasks = !plan.hasTasks();
+        if (!launchState.launchedWithNoRecentTasks) {
             mRecentsView.setTaskStack(stack);
         }
 
@@ -204,19 +201,19 @@
                 Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
         mFinishLaunchHomeRunnable = new FinishRecentsRunnable(homeIntent,
             ActivityOptions.makeCustomAnimation(this,
-                mConfig.launchedFromSearchHome ? R.anim.recents_to_search_launcher_enter :
+                    launchState.launchedFromSearchHome ? R.anim.recents_to_search_launcher_enter :
                         R.anim.recents_to_launcher_enter,
-                    mConfig.launchedFromSearchHome ? R.anim.recents_to_search_launcher_exit :
+                    launchState.launchedFromSearchHome ? R.anim.recents_to_search_launcher_exit :
                         R.anim.recents_to_launcher_exit));
 
         // Mark the task that is the launch target
         int launchTaskIndexInStack = 0;
-        if (mConfig.launchedToTaskId != -1) {
+        if (launchState.launchedToTaskId != -1) {
             ArrayList<Task> tasks = stack.getTasks();
             int taskCount = tasks.size();
             for (int j = 0; j < taskCount; j++) {
                 Task t = tasks.get(j);
-                if (t.key.id == mConfig.launchedToTaskId) {
+                if (t.key.id == launchState.launchedToTaskId) {
                     t.isLaunchTarget = true;
                     launchTaskIndexInStack = tasks.size() - j - 1;
                     break;
@@ -225,7 +222,7 @@
         }
 
         // Update the top level view's visibilities
-        if (mConfig.launchedWithNoRecentTasks) {
+        if (launchState.launchedWithNoRecentTasks) {
             if (mEmptyView == null) {
                 mEmptyView = mEmptyViewStub.inflate();
             }
@@ -246,13 +243,13 @@
         mScrimViews.prepareEnterRecentsAnimation();
 
         // Keep track of whether we launched from the nav bar button or via alt-tab
-        if (mConfig.launchedWithAltTab) {
+        if (launchState.launchedWithAltTab) {
             MetricsLogger.count(this, "overview_trigger_alttab", 1);
         } else {
             MetricsLogger.count(this, "overview_trigger_nav_btn", 1);
         }
         // Keep track of whether we launched from an app or from home
-        if (mConfig.launchedFromAppWithThumbnail) {
+        if (launchState.launchedFromAppWithThumbnail) {
             MetricsLogger.count(this, "overview_source_app", 1);
             // If from an app, track the stack index of the app in the stack (for affiliated tasks)
             MetricsLogger.histogram(this, "overview_source_app_index", launchTaskIndexInStack);
@@ -266,6 +263,7 @@
 
     /** Dismisses recents if we are already visible and the intent is to toggle the recents view */
     boolean dismissRecentsToFocusedTaskOrHome(boolean checkFilteredStackState) {
+        RecentsActivityLaunchState launchState = mConfig.getLaunchState();
         SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy();
         if (ssp.isRecentsTopMost(ssp.getTopMostTask(), null)) {
             // If we currently have filtered stacks, then unfilter those first
@@ -274,7 +272,7 @@
             // If we have a focused Task, launch that Task now
             if (mRecentsView.launchFocusedTask()) return true;
             // If we launched from Home, then return to Home
-            if (mConfig.launchedFromHome) {
+            if (launchState.launchedFromHome) {
                 dismissRecentsToHomeRaw(true);
                 return true;
             }
@@ -324,7 +322,8 @@
         // initialized
         RecentsTaskLoader.initialize(this);
         SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy();
-        mConfig = RecentsConfiguration.reinitialize(this, ssp);
+        mConfig = RecentsConfiguration.initialize(this, ssp);
+        mConfig.update(this, ssp, ssp.getWindowRect());
 
         // Initialize the widget host (the host id is static and does not change)
         mAppWidgetHost = new RecentsAppWidgetHost(this, Constants.Values.App.AppWidgetHostId);
@@ -337,7 +336,7 @@
                 View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
                 View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
         mEmptyViewStub = (ViewStub) findViewById(R.id.empty_view_stub);
-        mScrimViews = new SystemBarScrimViews(this, mConfig);
+        mScrimViews = new SystemBarScrimViews(this);
 
         // Bind the search app widget when we first start up
         mSearchWidgetInfo = ssp.getOrBindSearchAppWidget(this, mAppWidgetHost);
@@ -358,6 +357,7 @@
     @Override
     protected void onStart() {
         super.onStart();
+        RecentsActivityLaunchState launchState = mConfig.getLaunchState();
         MetricsLogger.visible(this, MetricsLogger.OVERVIEW_ACTIVITY);
         RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
         SystemServicesProxy ssp = loader.getSystemServicesProxy();
@@ -379,12 +379,13 @@
         // If this is a new instance from a configuration change, then we have to manually trigger
         // the enter animation state, or if recents was relaunched by AM, without going through
         // the normal mechanisms
-        boolean wasLaunchedByAm = !mConfig.launchedFromHome && !mConfig.launchedFromAppWithThumbnail;
-        if (mConfig.launchedHasConfigurationChanged || wasLaunchedByAm) {
+        boolean wasLaunchedByAm = !launchState.launchedFromHome &&
+                !launchState.launchedFromAppWithThumbnail;
+        if (launchState.launchedHasConfigurationChanged || wasLaunchedByAm) {
             onEnterAnimationTriggered();
         }
 
-        if (!mConfig.launchedHasConfigurationChanged) {
+        if (!launchState.launchedHasConfigurationChanged) {
             mRecentsView.disableLayersForOneFrame();
         }
     }
@@ -402,6 +403,7 @@
     protected void onStop() {
         super.onStop();
         MetricsLogger.hidden(this, MetricsLogger.OVERVIEW_ACTIVITY);
+        RecentsActivityLaunchState launchState = mConfig.getLaunchState();
         RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
         SystemServicesProxy ssp = loader.getSystemServicesProxy();
         Recents.notifyVisibilityChanged(this, ssp, false);
@@ -418,12 +420,12 @@
         // Workaround for b/22542869, if the RecentsActivity is started again, but without going
         // through SystemUI, we need to reset the config launch flags to ensure that we do not
         // wait on the system to send a signal that was never queued.
-        mConfig.launchedFromHome = false;
-        mConfig.launchedFromSearchHome = false;
-        mConfig.launchedFromAppWithThumbnail = false;
-        mConfig.launchedToTaskId = -1;
-        mConfig.launchedWithAltTab = false;
-        mConfig.launchedHasConfigurationChanged = false;
+        launchState.launchedFromHome = false;
+        launchState.launchedFromSearchHome = false;
+        launchState.launchedFromAppWithThumbnail = false;
+        launchState.launchedToTaskId = -1;
+        launchState.launchedWithAltTab = false;
+        launchState.launchedHasConfigurationChanged = false;
     }
 
     @Override
@@ -475,8 +477,9 @@
     public boolean onKeyDown(int keyCode, KeyEvent event) {
         switch (keyCode) {
             case KeyEvent.KEYCODE_TAB: {
+                int altTabKeyDelay = getResources().getInteger(R.integer.recents_alt_tab_key_delay);
                 boolean hasRepKeyTimeElapsed = (SystemClock.elapsedRealtime() -
-                        mLastTabKeyEventTime) > mConfig.altTabKeyDelay;
+                        mLastTabKeyEventTime) > altTabKeyDelay;
                 if (event.getRepeatCount() <= 0 || hasRepKeyTimeElapsed) {
                     // Focus the next task in the stack
                     final boolean backward = event.isShiftPressed();
@@ -514,9 +517,6 @@
 
     @Override
     public void onBackPressed() {
-        // Test mode where back does not do anything
-        if (mConfig.debugModeEnabled) return;
-
         // Dismiss Recents to the focused Task or Home
         dismissRecentsToFocusedTaskOrHome(true);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
new file mode 100644
index 0000000..e2e0e918
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recents;
+
+/**
+ * The launch state of the RecentsActivity.
+ *
+ * TODO: We will be refactoring this out RecentsConfiguration.
+ * Current Constraints:
+ *  - needed in onStart() before onNewIntent()
+ *  - needs to be reset when Recents is hidden
+ *  - needs to be computed in Recents component
+ *  - needs to be accessible by views
+ */
+public class RecentsActivityLaunchState {
+
+    public RecentsConfiguration mConfig;
+
+    public boolean launchedWithAltTab;
+    public boolean launchedWithNoRecentTasks;
+    public boolean launchedFromAppWithThumbnail;
+    public boolean launchedFromHome;
+    public boolean launchedFromSearchHome;
+    public boolean launchedReuseTaskStackViews;
+    public boolean launchedHasConfigurationChanged;
+    public int launchedToTaskId;
+    public int launchedNumVisibleTasks;
+    public int launchedNumVisibleThumbnails;
+
+    RecentsActivityLaunchState(RecentsConfiguration config) {
+        mConfig = config;
+    }
+
+    /** Called when the configuration has changed, and we want to reset any configuration specific
+     * members. */
+    public void updateOnConfigurationChange() {
+        // Reset this flag on configuration change to ensure that we recreate new task views
+        launchedReuseTaskStackViews = false;
+        // Set this flag to indicate that the configuration has changed since Recents last launched
+        launchedHasConfigurationChanged = true;
+    }
+
+    /** Returns whether the status bar scrim should be animated when shown for the first time. */
+    public boolean shouldAnimateStatusBarScrim() {
+        return launchedFromHome;
+    }
+
+    /** Returns whether the status bar scrim should be visible. */
+    public boolean hasStatusBarScrim() {
+        return !launchedWithNoRecentTasks;
+    }
+
+    /** Returns whether the nav bar scrim should be animated when shown for the first time. */
+    public boolean shouldAnimateNavBarScrim() {
+        return true;
+    }
+
+    /** Returns whether the nav bar scrim should be visible. */
+    public boolean hasNavBarScrim() {
+        // Only show the scrim if we have recent tasks, and if the nav bar is not transposed
+        return !launchedWithNoRecentTasks && mConfig.hasTransposedNavBar;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index a59eb30..52b9521 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -16,27 +16,29 @@
 
 package com.android.systemui.recents;
 
-import android.app.ActivityManager;
 import android.content.Context;
-import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.Rect;
 import android.provider.Settings;
-import android.util.DisplayMetrics;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
-
-import com.android.systemui.Prefs;
 import com.android.systemui.R;
-import com.android.systemui.recents.misc.Console;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 
-
-/** A static Recents configuration for the current context
- * NOTE: We should not hold any references to a Context from a static instance */
+/**
+ * Application resources that can be retrieved from the application context and are not specifically
+ * tied to the current activity.
+ */
 public class RecentsConfiguration {
     static RecentsConfiguration sInstance;
-    static int sPrevConfigurationHashCode;
+
+    private static final int LARGE_SCREEN_MIN_DP = 600;
+    private static final int XLARGE_SCREEN_MIN_DP = 720;
+
+    // Variables that are used for global calculations
+    private static final float STACK_SIDE_PADDING_PHONES_PCT = 0.03333f;
+    private static final float STACK_SIZE_PADDING_TABLETS_PCT = 0.075f;
+    private static final float STACK_SIZE_PADDING_LARGE_TABLETS_PCT = 0.15f;
+    private static final int SEARCH_BAR_SPACE_HEIGHT_PHONES_DPS = 64;
+    private static final int SEARCH_BAR_SPACE_HEIGHT_TABLETS_DPS = 72;
 
     /** Levels of svelte in increasing severity/austerity. */
     // No svelting.
@@ -50,123 +52,81 @@
     // Disable all thumbnail loading.
     public static final int SVELTE_DISABLE_LOADING = 3;
 
-    /** Interpolators */
-    public Interpolator fastOutSlowInInterpolator;
-    public Interpolator fastOutLinearInInterpolator;
-    public Interpolator linearOutSlowInInterpolator;
-    public Interpolator quintOutInterpolator;
+    // Launch states
+    public RecentsActivityLaunchState mLaunchState = new RecentsActivityLaunchState(this);
 
-    /** Filtering */
-    public int filteringCurrentViewsAnimDuration;
-    public int filteringNewViewsAnimDuration;
-
-    /** Insets */
-    public Rect systemInsets = new Rect();
-    public Rect displayRect = new Rect();
-
-    /** Layout */
-    boolean isLandscape;
+    // TODO: Values determined by the current context, needs to be refactored into something that is
+    //       agnostic of the activity context, but still calculable from the Recents component for
+    //       the transition into recents
     boolean hasTransposedSearchBar;
     boolean hasTransposedNavBar;
-
-    /** Loading */
-    public int maxNumTasksToLoad;
-
-    /** Search bar */
-    public int searchBarSpaceHeightPx;
-
-    /** Task stack */
-    public int taskStackScrollDuration;
-    public int taskStackMaxDim;
-    public int taskStackTopPaddingPx;
-    public int dismissAllButtonSizePx;
     public float taskStackWidthPaddingPct;
-    public float taskStackOverscrollPct;
 
-    /** Transitions */
-    public int transitionEnterFromAppDelay;
-    public int transitionEnterFromHomeDelay;
-
-    /** Task view animation and styles */
-    public int taskViewEnterFromAppDuration;
-    public int taskViewEnterFromHomeDuration;
-    public int taskViewEnterFromHomeStaggerDelay;
-    public int taskViewExitToAppDuration;
-    public int taskViewExitToHomeDuration;
-    public int taskViewRemoveAnimDuration;
-    public int taskViewRemoveAnimTranslationXPx;
-    public int taskViewTranslationZMinPx;
-    public int taskViewTranslationZMaxPx;
-    public int taskViewRoundedCornerRadiusPx;
-    public int taskViewHighlightPx;
-    public int taskViewAffiliateGroupEnterOffsetPx;
-    public float taskViewThumbnailAlpha;
-
-    /** Task bar colors */
-    public int taskBarViewDefaultBackgroundColor;
-    public int taskBarViewLightTextColor;
-    public int taskBarViewDarkTextColor;
-    public int taskBarViewHighlightColor;
-    public float taskBarViewAffiliationColorMinAlpha;
-
-    /** Task bar size & animations */
-    public int taskBarHeight;
-    public int taskBarDismissDozeDelaySeconds;
-
-    /** Nav bar scrim */
-    public int navBarScrimEnterDuration;
-
-    /** Launch states */
-    public boolean launchedWithAltTab;
-    public boolean launchedWithNoRecentTasks;
-    public boolean launchedFromAppWithThumbnail;
-    public boolean launchedFromHome;
-    public boolean launchedFromSearchHome;
-    public boolean launchedReuseTaskStackViews;
-    public boolean launchedHasConfigurationChanged;
-    public int launchedToTaskId;
-    public int launchedNumVisibleTasks;
-    public int launchedNumVisibleThumbnails;
+    // Since the positions in Recents has to be calculated globally (before the RecentsActivity
+    // starts), we need to calculate some resource values ourselves, instead of relying on framework
+    // resources.
+    public final boolean isLargeScreen;
+    public final boolean isXLargeScreen;
+    public final int smallestWidth;
 
     /** Misc **/
     public boolean useHardwareLayers;
-    public int altTabKeyDelay;
     public boolean fakeShadows;
+    public int svelteLevel;
+    public int searchBarSpaceHeightPx;
 
     /** Dev options and global settings */
     public boolean multiWindowEnabled;
     public boolean lockToAppEnabled;
-    public boolean developerOptionsEnabled;
-    public boolean debugModeEnabled;
-    public int svelteLevel;
 
     /** Private constructor */
-    private RecentsConfiguration(Context context) {
-        // Properties that don't have to be reloaded with each configuration change can be loaded
-        // here.
+    private RecentsConfiguration(Context context, SystemServicesProxy ssp) {
+        // Load only resources that can not change after the first load either through developer
+        // settings or via multi window
+        Context appContext = context.getApplicationContext();
+        Resources res = appContext.getResources();
+        useHardwareLayers = res.getBoolean(R.bool.config_recents_use_hardware_layers);
+        fakeShadows = res.getBoolean(R.bool.config_recents_fake_shadows);
+        svelteLevel = res.getInteger(R.integer.recents_svelte_level);
 
-        // Interpolators
-        fastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
-                com.android.internal.R.interpolator.fast_out_slow_in);
-        fastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context,
-                com.android.internal.R.interpolator.fast_out_linear_in);
-        linearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
-                com.android.internal.R.interpolator.linear_out_slow_in);
-        quintOutInterpolator = AnimationUtils.loadInterpolator(context,
-                com.android.internal.R.interpolator.decelerate_quint);
+        float density = context.getResources().getDisplayMetrics().density;
+        smallestWidth = ssp.getDeviceSmallestWidth();
+        isLargeScreen = smallestWidth >= (int) (density * LARGE_SCREEN_MIN_DP);
+        isXLargeScreen = smallestWidth >= (int) (density * XLARGE_SCREEN_MIN_DP);
+        searchBarSpaceHeightPx = isLargeScreen ?
+                (int) (density * SEARCH_BAR_SPACE_HEIGHT_TABLETS_DPS) :
+                (int) (density * SEARCH_BAR_SPACE_HEIGHT_PHONES_DPS);
+        if (isLargeScreen) {
+            taskStackWidthPaddingPct = STACK_SIZE_PADDING_TABLETS_PCT;
+        } else if (isXLargeScreen) {
+            taskStackWidthPaddingPct = STACK_SIZE_PADDING_LARGE_TABLETS_PCT;
+        } else {
+            taskStackWidthPaddingPct = STACK_SIDE_PADDING_PHONES_PCT;
+        }
+    }
+
+    /**
+     * Updates the configuration based on the current state of the system
+     */
+    void update(Context context, SystemServicesProxy ssp, Rect windowRect) {
+        // Only update resources that can change after the first load, either through developer
+        // settings or via multi window
+        lockToAppEnabled = ssp.getSystemSetting(context,
+                Settings.System.LOCK_TO_APP_ENABLED) != 0;
+        multiWindowEnabled = "true".equals(ssp.getSystemProperty("persist.sys.debug.multi_window"));
+
+        // Recompute some values based on the given state, since we can not rely on the resource
+        // system to get certain values.
+        boolean isLandscape = windowRect.width() > windowRect.height();
+        hasTransposedNavBar = isLandscape && isLargeScreen && !isXLargeScreen;
+        hasTransposedSearchBar = isLandscape && isLargeScreen && !isXLargeScreen;
     }
 
     /** Updates the configuration to the current context */
-    public static RecentsConfiguration reinitialize(Context context, SystemServicesProxy ssp) {
+    public static RecentsConfiguration initialize(Context context, SystemServicesProxy ssp) {
         if (sInstance == null) {
-            sInstance = new RecentsConfiguration(context);
+            sInstance = new RecentsConfiguration(context, ssp);
         }
-        int configHashCode = context.getResources().getConfiguration().hashCode();
-        if (sPrevConfigurationHashCode != configHashCode) {
-            sInstance.update(context);
-            sPrevConfigurationHashCode = configHashCode;
-        }
-        sInstance.reinitializeWithApplicationContext(context.getApplicationContext(), ssp);
         return sInstance;
     }
 
@@ -175,145 +135,18 @@
         return sInstance;
     }
 
-    /** Updates the state, given the specified context */
-    void update(Context context) {
-        Resources res = context.getResources();
-        DisplayMetrics dm = res.getDisplayMetrics();
-
-        // Debug mode
-        debugModeEnabled = Prefs.getBoolean(context, Prefs.Key.DEBUG_MODE_ENABLED,
-                false /* defaultValue */);
-        if (debugModeEnabled) {
-            Console.Enabled = true;
-        }
-
-        // Layout
-        isLandscape = res.getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE;
-        hasTransposedSearchBar = res.getBoolean(R.bool.recents_has_transposed_search_bar);
-        hasTransposedNavBar = res.getBoolean(R.bool.recents_has_transposed_nav_bar);
-
-        // Insets
-        displayRect.set(0, 0, dm.widthPixels, dm.heightPixels);
-
-        // Filtering
-        filteringCurrentViewsAnimDuration =
-                res.getInteger(R.integer.recents_filter_animate_current_views_duration);
-        filteringNewViewsAnimDuration =
-                res.getInteger(R.integer.recents_filter_animate_new_views_duration);
-
-        // Loading
-        maxNumTasksToLoad = ActivityManager.getMaxRecentTasksStatic();
-
-        // Search Bar
-        searchBarSpaceHeightPx = res.getDimensionPixelSize(R.dimen.recents_search_bar_space_height);
-
-        // Task stack
-        taskStackScrollDuration =
-                res.getInteger(R.integer.recents_animate_task_stack_scroll_duration);
-        taskStackWidthPaddingPct = res.getFloat(R.dimen.recents_stack_width_padding_percentage);
-        taskStackOverscrollPct = res.getFloat(R.dimen.recents_stack_overscroll_percentage);
-        taskStackMaxDim = res.getInteger(R.integer.recents_max_task_stack_view_dim);
-        taskStackTopPaddingPx = res.getDimensionPixelSize(R.dimen.recents_stack_top_padding);
-        dismissAllButtonSizePx = res.getDimensionPixelSize(R.dimen.recents_dismiss_all_button_size);
-
-        // Transition
-        transitionEnterFromAppDelay =
-                res.getInteger(R.integer.recents_enter_from_app_transition_duration);
-        transitionEnterFromHomeDelay =
-                res.getInteger(R.integer.recents_enter_from_home_transition_duration);
-
-        // Task view animation and styles
-        taskViewEnterFromAppDuration =
-                res.getInteger(R.integer.recents_task_enter_from_app_duration);
-        taskViewEnterFromHomeDuration =
-                res.getInteger(R.integer.recents_task_enter_from_home_duration);
-        taskViewEnterFromHomeStaggerDelay =
-                res.getInteger(R.integer.recents_task_enter_from_home_stagger_delay);
-        taskViewExitToAppDuration =
-                res.getInteger(R.integer.recents_task_exit_to_app_duration);
-        taskViewExitToHomeDuration =
-                res.getInteger(R.integer.recents_task_exit_to_home_duration);
-        taskViewRemoveAnimDuration =
-                res.getInteger(R.integer.recents_animate_task_view_remove_duration);
-        taskViewRemoveAnimTranslationXPx =
-                res.getDimensionPixelSize(R.dimen.recents_task_view_remove_anim_translation_x);
-        taskViewRoundedCornerRadiusPx =
-                res.getDimensionPixelSize(R.dimen.recents_task_view_rounded_corners_radius);
-        taskViewHighlightPx = res.getDimensionPixelSize(R.dimen.recents_task_view_highlight);
-        taskViewTranslationZMinPx = res.getDimensionPixelSize(R.dimen.recents_task_view_z_min);
-        taskViewTranslationZMaxPx = res.getDimensionPixelSize(R.dimen.recents_task_view_z_max);
-        taskViewAffiliateGroupEnterOffsetPx =
-                res.getDimensionPixelSize(R.dimen.recents_task_view_affiliate_group_enter_offset);
-        taskViewThumbnailAlpha = res.getFloat(R.dimen.recents_task_view_thumbnail_alpha);
-
-        // Task bar colors
-        taskBarViewDefaultBackgroundColor = context.getColor(
-                R.color.recents_task_bar_default_background_color);
-        taskBarViewLightTextColor = context.getColor(R.color.recents_task_bar_light_text_color);
-        taskBarViewDarkTextColor = context.getColor(R.color.recents_task_bar_dark_text_color);
-        taskBarViewHighlightColor = context.getColor(R.color.recents_task_bar_highlight_color);
-        taskBarViewAffiliationColorMinAlpha = res.getFloat(
-                R.dimen.recents_task_affiliation_color_min_alpha_percentage);
-
-        // Task bar size & animations
-        taskBarHeight = res.getDimensionPixelSize(R.dimen.recents_task_bar_height);
-        taskBarDismissDozeDelaySeconds =
-                res.getInteger(R.integer.recents_task_bar_dismiss_delay_seconds);
-
-        // Nav bar scrim
-        navBarScrimEnterDuration =
-                res.getInteger(R.integer.recents_nav_bar_scrim_enter_duration);
-
-        // Misc
-        useHardwareLayers = res.getBoolean(R.bool.config_recents_use_hardware_layers);
-        altTabKeyDelay = res.getInteger(R.integer.recents_alt_tab_key_delay);
-        fakeShadows = res.getBoolean(R.bool.config_recents_fake_shadows);
-        svelteLevel = res.getInteger(R.integer.recents_svelte_level);
-    }
-
-    /** Updates the system insets */
-    public void updateSystemInsets(Rect insets) {
-        systemInsets.set(insets);
-    }
-
-    /** Updates the states that need to be re-read from the application context. */
-    void reinitializeWithApplicationContext(Context context, SystemServicesProxy ssp) {
-        // Check if the developer options are enabled
-        developerOptionsEnabled = ssp.getGlobalSetting(context,
-                Settings.Global.DEVELOPMENT_SETTINGS_ENABLED) != 0;
-        lockToAppEnabled = ssp.getSystemSetting(context,
-                Settings.System.LOCK_TO_APP_ENABLED) != 0;
-        multiWindowEnabled = "true".equals(ssp.getSystemProperty("persist.sys.debug.multi_window"));
+    /**
+     * Returns the activity launch state.
+     * TODO: This will be refactored out of RecentsConfiguration.
+     */
+    public RecentsActivityLaunchState getLaunchState() {
+        return mLaunchState;
     }
 
     /** Called when the configuration has changed, and we want to reset any configuration specific
      * members. */
     public void updateOnConfigurationChange() {
-        // Reset this flag on configuration change to ensure that we recreate new task views
-        launchedReuseTaskStackViews = false;
-        // Set this flag to indicate that the configuration has changed since Recents last launched
-        launchedHasConfigurationChanged = true;
-    }
-
-    /** Returns whether the status bar scrim should be animated when shown for the first time. */
-    public boolean shouldAnimateStatusBarScrim() {
-        return launchedFromHome;
-    }
-
-    /** Returns whether the status bar scrim should be visible. */
-    public boolean hasStatusBarScrim() {
-        return !launchedWithNoRecentTasks;
-    }
-
-    /** Returns whether the nav bar scrim should be animated when shown for the first time. */
-    public boolean shouldAnimateNavBarScrim() {
-        return true;
-    }
-
-    /** Returns whether the nav bar scrim should be visible. */
-    public boolean hasNavBarScrim() {
-        // Only show the scrim if we have recent tasks, and if the nav bar is not transposed
-        return !launchedWithNoRecentTasks && (!hasTransposedNavBar || !isLandscape);
+        mLaunchState.updateOnConfigurationChange();
     }
 
     /**
@@ -322,14 +155,17 @@
      */
     public void getAvailableTaskStackBounds(Rect windowBounds, int topInset,
             int rightInset, Rect searchBarBounds, Rect taskStackBounds) {
-        if (isLandscape && hasTransposedSearchBar) {
-            // In landscape, the search bar appears on the left, but we overlay it on top
-            taskStackBounds.set(windowBounds.left, windowBounds.top + topInset,
-                    windowBounds.right - rightInset, windowBounds.bottom);
+        if (hasTransposedNavBar) {
+            // In landscape phones, the search bar appears on the left, but we overlay it on top
+            int swInset = getInsetToSmallestWidth(windowBounds.right - rightInset -
+                    windowBounds.left);
+            taskStackBounds.set(windowBounds.left + swInset, windowBounds.top + topInset,
+                    windowBounds.right - swInset - rightInset, windowBounds.bottom);
         } else {
             // In portrait, the search bar appears on the top (which already has the inset)
-            taskStackBounds.set(windowBounds.left, searchBarBounds.bottom,
-                    windowBounds.right, windowBounds.bottom);
+            int swInset = getInsetToSmallestWidth(windowBounds.right - windowBounds.left);
+            taskStackBounds.set(windowBounds.left + swInset, searchBarBounds.bottom,
+                    windowBounds.right - swInset, windowBounds.bottom);
         }
     }
 
@@ -340,8 +176,8 @@
     public void getSearchBarBounds(Rect windowBounds, int topInset, Rect searchBarSpaceBounds) {
         // Return empty rects if search is not enabled
         int searchBarSize = searchBarSpaceHeightPx;
-        if (isLandscape && hasTransposedSearchBar) {
-            // In landscape, the search bar appears on the left
+        if (hasTransposedSearchBar) {
+            // In landscape phones, the search bar appears on the left
             searchBarSpaceBounds.set(windowBounds.left, windowBounds.top + topInset,
                     windowBounds.left + searchBarSize, windowBounds.bottom);
         } else {
@@ -350,4 +186,14 @@
                     windowBounds.right, windowBounds.top + topInset + searchBarSize);
         }
     }
+
+    /**
+     * Constrain the width of the landscape stack to the smallest width of the device.
+     */
+    private int getInsetToSmallestWidth(int availableWidth) {
+        if (availableWidth > smallestWidth) {
+            return (availableWidth - smallestWidth) / 2;
+        }
+        return 0;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java
index 85f5b5d..59df293 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java
@@ -21,7 +21,6 @@
 import android.app.Dialog;
 import android.app.DialogFragment;
 import android.app.FragmentManager;
-import android.content.Context;
 import android.content.DialogInterface;
 import android.graphics.Rect;
 import android.os.Bundle;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
index cbf5c05..231843e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
@@ -39,7 +39,6 @@
 import android.widget.FrameLayout;
 import android.widget.LinearLayout;
 import android.widget.TextView;
-
 import com.android.systemui.R;
 
 import java.util.ArrayList;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index a2d7d01..b6d25f5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -32,7 +32,6 @@
 import android.content.pm.ActivityInfo;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
-import android.content.pm.PackageParser;
 import android.content.pm.ResolveInfo;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
@@ -56,18 +55,18 @@
 import android.provider.Settings;
 import android.util.Log;
 import android.util.MutableBoolean;
+import android.util.MutableFloat;
+import android.util.MutableInt;
 import android.util.Pair;
-import android.util.SparseArray;
+import android.util.Size;
 import android.view.Display;
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityManager;
-
 import com.android.internal.app.AssistUtils;
 import com.android.systemui.Prefs;
 import com.android.systemui.R;
 import com.android.systemui.recents.Constants;
 import com.android.systemui.recents.Recents;
-import com.android.systemui.recents.RecentsConfiguration;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -662,6 +661,18 @@
     }
 
     /**
+     * Returns the smallest width/height.
+     */
+    public int getDeviceSmallestWidth() {
+        if (mWm == null) return 0;
+
+        Point smallestSizeRange = new Point();
+        Point largestSizeRange = new Point();
+        mWm.getDefaultDisplay().getCurrentSizeRange(smallestSizeRange, largestSizeRange);
+        return smallestSizeRange.x;
+    }
+
+    /**
      * Returns the display rect.
      */
     public Rect getDisplayRect() {
@@ -675,7 +686,7 @@
     }
 
     /**
-     * Returns the window rect.
+     * Returns the window rect for the RecentsActivity, based on the dimensions of the home stack.
      */
     public Rect getWindowRect() {
         Rect windowRect = new Rect();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
index 649cb4d..6ef7253 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
@@ -23,7 +23,6 @@
 import android.graphics.drawable.Drawable;
 import android.os.UserHandle;
 import android.util.Log;
-import android.util.SparseArray;
 import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 
@@ -76,7 +75,7 @@
      * An optimization to preload the raw list of tasks.
      */
     public synchronized void preloadRawTasks(boolean isTopTaskHome) {
-        mRawTasks = mSystemServicesProxy.getRecentTasks(mConfig.maxNumTasksToLoad,
+        mRawTasks = mSystemServicesProxy.getRecentTasks(ActivityManager.getMaxRecentTasksStatic(),
                 UserHandle.CURRENT.getIdentifier(), isTopTaskHome);
         Collections.reverse(mRawTasks);
 
@@ -125,7 +124,7 @@
                     activityLabel, mSystemServicesProxy, res);
             Drawable activityIcon = loader.getAndUpdateActivityIcon(taskKey, t.taskDescription,
                     mSystemServicesProxy, res, infoHandle, false);
-            int activityColor = loader.getActivityPrimaryColor(t.taskDescription, mConfig);
+            int activityColor = loader.getActivityPrimaryColor(t.taskDescription, res);
 
             // Update the activity info cache
             if (!hadCachedActivityInfo && infoHandle.info != null) {
@@ -153,7 +152,7 @@
         // Initialize the stacks
         mStack = new TaskStack();
         mStack.setTasks(stackTasks);
-        mStack.createAffiliatedGroupings(mConfig);
+        mStack.createAffiliatedGroupings(mContext);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
index ad25c85..760382e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
@@ -27,7 +27,6 @@
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.util.Log;
-
 import com.android.systemui.R;
 import com.android.systemui.recents.Constants;
 import com.android.systemui.recents.RecentsConfiguration;
@@ -248,7 +247,7 @@
 }
 
 /* Recents task loader
- * NOTE: We should not hold any references to a Context from a static instance */
+ * NOTE: We should not hold any references to non-application Context from a static instance */
 public class RecentsTaskLoader {
     private static final String TAG = "RecentsTaskLoader";
 
@@ -438,12 +437,11 @@
     }
 
     /** Returns the activity's primary color. */
-    public int getActivityPrimaryColor(ActivityManager.TaskDescription td,
-            RecentsConfiguration config) {
+    public int getActivityPrimaryColor(ActivityManager.TaskDescription td, Resources res) {
         if (td != null && td.getPrimaryColor() != 0) {
             return td.getPrimaryColor();
         }
-        return config.taskBarViewDefaultBackgroundColor;
+        return res.getColor(R.color.recents_task_bar_default_background_color);
     }
 
     /** Returns the size of the app icon cache. */
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
index 515e578..20d9203 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
@@ -16,11 +16,12 @@
 
 package com.android.systemui.recents.model;
 
+import android.content.Context;
 import android.graphics.Color;
 import com.android.systemui.recents.Constants;
-import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.misc.NamedCounter;
 import com.android.systemui.recents.misc.Utilities;
+import com.android.systemui.R;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -367,7 +368,7 @@
     /**
      * Temporary: This method will simulate affiliation groups by
      */
-    public void createAffiliatedGroupings(RecentsConfiguration config) {
+    public void createAffiliatedGroupings(Context context) {
         if (Constants.DebugFlags.App.EnableSimulatedTaskGroups) {
             HashMap<Task.TaskKey, Task> taskMap = new HashMap<Task.TaskKey, Task>();
             // Sort all tasks by increasing firstActiveTime of the task
@@ -452,7 +453,8 @@
                 tasksMap.put(t.key, t);
             }
             // Update the task colors for each of the groups
-            float minAlpha = config.taskBarViewAffiliationColorMinAlpha;
+            float minAlpha = context.getResources().getFloat(
+                    R.dimen.recents_task_affiliation_color_min_alpha_percentage);
             int taskGroupCount = mGroups.size();
             for (int i = 0; i < taskGroupCount; i++) {
                 TaskGrouping group = mGroups.get(i);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/FakeShadowDrawable.java b/packages/SystemUI/src/com/android/systemui/recents/views/FakeShadowDrawable.java
index 41adbed..682fd8f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/FakeShadowDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/FakeShadowDrawable.java
@@ -89,7 +89,8 @@
         mCornerShadowPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
         mCornerShadowPaint.setStyle(Paint.Style.FILL);
         mCornerShadowPaint.setDither(true);
-        mCornerRadius = config.taskViewRoundedCornerRadiusPx;
+        mCornerRadius = resources.getDimensionPixelSize(
+                R.dimen.recents_task_view_rounded_corners_radius);
         mCardBounds = new RectF();
         mEdgeShadowPaint = new Paint(mCornerShadowPaint);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index 9685a24..92ed0f1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -38,8 +38,9 @@
 import android.view.View;
 import android.view.WindowInsets;
 import android.view.WindowManagerGlobal;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
 import android.widget.FrameLayout;
-
 import com.android.internal.logging.MetricsLogger;
 import com.android.systemui.R;
 import com.android.systemui.recents.Constants;
@@ -83,6 +84,9 @@
     TaskStackView mTaskStackView;
     RecentsAppWidgetHostView mSearchBar;
     RecentsViewCallbacks mCb;
+    Interpolator mFastOutSlowInInterpolator;
+
+    Rect mSystemInsets = new Rect();
 
     public RecentsView(Context context) {
         super(context);
@@ -100,6 +104,8 @@
         super(context, attrs, defStyleAttr, defStyleRes);
         mConfig = RecentsConfiguration.getInstance();
         mInflater = LayoutInflater.from(context);
+        mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
+                com.android.internal.R.interpolator.fast_out_slow_in);
     }
 
     /** Sets the callbacks */
@@ -109,7 +115,7 @@
 
     /** Set/get the bsp root node */
     public void setTaskStack(TaskStack stack) {
-        if (mConfig.launchedReuseTaskStackViews) {
+        if (mConfig.getLaunchState().launchedReuseTaskStackViews) {
             if (mTaskStackView != null) {
                 // If onRecentsHidden is not triggered, we need to the stack view again here
                 mTaskStackView.reset();
@@ -278,7 +284,7 @@
         // Get the search bar bounds and measure the search bar layout
         Rect searchBarSpaceBounds = new Rect();
         if (mSearchBar != null) {
-            mConfig.getSearchBarBounds(new Rect(0, 0, width, height), mConfig.systemInsets.top,
+            mConfig.getSearchBarBounds(new Rect(0, 0, width, height), mSystemInsets.top,
                     searchBarSpaceBounds);
             mSearchBar.measure(
                     MeasureSpec.makeMeasureSpec(searchBarSpaceBounds.width(), MeasureSpec.EXACTLY),
@@ -286,8 +292,8 @@
         }
 
         Rect taskStackBounds = new Rect();
-        mConfig.getAvailableTaskStackBounds(new Rect(0, 0, width, height), mConfig.systemInsets.top,
-                mConfig.systemInsets.right, searchBarSpaceBounds, taskStackBounds);
+        mConfig.getAvailableTaskStackBounds(new Rect(0, 0, width, height), mSystemInsets.top,
+                mSystemInsets.right, searchBarSpaceBounds, taskStackBounds);
         if (mTaskStackView != null && mTaskStackView.getVisibility() != GONE) {
             mTaskStackView.setTaskStackBounds(taskStackBounds);
             mTaskStackView.measure(widthMeasureSpec, heightMeasureSpec);
@@ -306,7 +312,7 @@
         Rect searchBarSpaceBounds = new Rect();
         if (mSearchBar != null) {
             mConfig.getSearchBarBounds(measuredRect,
-                    mConfig.systemInsets.top, searchBarSpaceBounds);
+                    mSystemInsets.top, searchBarSpaceBounds);
             mSearchBar.layout(searchBarSpaceBounds.left, searchBarSpaceBounds.top,
                     searchBarSpaceBounds.right, searchBarSpaceBounds.bottom);
         }
@@ -318,8 +324,7 @@
 
     @Override
     public WindowInsets onApplyWindowInsets(WindowInsets insets) {
-        // Update the configuration with the latest system insets and trigger a relayout
-        mConfig.updateSystemInsets(insets.getSystemWindowInsets());
+        mSystemInsets.set(insets.getSystemWindowInsets());
         requestLayout();
         return insets.consumeSystemWindowInsets();
     }
@@ -548,7 +553,7 @@
             // outside the display rect (to ensure we don't animate from too far away)
             sourceView = stackView;
             offsetX = transform.rect.left;
-            offsetY = mConfig.displayRect.height();
+            offsetY = getMeasuredHeight();
         } else {
             sourceView = tv.mThumbnailView;
         }
@@ -700,11 +705,13 @@
     public void onTaskStackFilterTriggered() {
         // Hide the search bar
         if (mSearchBar != null) {
+            int filterDuration = getResources().getInteger(
+                    R.integer.recents_filter_animate_current_views_duration);
             mSearchBar.animate()
                     .alpha(0f)
                     .setStartDelay(0)
-                    .setInterpolator(mConfig.fastOutSlowInInterpolator)
-                    .setDuration(mConfig.filteringCurrentViewsAnimDuration)
+                    .setInterpolator(mFastOutSlowInInterpolator)
+                    .setDuration(filterDuration)
                     .withLayer()
                     .start();
         }
@@ -714,11 +721,13 @@
     public void onTaskStackUnfilterTriggered() {
         // Show the search bar
         if (mSearchBar != null) {
+            int filterDuration = getResources().getInteger(
+                    R.integer.recents_filter_animate_new_views_duration);
             mSearchBar.animate()
                     .alpha(1f)
                     .setStartDelay(0)
-                    .setInterpolator(mConfig.fastOutSlowInInterpolator)
-                    .setDuration(mConfig.filteringNewViewsAnimDuration)
+                    .setInterpolator(mFastOutSlowInInterpolator)
+                    .setDuration(filterDuration)
                     .withLayer()
                     .start();
         }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java
index 0428b48..e04699c1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java
@@ -22,13 +22,15 @@
 import android.animation.ValueAnimator;
 import android.animation.ValueAnimator.AnimatorUpdateListener;
 import android.annotation.TargetApi;
+import android.content.Context;
 import android.os.Build;
 import android.util.DisplayMetrics;
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
 import android.view.View;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
 import android.view.animation.LinearInterpolator;
-import com.android.systemui.recents.RecentsConfiguration;
 
 /**
  * This class facilitates swipe to dismiss. It defines an interface to be implemented by the
@@ -46,6 +48,7 @@
     public static final int Y = 1;
 
     private static LinearInterpolator sLinearInterpolator = new LinearInterpolator();
+    private Interpolator mLinearOutSlowInInterpolator;
 
     private float SWIPE_ESCAPE_VELOCITY = 100f; // dp/sec
     private int DEFAULT_ESCAPE_ANIMATION_DURATION = 75; // ms
@@ -74,13 +77,15 @@
     public boolean mAllowSwipeTowardsEnd = true;
     private boolean mRtl;
 
-    public SwipeHelper(int swipeDirection, Callback callback, float densityScale,
+    public SwipeHelper(Context context, int swipeDirection, Callback callback, float densityScale,
             float pagingTouchSlop) {
         mCallback = callback;
         mSwipeDirection = swipeDirection;
         mVelocityTracker = VelocityTracker.obtain();
         mDensityScale = densityScale;
         mPagingTouchSlop = pagingTouchSlop;
+        mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
+                com.android.internal.R.interpolator.linear_out_slow_in);
     }
 
     public void setDensityScale(float densityScale) {
@@ -265,7 +270,7 @@
         ValueAnimator anim = createTranslationAnimation(view, 0);
         int duration = SNAP_ANIM_LEN;
         anim.setDuration(duration);
-        anim.setInterpolator(RecentsConfiguration.getInstance().linearOutSlowInInterpolator);
+        anim.setInterpolator(mLinearOutSlowInInterpolator);
         anim.addUpdateListener(new AnimatorUpdateListener() {
             @Override
             public void onAnimationUpdate(ValueAnimator animation) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
index 1086160..7ce50d8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
@@ -17,13 +17,19 @@
 package com.android.systemui.recents.views;
 
 import android.app.Activity;
+import android.content.Context;
 import android.view.View;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
 import com.android.systemui.R;
+import com.android.systemui.recents.RecentsActivity;
+import com.android.systemui.recents.RecentsActivityLaunchState;
 import com.android.systemui.recents.RecentsConfiguration;
 
 /** Manages the scrims for the various system bars. */
 public class SystemBarScrimViews {
 
+    Context mContext;
     RecentsConfiguration mConfig;
 
     View mStatusBarScrimView;
@@ -34,10 +40,22 @@
     boolean mHasStatusBarScrim;
     boolean mShouldAnimateNavBarScrim;
 
-    public SystemBarScrimViews(Activity activity, RecentsConfiguration config) {
-        mConfig = config;
+    int mNavBarScrimEnterDuration;
+
+    Interpolator mFastOutSlowInInterpolator;
+    Interpolator mQuintOutInterpolator;
+
+    public SystemBarScrimViews(Activity activity) {
+        mContext = activity;
+        mConfig = RecentsConfiguration.getInstance();
         mStatusBarScrimView = activity.findViewById(R.id.status_bar_scrim);
         mNavBarScrimView = activity.findViewById(R.id.nav_bar_scrim);
+        mNavBarScrimEnterDuration = activity.getResources().getInteger(
+                R.integer.recents_nav_bar_scrim_enter_duration);
+        mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(activity,
+                        com.android.internal.R.interpolator.fast_out_slow_in);
+        mQuintOutInterpolator = AnimationUtils.loadInterpolator(activity,
+                com.android.internal.R.interpolator.decelerate_quint);
     }
 
     /**
@@ -45,10 +63,11 @@
      * the first draw.
      */
     public void prepareEnterRecentsAnimation() {
-        mHasNavBarScrim = mConfig.hasNavBarScrim();
-        mShouldAnimateNavBarScrim = mConfig.shouldAnimateNavBarScrim();
-        mHasStatusBarScrim = mConfig.hasStatusBarScrim();
-        mShouldAnimateStatusBarScrim = mConfig.shouldAnimateStatusBarScrim();
+        RecentsActivityLaunchState launchState = mConfig.getLaunchState();
+        mHasNavBarScrim = launchState.hasNavBarScrim();
+        mShouldAnimateNavBarScrim = launchState.shouldAnimateNavBarScrim();
+        mHasStatusBarScrim = launchState.hasStatusBarScrim();
+        mShouldAnimateStatusBarScrim = launchState.shouldAnimateStatusBarScrim();
 
         mNavBarScrimView.setVisibility(mHasNavBarScrim && !mShouldAnimateNavBarScrim ?
                 View.VISIBLE : View.INVISIBLE);
@@ -60,15 +79,21 @@
      * Starts animating the scrim views when entering Recents.
      */
     public void startEnterRecentsAnimation() {
+        RecentsActivityLaunchState launchState = mConfig.getLaunchState();
+        int transitionEnterFromAppDelay = mContext.getResources().getInteger(
+                R.integer.recents_enter_from_app_transition_duration);
+        int transitionEnterFromHomeDelay = mContext.getResources().getInteger(
+                R.integer.recents_enter_from_home_transition_duration);
+
         if (mHasStatusBarScrim && mShouldAnimateStatusBarScrim) {
             mStatusBarScrimView.setTranslationY(-mStatusBarScrimView.getMeasuredHeight());
             mStatusBarScrimView.animate()
                     .translationY(0)
-                    .setStartDelay(mConfig.launchedFromHome ?
-                            mConfig.transitionEnterFromHomeDelay :
-                            mConfig.transitionEnterFromAppDelay)
-                    .setDuration(mConfig.navBarScrimEnterDuration)
-                    .setInterpolator(mConfig.quintOutInterpolator)
+                    .setStartDelay(launchState.launchedFromHome ?
+                            transitionEnterFromHomeDelay :
+                            transitionEnterFromAppDelay)
+                    .setDuration(mNavBarScrimEnterDuration)
+                    .setInterpolator(mQuintOutInterpolator)
                     .withStartAction(new Runnable() {
                         @Override
                         public void run() {
@@ -81,11 +106,11 @@
             mNavBarScrimView.setTranslationY(mNavBarScrimView.getMeasuredHeight());
             mNavBarScrimView.animate()
                     .translationY(0)
-                    .setStartDelay(mConfig.launchedFromHome ?
-                            mConfig.transitionEnterFromHomeDelay :
-                            mConfig.transitionEnterFromAppDelay)
-                    .setDuration(mConfig.navBarScrimEnterDuration)
-                    .setInterpolator(mConfig.quintOutInterpolator)
+                    .setStartDelay(launchState.launchedFromHome ?
+                            transitionEnterFromHomeDelay :
+                            transitionEnterFromAppDelay)
+                    .setDuration(mNavBarScrimEnterDuration)
+                    .setInterpolator(mQuintOutInterpolator)
                     .withStartAction(new Runnable() {
                         @Override
                         public void run() {
@@ -101,20 +126,22 @@
      * going home).
      */
     public void startExitRecentsAnimation() {
+        int taskViewExitToAppDuration = mContext.getResources().getInteger(
+                R.integer.recents_task_exit_to_app_duration);
         if (mHasStatusBarScrim && mShouldAnimateStatusBarScrim) {
             mStatusBarScrimView.animate()
                     .translationY(-mStatusBarScrimView.getMeasuredHeight())
                     .setStartDelay(0)
-                    .setDuration(mConfig.taskViewExitToAppDuration)
-                    .setInterpolator(mConfig.fastOutSlowInInterpolator)
+                    .setDuration(taskViewExitToAppDuration)
+                    .setInterpolator(mFastOutSlowInInterpolator)
                     .start();
         }
         if (mHasNavBarScrim && mShouldAnimateNavBarScrim) {
             mNavBarScrimView.animate()
                     .translationY(mNavBarScrimView.getMeasuredHeight())
                     .setStartDelay(0)
-                    .setDuration(mConfig.taskViewExitToAppDuration)
-                    .setInterpolator(mConfig.fastOutSlowInInterpolator)
+                    .setDuration(taskViewExitToAppDuration)
+                    .setInterpolator(mFastOutSlowInInterpolator)
                     .start();
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index 4db8b37..b5ad112 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -29,10 +29,10 @@
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.FrameLayout;
-
 import com.android.internal.logging.MetricsLogger;
 import com.android.systemui.R;
 import com.android.systemui.recents.Constants;
+import com.android.systemui.recents.RecentsActivityLaunchState;
 import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.misc.DozeTrigger;
 import com.android.systemui.recents.misc.SystemServicesProxy;
@@ -117,14 +117,17 @@
         // Set the stack first
         setStack(stack);
         mConfig = RecentsConfiguration.getInstance();
-        mViewPool = new ViewPool<TaskView, Task>(context, this);
+        mViewPool = new ViewPool<>(context, this);
         mInflater = LayoutInflater.from(context);
-        mLayoutAlgorithm = new TaskStackViewLayoutAlgorithm(mConfig);
-        mFilterAlgorithm = new TaskStackViewFilterAlgorithm(mConfig, this, mViewPool);
-        mStackScroller = new TaskStackViewScroller(context, mConfig, mLayoutAlgorithm);
+        mLayoutAlgorithm = new TaskStackViewLayoutAlgorithm(context, mConfig);
+        mFilterAlgorithm = new TaskStackViewFilterAlgorithm(this, mViewPool);
+        mStackScroller = new TaskStackViewScroller(context, mLayoutAlgorithm);
         mStackScroller.setCallbacks(this);
-        mTouchHandler = new TaskStackViewTouchHandler(context, this, mConfig, mStackScroller);
-        mUIDozeTrigger = new DozeTrigger(mConfig.taskBarDismissDozeDelaySeconds, new Runnable() {
+        mTouchHandler = new TaskStackViewTouchHandler(context, this, mStackScroller);
+
+        int taskBarDismissDozeDelaySeconds = getResources().getInteger(
+                R.integer.recents_task_bar_dismiss_delay_seconds);
+        mUIDozeTrigger = new DozeTrigger(taskBarDismissDozeDelaySeconds, new Runnable() {
             @Override
             public void run() {
                 // Show the task bar dismiss buttons
@@ -731,8 +734,9 @@
         int height = MeasureSpec.getSize(heightMeasureSpec);
 
         // Compute our stack/task rects
-        computeRects(width, height, mTaskStackBounds, mConfig.launchedWithAltTab,
-                mConfig.launchedFromHome);
+        RecentsActivityLaunchState launchState = mConfig.getLaunchState();
+        computeRects(width, height, mTaskStackBounds, launchState.launchedWithAltTab,
+                launchState.launchedFromHome);
 
         // If this is the first layout, then scroll to the front of the stack and synchronize the
         // stack views immediately to load all the views
@@ -764,9 +768,11 @@
         // Measure the dismiss button
         if (mDismissAllButton != null) {
             int taskRectWidth = mLayoutAlgorithm.mTaskRect.width();
+            int dismissAllButtonHeight = getResources().getDimensionPixelSize(
+                    R.dimen.recents_dismiss_all_button_size);
             mDismissAllButton.measure(
                     MeasureSpec.makeMeasureSpec(taskRectWidth, MeasureSpec.EXACTLY),
-                    MeasureSpec.makeMeasureSpec(mConfig.dismissAllButtonSizePx, MeasureSpec.EXACTLY));
+                    MeasureSpec.makeMeasureSpec(dismissAllButtonHeight, MeasureSpec.EXACTLY));
         }
 
         setMeasuredDimension(width, height);
@@ -847,13 +853,14 @@
 
         // When Alt-Tabbing, focus the previous task (but leave the animation until we finish the
         // enter animation).
-        if (mConfig.launchedWithAltTab) {
-            if (mConfig.launchedFromAppWithThumbnail) {
+        RecentsActivityLaunchState launchState = mConfig.getLaunchState();
+        if (launchState.launchedWithAltTab) {
+            if (launchState.launchedFromAppWithThumbnail) {
                 focusTask(Math.max(0, mStack.getTaskCount() - 2), false,
-                        mConfig.launchedHasConfigurationChanged);
+                        launchState.launchedHasConfigurationChanged);
             } else {
                 focusTask(Math.max(0, mStack.getTaskCount() - 1), false,
-                        mConfig.launchedHasConfigurationChanged);
+                        launchState.launchedHasConfigurationChanged);
             }
         }
 
@@ -924,7 +931,9 @@
 
                     // Start the focus animation when alt-tabbing
                     ArrayList<Task> tasks = mStack.getTasks();
-                    if (mConfig.launchedWithAltTab && !mConfig.launchedHasConfigurationChanged &&
+                    RecentsActivityLaunchState launchState = mConfig.getLaunchState();
+                    if (launchState.launchedWithAltTab &&
+                            !launchState.launchedHasConfigurationChanged &&
                             0 <= mFocusedTaskIndex && mFocusedTaskIndex < tasks.size()) {
                         TaskView tv = getChildViewForTask(tasks.get(mFocusedTaskIndex));
                         if (tv != null) {
@@ -1115,7 +1124,8 @@
         }
 
         // Update the min/max scroll and animate other task views into their new positions
-        updateMinMaxScroll(true, mConfig.launchedWithAltTab, mConfig.launchedFromHome);
+        RecentsActivityLaunchState launchState = mConfig.getLaunchState();
+        updateMinMaxScroll(true, launchState.launchedWithAltTab, launchState.launchedFromHome);
 
         // Offset the stack by as much as the anchor task would otherwise move back
         if (pullStackForward) {
@@ -1133,7 +1143,8 @@
             TaskView frontTv = getChildViewForTask(newFrontMostTask);
             if (frontTv != null) {
                 frontTv.onTaskBound(newFrontMostTask);
-                frontTv.fadeInActionButton(0, mConfig.taskViewEnterFromAppDuration);
+                frontTv.fadeInActionButton(0, getResources().getInteger(
+                        R.integer.recents_task_enter_from_app_duration));
             }
         }
 
@@ -1384,7 +1395,8 @@
                 if (nextTv != null) {
                     // Focus the next task, and only animate the visible state if we are launched
                     // from Alt-Tab
-                    nextTv.setFocusedTask(mConfig.launchedWithAltTab);
+                    RecentsActivityLaunchState launchState = mConfig.getLaunchState();
+                    nextTv.setFocusedTask(launchState.launchedWithAltTab);
                 }
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewFilterAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewFilterAlgorithm.java
index 614ca53..e9f6a46 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewFilterAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewFilterAlgorithm.java
@@ -17,8 +17,8 @@
 package com.android.systemui.recents.views;
 
 import com.android.systemui.recents.Constants;
-import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.model.Task;
+import com.android.systemui.R;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -27,13 +27,10 @@
 /* The layout logic for a TaskStackView */
 public class TaskStackViewFilterAlgorithm {
 
-    RecentsConfiguration mConfig;
     TaskStackView mStackView;
     ViewPool<TaskView, Task> mViewPool;
 
-    public TaskStackViewFilterAlgorithm(RecentsConfiguration config, TaskStackView stackView,
-                                        ViewPool<TaskView, Task> viewPool) {
-        mConfig = config;
+    public TaskStackViewFilterAlgorithm(TaskStackView stackView, ViewPool<TaskView, Task> viewPool) {
         mStackView = stackView;
         mViewPool = viewPool;
     }
@@ -126,7 +123,8 @@
                 }
             }
         }
-        return mConfig.filteringNewViewsAnimDuration;
+        return mStackView.getResources().getInteger(
+                R.integer.recents_filter_animate_new_views_duration);
     }
 
     /**
@@ -172,7 +170,8 @@
             childViewTransformsOut.put(tv, toTransform);
             offset++;
         }
-        return mConfig.filteringCurrentViewsAnimDuration;
+        return mStackView.getResources().getInteger(
+                R.integer.recents_filter_animate_current_views_duration);
     }
 
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java
index f6df881..8128cac 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java
@@ -16,11 +16,13 @@
 
 package com.android.systemui.recents.views;
 
+import android.content.Context;
 import android.graphics.Rect;
 import com.android.systemui.recents.Constants;
 import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.misc.Utilities;
 import com.android.systemui.recents.model.Task;
+import com.android.systemui.R;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -48,6 +50,7 @@
         }
     }
 
+    Context mContext;
     RecentsConfiguration mConfig;
 
     // The various rects that define the stack view
@@ -71,7 +74,8 @@
     static float[] xp;
     static float[] px;
 
-    public TaskStackViewLayoutAlgorithm(RecentsConfiguration config) {
+    public TaskStackViewLayoutAlgorithm(Context context, RecentsConfiguration config) {
+        mContext = context;
         mConfig = config;
 
         // Precompute the path
@@ -87,7 +91,8 @@
         mStackVisibleRect.bottom = mViewRect.bottom;
 
         int widthPadding = (int) (mConfig.taskStackWidthPaddingPct * mStackRect.width());
-        int heightPadding = mConfig.taskStackTopPaddingPx;
+        int heightPadding = mContext.getResources().getDimensionPixelSize(
+                R.dimen.recents_stack_top_padding);
         mStackRect.inset(widthPadding, heightPadding);
 
         // Compute the task rect
@@ -98,7 +103,8 @@
 
         // Update the affiliation offsets
         float visibleTaskPct = 0.5f;
-        mWithinAffiliationOffset = mConfig.taskBarHeight;
+        mWithinAffiliationOffset = mContext.getResources().getDimensionPixelSize(
+                R.dimen.recents_task_bar_height);
         mBetweenAffiliationOffset = (int) (visibleTaskPct * mTaskRect.height());
     }
 
@@ -134,8 +140,10 @@
                         mStackRect.bottom));
         float pDismissAllButtonOffset = 0f;
         if (Constants.DebugFlags.App.EnableDismissAll) {
+            int dismissAllButtonHeight = mContext.getResources().getDimensionPixelSize(
+                    R.dimen.recents_dismiss_all_button_size);
             pDismissAllButtonOffset = pAtBottomOfStackRect -
-                screenYToCurveProgress(mStackVisibleRect.bottom - mConfig.dismissAllButtonSizePx);
+                screenYToCurveProgress(mStackVisibleRect.bottom - dismissAllButtonHeight);
         }
 
         // Update the task offsets
@@ -177,6 +185,8 @@
 
         // Walk backwards in the task stack and count the number of tasks and visible thumbnails
         int taskHeight = mTaskRect.height();
+        int taskBarHeight = mContext.getResources().getDimensionPixelSize(
+                R.dimen.recents_task_bar_height);
         int numVisibleTasks = 1;
         int numVisibleThumbnails = 1;
         float progress = mTaskProgressMap.get(tasks.get(tasks.size() - 1).key) - mInitialScrollP;
@@ -192,7 +202,7 @@
                 float scaleAtP = curveProgressToScale(progress);
                 int scaleYOffsetAtP = (int) (((1f - scaleAtP) * taskHeight) / 2);
                 int screenY = curveProgressToScreenY(progress) + scaleYOffsetAtP;
-                boolean hasVisibleThumbnail = (prevScreenY - screenY) > mConfig.taskBarHeight;
+                boolean hasVisibleThumbnail = (prevScreenY - screenY) > taskBarHeight;
                 if (hasVisibleThumbnail) {
                     numVisibleThumbnails++;
                     numVisibleTasks++;
@@ -251,8 +261,8 @@
         }
         float scale = curveProgressToScale(pBounded);
         int scaleYOffset = (int) (((1f - scale) * mTaskRect.height()) / 2);
-        int minZ = mConfig.taskViewTranslationZMinPx;
-        int maxZ = mConfig.taskViewTranslationZMaxPx;
+        int minZ = mContext.getResources().getDimensionPixelSize(R.dimen.recents_task_view_z_min);
+        int maxZ = mContext.getResources().getDimensionPixelSize(R.dimen.recents_task_view_z_max);
         transformOut.scale = scale;
         transformOut.translationY = curveProgressToScreenY(pBounded) - mStackVisibleRect.top -
                 scaleYOffset;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
index fabc86d..f0ae87f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
@@ -21,9 +21,11 @@
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
 import android.content.Context;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
 import android.widget.OverScroller;
-import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.misc.Utilities;
+import com.android.systemui.R;
 
 /* The scrolling logic for a TaskStackView */
 public class TaskStackViewScroller {
@@ -31,7 +33,7 @@
         public void onScrollChanged(float p);
     }
 
-    RecentsConfiguration mConfig;
+    Context mContext;
     TaskStackViewLayoutAlgorithm mLayoutAlgorithm;
     TaskStackViewScrollerCallbacks mCb;
 
@@ -41,10 +43,14 @@
     ObjectAnimator mScrollAnimator;
     float mFinalAnimatedScroll;
 
-    public TaskStackViewScroller(Context context, RecentsConfiguration config, TaskStackViewLayoutAlgorithm layoutAlgorithm) {
-        mConfig = config;
+    Interpolator mLinearOutSlowInInterpolator;
+
+    public TaskStackViewScroller(Context context, TaskStackViewLayoutAlgorithm layoutAlgorithm) {
+        mContext = context;
         mScroller = new OverScroller(context);
         mLayoutAlgorithm = layoutAlgorithm;
+        mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
+                com.android.internal.R.interpolator.linear_out_slow_in);
         setStackScroll(getStackScroll());
     }
 
@@ -140,8 +146,9 @@
 
         mFinalAnimatedScroll = newScroll;
         mScrollAnimator = ObjectAnimator.ofFloat(this, "stackScroll", curScroll, newScroll);
-        mScrollAnimator.setDuration(mConfig.taskStackScrollDuration);
-        mScrollAnimator.setInterpolator(mConfig.linearOutSlowInInterpolator);
+        mScrollAnimator.setDuration(mContext.getResources().getInteger(
+                R.integer.recents_animate_task_stack_scroll_duration));
+        mScrollAnimator.setInterpolator(mLinearOutSlowInInterpolator);
         mScrollAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
             @Override
             public void onAnimationUpdate(ValueAnimator animation) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
index 7d079d9..86eced8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
@@ -26,7 +26,7 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.systemui.recents.Constants;
 import com.android.systemui.recents.Recents;
-import com.android.systemui.recents.RecentsConfiguration;
+import com.android.systemui.R;
 
 import java.util.List;
 
@@ -34,7 +34,7 @@
 class TaskStackViewTouchHandler implements SwipeHelper.Callback {
     static int INACTIVE_POINTER_ID = -1;
 
-    RecentsConfiguration mConfig;
+    Context mContext;
     TaskStackView mSv;
     TaskStackViewScroller mScroller;
     VelocityTracker mVelocityTracker;
@@ -62,7 +62,8 @@
     boolean mInterceptedBySwipeHelper;
 
     public TaskStackViewTouchHandler(Context context, TaskStackView sv,
-            RecentsConfiguration config, TaskStackViewScroller scroller) {
+            TaskStackViewScroller scroller) {
+        mContext = context;
         ViewConfiguration configuration = ViewConfiguration.get(context);
         mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
         mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
@@ -71,10 +72,9 @@
         mWindowTouchSlop = configuration.getScaledWindowTouchSlop();
         mSv = sv;
         mScroller = scroller;
-        mConfig = config;
 
         float densityScale = context.getResources().getDisplayMetrics().density;
-        mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, densityScale, mPagingTouchSlop);
+        mSwipeHelper = new SwipeHelper(context, SwipeHelper.X, this, densityScale, mPagingTouchSlop);
         mSwipeHelper.setMinAlpha(1f);
     }
 
@@ -268,7 +268,8 @@
                     if (Float.compare(overScrollAmount, 0f) != 0) {
                         // Bound the overscroll to a fixed amount, and inversely scale the y-movement
                         // relative to how close we are to the max overscroll
-                        float maxOverScroll = mConfig.taskStackOverscrollPct;
+                        float maxOverScroll = mContext.getResources().getFloat(
+                                R.dimen.recents_stack_overscroll_percentage);
                         deltaP *= (1f - (Math.min(maxOverScroll, overScrollAmount)
                                 / maxOverScroll));
                     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index 373fe7b..bbbaccf 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -20,16 +20,25 @@
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
 import android.content.Context;
-import android.graphics.*;
+import android.content.res.Resources;
+import android.graphics.Color;
+import android.graphics.Outline;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
+import android.graphics.Rect;
 import android.util.AttributeSet;
-import android.view.accessibility.AccessibilityManager;
 import android.view.View;
 import android.view.ViewOutlineProvider;
+import android.view.accessibility.AccessibilityManager;
 import android.view.animation.AccelerateInterpolator;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
 import android.widget.FrameLayout;
 import com.android.internal.logging.MetricsLogger;
 import com.android.systemui.R;
 import com.android.systemui.recents.Constants;
+import com.android.systemui.recents.RecentsActivityLaunchState;
 import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.misc.Utilities;
 import com.android.systemui.recents.model.Task;
@@ -75,6 +84,10 @@
     View mActionButtonView;
     TaskViewCallbacks mCb;
 
+    Interpolator mFastOutSlowInInterpolator;
+    Interpolator mFastOutLinearInInterpolator;
+    Interpolator mQuintOutInterpolator;
+
     // Optimizations
     ValueAnimator.AnimatorUpdateListener mUpdateDimListener =
             new ValueAnimator.AnimatorUpdateListener() {
@@ -99,14 +112,22 @@
 
     public TaskView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
+        Resources res = context.getResources();
         mConfig = RecentsConfiguration.getInstance();
-        mMaxDimScale = mConfig.taskStackMaxDim / 255f;
+        mMaxDimScale = res.getInteger(R.integer.recents_max_task_stack_view_dim) / 255f;
         mClipViewInStack = true;
-        mViewBounds = new AnimateableViewBounds(this, mConfig.taskViewRoundedCornerRadiusPx);
+        mViewBounds = new AnimateableViewBounds(this, res.getDimensionPixelSize(
+                R.dimen.recents_task_view_rounded_corners_radius));
+        mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
+                com.android.internal.R.interpolator.fast_out_slow_in);
+        mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context,
+                com.android.internal.R.interpolator.fast_out_linear_in);
+        mQuintOutInterpolator = AnimationUtils.loadInterpolator(context,
+                com.android.internal.R.interpolator.decelerate_quint);
         setTaskProgress(getTaskProgress());
         setDim(getDim());
         if (mConfig.fakeShadows) {
-            setBackground(new FakeShadowDrawable(context.getResources(), mConfig));
+            setBackground(new FakeShadowDrawable(res, mConfig));
         }
         setOutlineProvider(mViewBounds);
     }
@@ -159,6 +180,7 @@
 
         int widthWithoutPadding = width - mPaddingLeft - mPaddingRight;
         int heightWithoutPadding = height - mPaddingTop - mPaddingBottom;
+        int taskBarHeight = getResources().getDimensionPixelSize(R.dimen.recents_task_bar_height);
 
         // Measure the content
         mContent.measure(MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.EXACTLY),
@@ -166,7 +188,7 @@
 
         // Measure the bar view, and action button
         mHeaderView.measure(MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.EXACTLY),
-                MeasureSpec.makeMeasureSpec(mConfig.taskBarHeight, MeasureSpec.EXACTLY));
+                MeasureSpec.makeMeasureSpec(taskBarHeight, MeasureSpec.EXACTLY));
         mActionButtonView.measure(
                 MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.AT_MOST),
                 MeasureSpec.makeMeasureSpec(heightWithoutPadding, MeasureSpec.AT_MOST));
@@ -186,7 +208,7 @@
     void updateViewPropertiesToTaskTransform(TaskViewTransform toTransform, int duration,
                                              ValueAnimator.AnimatorUpdateListener updateCallback) {
         // Apply the transform
-        toTransform.applyToTaskView(this, duration, mConfig.fastOutSlowInInterpolator, false,
+        toTransform.applyToTaskView(this, duration, mFastOutSlowInInterpolator, false,
                 !mConfig.fakeShadows, updateCallback);
 
         // Update the task progress
@@ -238,10 +260,11 @@
      * first layout because the actual animation into recents may take a long time. */
     void prepareEnterRecentsAnimation(boolean isTaskViewLaunchTargetTask,
                                              boolean occludesLaunchTarget, int offscreenY) {
+        RecentsActivityLaunchState launchState = mConfig.getLaunchState();
         int initialDim = getDim();
-        if (mConfig.launchedHasConfigurationChanged) {
+        if (launchState.launchedHasConfigurationChanged) {
             // Just load the views as-is
-        } else if (mConfig.launchedFromAppWithThumbnail) {
+        } else if (launchState.launchedFromAppWithThumbnail) {
             if (isTaskViewLaunchTargetTask) {
                 // Set the dim to 0 so we can animate it in
                 initialDim = 0;
@@ -252,7 +275,7 @@
                 setTranslationY(offscreenY);
             }
 
-        } else if (mConfig.launchedFromHome) {
+        } else if (launchState.launchedFromHome) {
             // Move the task view off screen (below) so we can animate it in
             setTranslationY(offscreenY);
             setTranslationZ(0);
@@ -267,45 +290,59 @@
 
     /** Animates this task view as it enters recents */
     void startEnterRecentsAnimation(final ViewAnimation.TaskViewEnterContext ctx) {
+        RecentsActivityLaunchState launchState = mConfig.getLaunchState();
+        Resources res = mContext.getResources();
         final TaskViewTransform transform = ctx.currentTaskTransform;
+        final int transitionEnterFromAppDelay = res.getInteger(
+                R.integer.recents_enter_from_app_transition_duration);
+        final int transitionEnterFromHomeDelay = res.getInteger(
+                R.integer.recents_enter_from_home_transition_duration);
+        final int taskViewEnterFromAppDuration = res.getInteger(
+                R.integer.recents_task_enter_from_app_duration);
+        final int taskViewEnterFromHomeDuration = res.getInteger(
+                R.integer.recents_task_enter_from_home_duration);
+        final int taskViewEnterFromHomeStaggerDelay = res.getInteger(
+                R.integer.recents_task_enter_from_home_stagger_delay);
+        final int taskViewAffiliateGroupEnterOffset = res.getDimensionPixelSize(
+                R.dimen.recents_task_view_affiliate_group_enter_offset);
         int startDelay = 0;
 
-        if (mConfig.launchedFromAppWithThumbnail) {
+        if (launchState.launchedFromAppWithThumbnail) {
             if (mTask.isLaunchTarget) {
                 // Animate the dim/overlay
                 if (Constants.DebugFlags.App.EnableThumbnailAlphaOnFrontmost) {
                     // Animate the thumbnail alpha before the dim animation (to prevent updating the
                     // hardware layer)
-                    mThumbnailView.startEnterRecentsAnimation(mConfig.transitionEnterFromAppDelay,
+                    mThumbnailView.startEnterRecentsAnimation(transitionEnterFromAppDelay,
                             new Runnable() {
                                 @Override
                                 public void run() {
-                                    animateDimToProgress(0, mConfig.taskViewEnterFromAppDuration,
+                                    animateDimToProgress(0, taskViewEnterFromAppDuration,
                                             ctx.postAnimationTrigger.decrementOnAnimationEnd());
                                 }
                             });
                 } else {
                     // Immediately start the dim animation
-                    animateDimToProgress(mConfig.transitionEnterFromAppDelay,
-                            mConfig.taskViewEnterFromAppDuration,
+                    animateDimToProgress(transitionEnterFromAppDelay,
+                            taskViewEnterFromAppDuration,
                             ctx.postAnimationTrigger.decrementOnAnimationEnd());
                 }
                 ctx.postAnimationTrigger.increment();
 
                 // Animate the action button in
-                fadeInActionButton(mConfig.transitionEnterFromAppDelay,
-                        mConfig.taskViewEnterFromAppDuration);
+                fadeInActionButton(transitionEnterFromAppDelay,
+                        taskViewEnterFromAppDuration);
             } else {
                 // Animate the task up if it was occluding the launch target
                 if (ctx.currentTaskOccludesLaunchTarget) {
-                    setTranslationY(transform.translationY + mConfig.taskViewAffiliateGroupEnterOffsetPx);
+                    setTranslationY(transform.translationY + taskViewAffiliateGroupEnterOffset);
                     setAlpha(0f);
                     animate().alpha(1f)
                             .translationY(transform.translationY)
-                            .setStartDelay(mConfig.transitionEnterFromAppDelay)
+                            .setStartDelay(transitionEnterFromAppDelay)
                             .setUpdateListener(null)
-                            .setInterpolator(mConfig.fastOutSlowInInterpolator)
-                            .setDuration(mConfig.taskViewEnterFromHomeDuration)
+                            .setInterpolator(mFastOutSlowInInterpolator)
+                            .setDuration(taskViewEnterFromHomeDuration)
                             .withEndAction(new Runnable() {
                                 @Override
                                 public void run() {
@@ -317,13 +354,13 @@
                     ctx.postAnimationTrigger.increment();
                 }
             }
-            startDelay = mConfig.transitionEnterFromAppDelay;
+            startDelay = transitionEnterFromAppDelay;
 
-        } else if (mConfig.launchedFromHome) {
+        } else if (launchState.launchedFromHome) {
             // Animate the tasks up
             int frontIndex = (ctx.currentStackViewCount - ctx.currentStackViewIndex - 1);
-            int delay = mConfig.transitionEnterFromHomeDelay +
-                    frontIndex * mConfig.taskViewEnterFromHomeStaggerDelay;
+            int delay = transitionEnterFromHomeDelay +
+                    frontIndex * taskViewEnterFromHomeStaggerDelay;
 
             setScaleX(transform.scale);
             setScaleY(transform.scale);
@@ -334,9 +371,9 @@
                     .translationY(transform.translationY)
                     .setStartDelay(delay)
                     .setUpdateListener(ctx.updateListener)
-                    .setInterpolator(mConfig.quintOutInterpolator)
-                    .setDuration(mConfig.taskViewEnterFromHomeDuration +
-                            frontIndex * mConfig.taskViewEnterFromHomeStaggerDelay)
+                    .setInterpolator(mQuintOutInterpolator)
+                    .setDuration(taskViewEnterFromHomeDuration +
+                            frontIndex * taskViewEnterFromHomeStaggerDelay)
                     .withEndAction(new Runnable() {
                         @Override
                         public void run() {
@@ -373,12 +410,14 @@
 
     /** Animates this task view as it leaves recents by pressing home. */
     void startExitToHomeAnimation(ViewAnimation.TaskViewExitContext ctx) {
+        int taskViewExitToHomeDuration = getResources().getInteger(
+                R.integer.recents_task_exit_to_home_duration);
         animate()
                 .translationY(ctx.offscreenTranslationY)
                 .setStartDelay(0)
                 .setUpdateListener(null)
-                .setInterpolator(mConfig.fastOutLinearInInterpolator)
-                .setDuration(mConfig.taskViewExitToHomeDuration)
+                .setInterpolator(mFastOutLinearInInterpolator)
+                .setDuration(taskViewExitToHomeDuration)
                 .withEndAction(ctx.postAnimationTrigger.decrementAsRunnable())
                 .start();
         ctx.postAnimationTrigger.increment();
@@ -392,6 +431,11 @@
     /** Animates this task view as it exits recents */
     void startLaunchTaskAnimation(final Runnable postAnimRunnable, boolean isLaunchingTask,
             boolean occludesLaunchTarget, boolean lockToTask) {
+        final int taskViewExitToAppDuration = mContext.getResources().getInteger(
+                R.integer.recents_task_exit_to_app_duration);
+        final int taskViewAffiliateGroupEnterOffset = mContext.getResources().getDimensionPixelSize(
+                R.dimen.recents_task_view_affiliate_group_enter_offset);
+
         if (isLaunchingTask) {
             // Animate the thumbnail alpha back into full opacity for the window animation out
             mThumbnailView.startLaunchTaskAnimation(postAnimRunnable);
@@ -399,8 +443,8 @@
             // Animate the dim
             if (mDimAlpha > 0) {
                 ObjectAnimator anim = ObjectAnimator.ofInt(this, "dim", 0);
-                anim.setDuration(mConfig.taskViewExitToAppDuration);
-                anim.setInterpolator(mConfig.fastOutLinearInInterpolator);
+                anim.setDuration(taskViewExitToAppDuration);
+                anim.setInterpolator(mFastOutLinearInInterpolator);
                 anim.start();
             }
 
@@ -414,8 +458,8 @@
             mActionButtonView.animate()
                     .alpha(0f)
                     .setStartDelay(0)
-                    .setDuration(mConfig.taskViewExitToAppDuration)
-                    .setInterpolator(mConfig.fastOutLinearInInterpolator)
+                    .setDuration(taskViewExitToAppDuration)
+                    .setInterpolator(mFastOutLinearInInterpolator)
                     .start();
         } else {
             // Hide the dismiss button
@@ -424,11 +468,11 @@
             // animate it away first
             if (occludesLaunchTarget) {
                 animate().alpha(0f)
-                    .translationY(getTranslationY() + mConfig.taskViewAffiliateGroupEnterOffsetPx)
+                    .translationY(getTranslationY() + taskViewAffiliateGroupEnterOffset)
                     .setStartDelay(0)
                     .setUpdateListener(null)
-                    .setInterpolator(mConfig.fastOutLinearInInterpolator)
-                    .setDuration(mConfig.taskViewExitToAppDuration)
+                    .setInterpolator(mFastOutLinearInInterpolator)
+                    .setDuration(taskViewExitToAppDuration)
                     .start();
             }
         }
@@ -436,15 +480,20 @@
 
     /** Animates the deletion of this task view */
     void startDeleteTaskAnimation(final Runnable r, int delay) {
+        int taskViewRemoveAnimDuration = getResources().getInteger(
+                R.integer.recents_animate_task_view_remove_duration);
+        int taskViewRemoveAnimTranslationXPx = getResources().getDimensionPixelSize(
+                R.dimen.recents_task_view_remove_anim_translation_x);
+
         // Disabling clipping with the stack while the view is animating away
         setClipViewInStack(false);
 
-        animate().translationX(mConfig.taskViewRemoveAnimTranslationXPx)
+        animate().translationX(taskViewRemoveAnimTranslationXPx)
             .alpha(0f)
             .setStartDelay(delay)
             .setUpdateListener(null)
-            .setInterpolator(mConfig.fastOutSlowInInterpolator)
-            .setDuration(mConfig.taskViewRemoveAnimDuration)
+            .setInterpolator(mFastOutSlowInInterpolator)
+            .setDuration(taskViewRemoveAnimDuration)
             .withEndAction(new Runnable() {
                 @Override
                 public void run() {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
index 3e9410e..f68dd64 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -26,19 +26,21 @@
 import android.content.res.ColorStateList;
 import android.graphics.Canvas;
 import android.graphics.Color;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.GradientDrawable;
-import android.graphics.drawable.RippleDrawable;
 import android.graphics.Outline;
 import android.graphics.Paint;
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffColorFilter;
 import android.graphics.PorterDuffXfermode;
 import android.graphics.Rect;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.GradientDrawable;
+import android.graphics.drawable.RippleDrawable;
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.ViewOutlineProvider;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.TextView;
@@ -67,6 +69,8 @@
     boolean mCurrentPrimaryColorIsDark;
     int mCurrentPrimaryColor;
     int mBackgroundColor;
+    int mCornerRadius;
+    int mHighlightHeight;
     Drawable mLightDismissDrawable;
     Drawable mDarkDismissDrawable;
     RippleDrawable mBackground;
@@ -81,6 +85,9 @@
     Paint mDimLayerPaint = new Paint();
     PorterDuffColorFilter mDimColorFilter = new PorterDuffColorFilter(0, PorterDuff.Mode.SRC_ATOP);
 
+    Interpolator mFastOutSlowInInterpolator;
+    Interpolator mFastOutLinearInInterpolator;
+
     boolean mLayersDisabled;
 
     public TaskViewHeader(Context context) {
@@ -113,13 +120,21 @@
         mDarkDismissDrawable = context.getDrawable(R.drawable.recents_dismiss_dark);
         mDismissContentDescription =
                 context.getString(R.string.accessibility_recents_item_will_be_dismissed);
+        mCornerRadius = getResources().getDimensionPixelSize(
+                R.dimen.recents_task_view_rounded_corners_radius);
+        mHighlightHeight = getResources().getDimensionPixelSize(
+                R.dimen.recents_task_view_highlight);
+        mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
+                com.android.internal.R.interpolator.fast_out_slow_in);
+        mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context,
+                com.android.internal.R.interpolator.fast_out_linear_in);
 
         // Configure the highlight paint
         if (sHighlightPaint == null) {
             sHighlightPaint = new Paint();
             sHighlightPaint.setStyle(Paint.Style.STROKE);
-            sHighlightPaint.setStrokeWidth(mConfig.taskViewHighlightPx);
-            sHighlightPaint.setColor(mConfig.taskBarViewHighlightColor);
+            sHighlightPaint.setStrokeWidth(mHighlightHeight);
+            sHighlightPaint.setColor(context.getColor(R.color.recents_task_bar_highlight_color));
             sHighlightPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.ADD));
             sHighlightPaint.setAntiAlias(true);
         }
@@ -154,8 +169,8 @@
     @Override
     protected void onDraw(Canvas canvas) {
         // Draw the highlight at the top edge (but put the bottom edge just out of view)
-        float offset = (float) Math.ceil(mConfig.taskViewHighlightPx / 2f);
-        float radius = mConfig.taskViewRoundedCornerRadiusPx;
+        float offset = (float) Math.ceil(mHighlightHeight / 2f);
+        float radius = mCornerRadius;
         int count = canvas.save(Canvas.CLIP_SAVE_FLAG);
         canvas.clipRect(0, 0, getMeasuredWidth(), getMeasuredHeight());
         canvas.drawRoundRect(-offset, 0f, (float) getMeasuredWidth() + offset,
@@ -207,10 +222,15 @@
             mBackgroundColorDrawable.setColor(t.colorPrimary);
             mBackgroundColor = t.colorPrimary;
         }
+
+        int taskBarViewLightTextColor = getResources().getColor(
+                R.color.recents_task_bar_light_text_color);
+        int taskBarViewDarkTextColor = getResources().getColor(
+                R.color.recents_task_bar_dark_text_color);
         mCurrentPrimaryColor = t.colorPrimary;
         mCurrentPrimaryColorIsDark = t.useLightOnPrimaryColor;
         mActivityDescription.setTextColor(t.useLightOnPrimaryColor ?
-                mConfig.taskBarViewLightTextColor : mConfig.taskBarViewDarkTextColor);
+                taskBarViewLightTextColor : taskBarViewDarkTextColor);
         mDismissButton.setImageDrawable(t.useLightOnPrimaryColor ?
                 mLightDismissDrawable : mDarkDismissDrawable);
         mDismissButton.setContentDescription(String.format(mDismissContentDescription,
@@ -262,12 +282,14 @@
     /** Animates this task bar dismiss button when launching a task. */
     void startLaunchTaskDismissAnimation() {
         if (mDismissButton.getVisibility() == View.VISIBLE) {
+            int taskViewExitToAppDuration = mContext.getResources().getInteger(
+                    R.integer.recents_task_exit_to_app_duration);
             mDismissButton.animate().cancel();
             mDismissButton.animate()
                     .alpha(0f)
                     .setStartDelay(0)
-                    .setInterpolator(mConfig.fastOutSlowInInterpolator)
-                    .setDuration(mConfig.taskViewExitToAppDuration)
+                    .setInterpolator(mFastOutSlowInInterpolator)
+                    .setDuration(taskViewExitToAppDuration)
                     .start();
         }
     }
@@ -280,8 +302,9 @@
             mDismissButton.animate()
                     .alpha(1f)
                     .setStartDelay(0)
-                    .setInterpolator(mConfig.fastOutLinearInInterpolator)
-                    .setDuration(mConfig.taskViewEnterFromAppDuration)
+                    .setInterpolator(mFastOutLinearInInterpolator)
+                    .setDuration(getResources().getInteger(
+                            R.integer.recents_task_enter_from_app_duration))
                     .start();
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
index 117a7d3..6c83bee 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
@@ -32,9 +32,11 @@
 import android.graphics.Shader;
 import android.util.AttributeSet;
 import android.view.View;
-import com.android.systemui.recents.RecentsConfiguration;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
 import com.android.systemui.recents.misc.Utilities;
 import com.android.systemui.recents.model.Task;
+import com.android.systemui.R;
 
 
 /**
@@ -43,9 +45,8 @@
  */
 public class TaskViewThumbnail extends View {
 
-    RecentsConfiguration mConfig;
-
     // Drawing
+    int mCornerRadius;
     float mDimAlpha;
     Matrix mScaleMatrix = new Matrix();
     Paint mDrawPaint = new Paint();
@@ -54,6 +55,8 @@
     BitmapShader mBitmapShader;
     LightingColorFilter mLightingColorFilter = new LightingColorFilter(0xffffffff, 0);
 
+    Interpolator mFastOutSlowInInterpolator;
+
     // Thumbnail alpha
     float mThumbnailAlpha;
     ValueAnimator mThumbnailAlphaAnimator;
@@ -89,15 +92,18 @@
 
     public TaskViewThumbnail(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
-        mConfig = RecentsConfiguration.getInstance();
         mDrawPaint.setColorFilter(mLightingColorFilter);
         mDrawPaint.setFilterBitmap(true);
         mDrawPaint.setAntiAlias(true);
+        mCornerRadius = getResources().getDimensionPixelSize(
+                R.dimen.recents_task_view_rounded_corners_radius);
+        mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
+                com.android.internal.R.interpolator.fast_out_slow_in);
     }
 
     @Override
     protected void onFinishInflate() {
-        mThumbnailAlpha = mConfig.taskViewThumbnailAlpha;
+        mThumbnailAlpha = getResources().getFloat(R.dimen.recents_task_view_thumbnail_alpha);
         updateThumbnailPaintFilter();
     }
 
@@ -117,8 +123,8 @@
         }
         // Draw the thumbnail with the rounded corners
         canvas.drawRoundRect(0, 0, getWidth(), getHeight(),
-                mConfig.taskViewRoundedCornerRadiusPx,
-                mConfig.taskViewRoundedCornerRadiusPx, mDrawPaint);
+                mCornerRadius,
+                mCornerRadius, mDrawPaint);
     }
 
     /** Sets the thumbnail to a given bitmap. */
@@ -215,8 +221,10 @@
                 startFadeAnimation(1f, 0, 150, null);
             }
         } else {
-            if (Float.compare(getAlpha(), mConfig.taskViewThumbnailAlpha) != 0) {
-                startFadeAnimation(mConfig.taskViewThumbnailAlpha, 0, 150, null);
+            float taskViewThumbnailAlpha = getResources().getFloat(
+                    R.dimen.recents_task_view_thumbnail_alpha);
+            if (Float.compare(getAlpha(), taskViewThumbnailAlpha) != 0) {
+                startFadeAnimation(taskViewThumbnailAlpha, 0, 150, null);
             }
         }
     }
@@ -229,20 +237,26 @@
         if (isTaskViewLaunchTargetTask) {
             mThumbnailAlpha = 1f;
         } else {
-            mThumbnailAlpha = mConfig.taskViewThumbnailAlpha;
+            mThumbnailAlpha = getResources().getFloat(
+                    R.dimen.recents_task_view_thumbnail_alpha);
         }
         updateThumbnailPaintFilter();
     }
 
     /** Animates this task thumbnail as it enters Recents. */
     void startEnterRecentsAnimation(int delay, Runnable postAnimRunnable) {
-        startFadeAnimation(mConfig.taskViewThumbnailAlpha, delay,
-                mConfig.taskViewEnterFromAppDuration, postAnimRunnable);
+        float taskViewThumbnailAlpha = getResources().getFloat(
+                R.dimen.recents_task_view_thumbnail_alpha);
+        startFadeAnimation(taskViewThumbnailAlpha, delay,
+                getResources().getInteger(R.integer.recents_task_enter_from_app_duration),
+                postAnimRunnable);
     }
 
     /** Animates this task thumbnail as it exits Recents. */
     void startLaunchTaskAnimation(Runnable postAnimRunnable) {
-        startFadeAnimation(1f, 0, mConfig.taskViewExitToAppDuration, postAnimRunnable);
+        int taskViewExitToAppDuration = mContext.getResources().getInteger(
+                R.integer.recents_task_exit_to_app_duration);
+        startFadeAnimation(1f, 0, taskViewExitToAppDuration, postAnimRunnable);
     }
 
     /** Starts a new thumbnail alpha animation. */
@@ -251,7 +265,7 @@
         mThumbnailAlphaAnimator = ValueAnimator.ofFloat(mThumbnailAlpha, finalAlpha);
         mThumbnailAlphaAnimator.setStartDelay(delay);
         mThumbnailAlphaAnimator.setDuration(duration);
-        mThumbnailAlphaAnimator.setInterpolator(mConfig.fastOutSlowInInterpolator);
+        mThumbnailAlphaAnimator.setInterpolator(mFastOutSlowInInterpolator);
         mThumbnailAlphaAnimator.addUpdateListener(mThumbnailAlphaUpdateListener);
         if (postAnimRunnable != null) {
             mThumbnailAlphaAnimator.addListener(new AnimatorListenerAdapter() {