Indicator for task auto-select

Change-Id: I081222b84a5f90e77890724977821ed481fe3924
diff --git a/packages/SystemUI/res/layout/recents_task_view_header.xml b/packages/SystemUI/res/layout/recents_task_view_header.xml
index 04f18c5..07ac39a 100644
--- a/packages/SystemUI/res/layout/recents_task_view_header.xml
+++ b/packages/SystemUI/res/layout/recents_task_view_header.xml
@@ -1,12 +1,13 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
+<!--
+     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.
@@ -63,4 +64,12 @@
         android:background="@drawable/recents_button_bg"
         android:visibility="invisible"
         android:src="@drawable/recents_dismiss_light" />
+    <ProgressBar
+        android:id="@+id/focus_timer_indicator"
+        style="?android:attr/progressBarStyleHorizontal"
+        android:layout_width="match_parent"
+        android:layout_height="5dp"
+        android:layout_gravity="bottom"
+        android:indeterminateOnly="false"
+        android:visibility="invisible" />
 </com.android.systemui.recents.views.TaskViewHeader>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 955af82..916e497 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -177,6 +177,9 @@
     <!-- The animation duration for scrolling the stack to a particular item. -->
     <integer name="recents_animate_task_stack_scroll_duration">200</integer>
 
+    <!-- The animation duration for scrolling the stack to a particular item. -->
+    <integer name="recents_auto_advance_duration">2000</integer>
+
     <!-- The animation duration for entering and exiting the history. -->
     <integer name="recents_history_transition_duration">250</integer>
 
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 0e4f98f..c600a1f 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1173,6 +1173,11 @@
     <!-- Description for the toggle for fast-toggling recents via the recents button. DO NOT TRANSLATE -->
     <string name="overview_fast_toggle_via_button_desc">Enable launch timeout while paging</string>
 
+    <!-- Toggles the fast-toggling indicator. DO NOT TRANSLATE -->
+    <string name="overview_fast_toggle_indicator">Enable fast toggle indicator</string>
+    <!-- Description for the fast-toggling indicator. DO NOT TRANSLATE -->
+    <string name="overview_fast_toggle_indicator_desc">Show an indicator for the launch timeout</string>
+
     <!-- Toggle to set the initial scroll state to be paging or stack. DO NOT TRANSLATE -->
     <string name="overview_initial_state_paging">Initialize to paging</string>
     <!-- Description for the toggle to set the initial scroll state to be paging or stack. DO NOT TRANSLATE -->
diff --git a/packages/SystemUI/res/xml/tuner_prefs.xml b/packages/SystemUI/res/xml/tuner_prefs.xml
index 90cd394..11ef735d 100644
--- a/packages/SystemUI/res/xml/tuner_prefs.xml
+++ b/packages/SystemUI/res/xml/tuner_prefs.xml
@@ -84,6 +84,12 @@
             android:title="@string/overview_fast_toggle_via_button"
             android:summary="@string/overview_fast_toggle_via_button_desc" />
 
+        <com.android.systemui.tuner.TunerSwitch
+            android:key="overview_fast_toggle_indicator"
+            android:title="@string/overview_fast_toggle_indicator"
+            android:summary="@string/overview_fast_toggle_indicator_desc"
+            android:dependency="overview_fast_toggle_via_button" />
+
     </PreferenceScreen>
 
     <SwitchPreference
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index e4d8067..40864c9 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -5,7 +5,7 @@
  * 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
+ * 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,
@@ -113,16 +113,12 @@
     private FinishRecentsRunnable mFinishLaunchHomeRunnable;
 
     // The trigger to automatically launch the current task
-    private DozeTrigger mIterateTrigger = new DozeTrigger(500, new Runnable() {
-        @Override
-        public void run() {
-            dismissRecentsToFocusedTask();
-        }
-    });
+    private int mFocusTimerDuration;
+    private DozeTrigger mIterateTrigger;
 
     /**
      * A common Runnable to finish Recents by launching Home with an animation depending on the
-     * last activity launch state.  Generally we always launch home when we exit Recents rather than
+     * last activity launch state. Generally we always launch home when we exit Recents rather than
      * just finishing the activity since we don't know what is behind Recents in the task stack.
      */
     class FinishRecentsRunnable implements Runnable {
@@ -218,8 +214,8 @@
         boolean animateStatusBarScrim = launchState.launchedFromHome;
         boolean hasNavBarScrim = (stack.getStackTaskCount() > 0) && !config.hasTransposedNavBar;
         boolean animateNavBarScrim = true;
-        mScrimViews.prepareEnterRecentsAnimation(hasStatusBarScrim, animateStatusBarScrim, hasNavBarScrim,
-                animateNavBarScrim);
+        mScrimViews.prepareEnterRecentsAnimation(hasStatusBarScrim, animateStatusBarScrim,
+                hasNavBarScrim, animateNavBarScrim);
 
         // Keep track of whether we launched from the nav bar button or via alt-tab
         if (launchState.launchedWithAltTab) {
@@ -357,6 +353,14 @@
         getWindow().getAttributes().privateFlags |=
                 WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY;
 
+        mFocusTimerDuration = getResources().getInteger(R.integer.recents_auto_advance_duration);
+        mIterateTrigger = new DozeTrigger(mFocusTimerDuration, new Runnable() {
+            @Override
+            public void run() {
+                dismissRecentsToFocusedTask();
+            }
+        });
+
         // Create the home intent runnable
         Intent homeIntent = new Intent(Intent.ACTION_MAIN, null);
         homeIntent.addCategory(Intent.CATEGORY_HOME);
@@ -543,7 +547,8 @@
                     if (backward) {
                         EventBus.getDefault().send(new FocusPreviousTaskViewEvent());
                     } else {
-                        EventBus.getDefault().send(new FocusNextTaskViewEvent());
+                        EventBus.getDefault().send(
+                                new FocusNextTaskViewEvent(false /* showTimerIndicator */));
                     }
                     mLastTabKeyEventTime = SystemClock.elapsedRealtime();
 
@@ -555,7 +560,8 @@
                 return true;
             }
             case KeyEvent.KEYCODE_DPAD_UP: {
-                EventBus.getDefault().send(new FocusNextTaskViewEvent());
+                EventBus.getDefault().send(
+                        new FocusNextTaskViewEvent(false /* showTimerIndicator */));
                 return true;
             }
             case KeyEvent.KEYCODE_DPAD_DOWN: {
@@ -579,7 +585,9 @@
 
     @Override
     public void onUserInteraction() {
-        EventBus.getDefault().send(new UserInteractionEvent());
+        final RecentsDebugFlags debugFlags = Recents.getDebugFlags();
+        EventBus.getDefault().send(new UserInteractionEvent(debugFlags.isFastToggleRecentsEnabled()
+                && debugFlags.isFastToggleIndicatorEnabled()));
     }
 
     @Override
@@ -603,11 +611,14 @@
 
     public final void onBusEvent(IterateRecentsEvent event) {
         if (!dismissHistory()) {
+            final RecentsDebugFlags debugFlags = Recents.getDebugFlags();
+
             // Focus the next task
-            EventBus.getDefault().send(new FocusNextTaskViewEvent());
+            EventBus.getDefault().send(
+                    new FocusNextTaskViewEvent(debugFlags.isFastToggleRecentsEnabled()
+                            && debugFlags.isFastToggleIndicatorEnabled()));
 
             // Start dozing after the recents button is clicked
-            RecentsDebugFlags debugFlags = Recents.getDebugFlags();
             if (debugFlags.isFastToggleRecentsEnabled()) {
                 if (!mIterateTrigger.isDozing()) {
                     mIterateTrigger.startDozing();
@@ -701,7 +712,7 @@
         intent.setComponent(intent.resolveActivity(getPackageManager()));
         TaskStackBuilder.create(this)
                 .addNextIntentWithParentStack(intent).startActivities(null,
-                new UserHandle(event.task.key.userId));
+                        new UserHandle(event.task.key.userId));
 
         // Keep track of app-info invocations
         MetricsLogger.count(this, "overview_app_info", 1);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
index c323522..3151fd7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
@@ -27,6 +27,7 @@
 public class RecentsDebugFlags implements TunerService.Tunable {
 
     private static final String KEY_FAST_TOGGLE = "overview_fast_toggle_via_button";
+    private static final String KEY_FAST_TOGGLE_INDICATOR = "overview_fast_toggle_indicator";
     private static final String KEY_INITIAL_STATE_PAGING = "overview_initial_state_paging";
 
     public static class Static {
@@ -49,6 +50,7 @@
     }
 
     private boolean mFastToggleRecents;
+    private boolean mFastToggleIndicator;
     private boolean mInitialStatePaging;
 
     /**
@@ -58,7 +60,8 @@
     public RecentsDebugFlags(Context context) {
         // Register all our flags, this will also call onTuningChanged() for each key, which will
         // initialize the current state of each flag
-        TunerService.get(context).addTunable(this, KEY_FAST_TOGGLE, KEY_INITIAL_STATE_PAGING);
+        TunerService.get(context).addTunable(this, KEY_FAST_TOGGLE, KEY_FAST_TOGGLE_INDICATOR,
+                KEY_INITIAL_STATE_PAGING);
     }
 
     /**
@@ -69,6 +72,13 @@
     }
 
     /**
+     * @return whether we are enabling the fast toggle indicator.
+     */
+    public boolean isFastToggleIndicatorEnabled() {
+        return mFastToggleIndicator;
+    }
+
+    /**
      * @return whether the initial stack state is paging.
      */
     public boolean isInitialStatePaging() {
@@ -82,6 +92,10 @@
                 mFastToggleRecents = (newValue != null) &&
                         (Integer.parseInt(newValue) != 0);
                 break;
+            case KEY_FAST_TOGGLE_INDICATOR:
+                mFastToggleIndicator = (newValue != null) &&
+                        (Integer.parseInt(newValue) != 0);
+                break;
             case KEY_INITIAL_STATE_PAGING:
                 mInitialStatePaging = (newValue != null) &&
                         (Integer.parseInt(newValue) != 0);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/UserInteractionEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/UserInteractionEvent.java
index 6e6cd84..5a132c2 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/UserInteractionEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/UserInteractionEvent.java
@@ -22,5 +22,10 @@
  * This is sent whenever the user interacts with the activity.
  */
 public class UserInteractionEvent extends EventBus.Event {
-    // Simple event
+
+    public final boolean showTimerIndicator;
+
+    public UserInteractionEvent(boolean showTimerIndicator) {
+        this.showTimerIndicator = showTimerIndicator;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/FocusNextTaskViewEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/FocusNextTaskViewEvent.java
index 171ab5e..def4ae1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/FocusNextTaskViewEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/FocusNextTaskViewEvent.java
@@ -22,5 +22,10 @@
  * Focuses the next task view in the stack.
  */
 public class FocusNextTaskViewEvent extends EventBus.Event {
-    // Simple event
+
+    public final boolean showTimerIndicator;
+
+    public FocusNextTaskViewEvent(boolean showTimerIndicator) {
+        this.showTimerIndicator = showTimerIndicator;
+    }
 }
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 9568fac..ceab9c7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -126,6 +126,7 @@
     GradientDrawable mFreeformWorkspaceBackground;
     ObjectAnimator mFreeformWorkspaceBackgroundAnimator;
     ViewPool<TaskView, Task> mViewPool;
+    boolean mStartTimerIndicator;
 
     ArrayList<TaskView> mTaskViews = new ArrayList<>();
     ArrayList<TaskViewTransform> mCurrentTaskTransforms = new ArrayList<>();
@@ -623,6 +624,16 @@
      */
     private boolean setFocusedTask(int taskIndex, boolean scrollToTask,
             final boolean requestViewFocus) {
+        return setFocusedTask(taskIndex, scrollToTask, requestViewFocus, false);
+    }
+
+    /**
+     * Sets the focused task to the provided (bounded taskIndex).
+     *
+     * @return whether or not the stack will scroll as a part of this focus change
+     */
+    private boolean setFocusedTask(int taskIndex, boolean scrollToTask,
+            final boolean requestViewFocus, final boolean showTimerIndicator) {
         // Find the next task to focus
         int newFocusedTaskIndex = mStack.getStackTaskCount() > 0 ?
                 Math.max(0, Math.min(mStack.getStackTaskCount() - 1, taskIndex)) : -1;
@@ -632,15 +643,36 @@
         // Reset the last focused task state if changed
         if (mFocusedTask != null) {
             resetFocusedTask(mFocusedTask);
+
+            // Cancel the timer indicator, if applicable
+            if (showTimerIndicator) {
+                final TaskView tv = getChildViewForTask(mFocusedTask);
+                if (tv != null) {
+                    tv.getHeaderView().cancelFocusTimerIndicator();
+                }
+            }
         }
 
         boolean willScroll = false;
+
         mFocusedTask = newFocusedTask;
+
         if (newFocusedTask != null) {
+            // Start the timer indicator, if applicable
+            if (showTimerIndicator) {
+                final TaskView tv = getChildViewForTask(mFocusedTask);
+                if (tv != null) {
+                    tv.getHeaderView().startFocusTimerIndicator();
+                } else {
+                    // The view is null; set a flag for later
+                    mStartTimerIndicator = true;
+                }
+            }
+
             Runnable focusTaskRunnable = new Runnable() {
                 @Override
                 public void run() {
-                    TaskView tv = getChildViewForTask(newFocusedTask);
+                    final TaskView tv = getChildViewForTask(newFocusedTask);
                     if (tv != null) {
                         tv.setFocusedState(true, requestViewFocus);
                     }
@@ -694,10 +726,28 @@
      * @param animated determines whether to actually draw the highlight along with the change in
      *                            focus.
      * @param cancelWindowAnimations if set, will attempt to cancel window animations if a scroll
-     *                               happens
+     *                               happens.
      */
     public void setRelativeFocusedTask(boolean forward, boolean stackTasksOnly, boolean animated,
                                        boolean cancelWindowAnimations) {
+        setRelativeFocusedTask(forward, stackTasksOnly, animated, false, false);
+    }
+
+    /**
+     * Sets the focused task relative to the currently focused task.
+     *
+     * @param forward whether to go to the next task in the stack (along the curve) or the previous
+     * @param stackTasksOnly if set, will ensure that the traversal only goes along stack tasks, and
+     *                       if the currently focused task is not a stack task, will set the focus
+     *                       to the first visible stack task
+     * @param animated determines whether to actually draw the highlight along with the change in
+     *                            focus.
+     * @param cancelWindowAnimations if set, will attempt to cancel window animations if a scroll
+     *                               happens.
+     * @param showTimerIndicator determines whether or not to show an indicator for the task auto-advance.
+     */
+    public void setRelativeFocusedTask(boolean forward, boolean stackTasksOnly, boolean animated,
+                                       boolean cancelWindowAnimations, boolean showTimerIndicator) {
         int newIndex = mStack.indexOfStackTask(mFocusedTask);
         if (mFocusedTask != null) {
             if (stackTasksOnly) {
@@ -733,7 +783,7 @@
         }
         if (newIndex != -1) {
             boolean willScroll = setFocusedTask(newIndex, true /* scrollToTask */,
-                    true /* requestViewFocus */);
+                    true /* requestViewFocus */, showTimerIndicator);
             if (willScroll && cancelWindowAnimations) {
                 // As we iterate to the next/previous task, cancel any current/lagging window
                 // transition animations
@@ -1210,6 +1260,11 @@
         tv.setClipViewInStack(true);
         if (mFocusedTask == task) {
             tv.setFocusedState(true, false /* requestViewFocus */);
+            if (mStartTimerIndicator) {
+                // The timer indicator couldn't be started before, so start it now
+                tv.getHeaderView().startFocusTimerIndicator();
+                mStartTimerIndicator = false;
+            }
         }
 
         // Restore the action button visibility if it is the front most task view
@@ -1318,7 +1373,8 @@
     }
 
     public final void onBusEvent(FocusNextTaskViewEvent event) {
-        setRelativeFocusedTask(true, false /* stackTasksOnly */, true /* animated */);
+        setRelativeFocusedTask(true, false /* stackTasksOnly */, true /* animated */, false,
+                event.showTimerIndicator);
     }
 
     public final void onBusEvent(FocusPreviousTaskViewEvent event) {
@@ -1328,6 +1384,9 @@
     public final void onBusEvent(UserInteractionEvent event) {
         // Poke the doze trigger on user interaction
         mUIDozeTrigger.poke();
+        if (event.showTimerIndicator && mFocusedTask != null) {
+            getChildViewForTask(mFocusedTask).getHeaderView().cancelFocusTimerIndicator();
+        }
     }
 
     public final void onBusEvent(RecentsVisibilityChangedEvent event) {
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 bc441b2..7abbdb8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -360,6 +360,10 @@
         updateDimFromTaskProgress();
     }
 
+    public TaskViewHeader getHeaderView() {
+        return mHeaderView;
+    }
+
     /** Returns the current task progress. */
     public float getTaskProgress() {
         return mTaskProgress;
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 6a47424..00d64fe 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -5,7 +5,7 @@
  * 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
+ * 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,
@@ -23,17 +23,20 @@
 import android.graphics.Color;
 import android.graphics.ColorFilter;
 import android.graphics.Paint;
+import android.graphics.PorterDuff;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.RippleDrawable;
 import android.support.v4.graphics.ColorUtils;
+import android.os.CountDownTimer;
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
+import android.widget.ProgressBar;
 import android.widget.TextView;
 import com.android.internal.logging.MetricsLogger;
 
@@ -51,12 +54,12 @@
 import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
 import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
 
-
 /* The task bar view */
 public class TaskViewHeader extends FrameLayout
         implements View.OnClickListener, View.OnLongClickListener {
 
     private static final float HIGHLIGHT_LIGHTNESS_INCREMENT = 0.125f;
+    private static final long FOCUS_INDICATOR_INTERVAL_MS = 30;
 
     /**
      * A color drawable that draws a slight highlight at the top to help it stand out.
@@ -124,6 +127,7 @@
     ImageView mIconView;
     TextView mTitleView;
     int mMoveTaskTargetStackId = INVALID_STACK_ID;
+    ProgressBar mFocusTimerIndicator;
 
     // Header drawables
     Rect mTaskViewRect = new Rect();
@@ -145,6 +149,10 @@
     Interpolator mFastOutSlowInInterpolator;
     Interpolator mFastOutLinearInInterpolator;
 
+    long mFocusIndicatorProgress;
+    private CountDownTimer mFocusTimerCountDown;
+    long mFocusTimerDuration;
+
     public TaskViewHeader(Context context) {
         this(context, null);
     }
@@ -182,6 +190,7 @@
         setBackground(mBackground);
         mDimLayerPaint.setColor(Color.argb(255, 0, 0, 0));
         mDimLayerPaint.setAntiAlias(true);
+        mFocusTimerDuration = res.getInteger(R.integer.recents_auto_advance_duration);
     }
 
     @Override
@@ -193,6 +202,7 @@
         mDismissButton = (ImageView) findViewById(R.id.dismiss_task);
         mDismissButton.setOnClickListener(this);
         mMoveTaskButton = (ImageView) findViewById(R.id.move_task);
+        mFocusTimerIndicator = (ProgressBar) findViewById(R.id.focus_timer_indicator);
 
         // Hide the backgrounds if they are ripple drawables
         if (mIconView.getBackground() instanceof RippleDrawable) {
@@ -268,6 +278,41 @@
                 mCornerRadius, mCornerRadius, mDimLayerPaint);
     }
 
+    /** Starts the focus timer. */
+    public void startFocusTimerIndicator() {
+        mFocusTimerIndicator.setVisibility(View.VISIBLE);
+        mFocusTimerIndicator.setMax((int) mFocusTimerDuration);
+        if (mFocusTimerCountDown == null) {
+            mFocusTimerCountDown = new CountDownTimer(mFocusTimerDuration,
+                    FOCUS_INDICATOR_INTERVAL_MS) {
+                public void onTick(long millisUntilFinished) {
+                    mFocusTimerIndicator.setProgress((int) millisUntilFinished);
+                }
+
+                public void onFinish() {
+                    mFocusTimerIndicator.setProgress((int) mFocusTimerDuration);
+                }
+            }.start();
+        } else {
+            mFocusTimerCountDown.start();
+        }
+    }
+
+    /** Cancels the focus timer. */
+    public void cancelFocusTimerIndicator() {
+        if (mFocusTimerCountDown != null && mFocusTimerIndicator != null) {
+            mFocusTimerCountDown.cancel();
+            mFocusTimerIndicator.setProgress(0);
+            mFocusTimerIndicator.setVisibility(View.INVISIBLE);
+        }
+    }
+
+    /** Returns the secondary color for a primary color. */
+    int getSecondaryColor(int primaryColor, boolean useLightOverlayColor) {
+        int overlayColor = useLightOverlayColor ? Color.WHITE : Color.BLACK;
+        return Utilities.getColorWithOverlay(primaryColor, overlayColor, 0.8f);
+    }
+
     /**
      * Sets the dim alpha, only used when we are not using hardware layers.
      * (see RecentsConfiguration.useHardwareLayers)
@@ -330,6 +375,11 @@
             mMoveTaskButton.setOnClickListener(this);
         }
 
+        mFocusTimerIndicator.getProgressDrawable()
+                .setColorFilter(
+                        getSecondaryColor(t.colorPrimary, t.useLightOnPrimaryColor),
+                        PorterDuff.Mode.SRC_IN);
+
         // In accessibility, a single click on the focused app info button will show it
         if (ssp.isTouchExplorationEnabled()) {
             mIconView.setOnClickListener(this);
@@ -359,7 +409,10 @@
         }
     }
 
-    /** Mark this task view that the user does has not interacted with the stack after a certain time. */
+    /**
+     * Mark this task view that the user does has not interacted with the stack after a certain
+     * time.
+     */
     void setNoUserInteractionState() {
         if (mDismissButton.getVisibility() != View.VISIBLE) {
             mDismissButton.animate().cancel();
@@ -368,7 +421,10 @@
         }
     }
 
-    /** Resets the state tracking that the user has not interacted with the stack after a certain time. */
+    /**
+     * Resets the state tracking that the user has not interacted with the stack after a certain
+     * time.
+     */
     void resetNoUserInteractionState() {
         mDismissButton.setVisibility(View.INVISIBLE);
     }