OSDN Git Service

SystemUI: Support recents task locking
authorAnas Karbila <anaskarbila@gmail.com>
Sun, 30 Apr 2017 17:20:07 +0000 (02:20 +0900)
committerJoey Rizzoli <joey@lineageos.it>
Sun, 11 Jun 2017 05:55:20 +0000 (05:55 +0000)
This adds the ability to lock task in recents so they won't be cleared when removing all tasks

Ticket: NOUGAT-1

Drawables from material.io

Change-Id: I06ffe411e72d4e837cfec7b9b77fb2519e417bc7

packages/SystemUI/res/drawable/recents_locked_dark.xml [new file with mode: 0644]
packages/SystemUI/res/drawable/recents_locked_light.xml [new file with mode: 0644]
packages/SystemUI/res/drawable/recents_unlocked_dark.xml [new file with mode: 0644]
packages/SystemUI/res/drawable/recents_unlocked_light.xml [new file with mode: 0644]
packages/SystemUI/res/layout/recents_task_view_header.xml
packages/SystemUI/res/values/cm_dimens.xml
packages/SystemUI/src/com/android/systemui/recents/Recents.java
packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java

diff --git a/packages/SystemUI/res/drawable/recents_locked_dark.xml b/packages/SystemUI/res/drawable/recents_locked_dark.xml
new file mode 100644 (file)
index 0000000..c0ab016
--- /dev/null
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:height="24dp"
+        android:width="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="@color/recents_task_bar_dark_icon_color"
+        android:pathData="M18,8h-1L17,6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6v2L6,8c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,10c0,-1.1 -0.9,-2 -2,-2zM12,17c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2zM15.1,8L8.9,8L8.9,6c0,-1.71 1.39,-3.1 3.1,-3.1 1.71,0 3.1,1.39 3.1,3.1v2z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/recents_locked_light.xml b/packages/SystemUI/res/drawable/recents_locked_light.xml
new file mode 100644 (file)
index 0000000..ee26161
--- /dev/null
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:height="24dp"
+        android:width="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="@color/recents_task_bar_light_icon_color"
+        android:pathData="M18,8h-1L17,6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6v2L6,8c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,10c0,-1.1 -0.9,-2 -2,-2zM12,17c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2zM15.1,8L8.9,8L8.9,6c0,-1.71 1.39,-3.1 3.1,-3.1 1.71,0 3.1,1.39 3.1,3.1v2z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/recents_unlocked_dark.xml b/packages/SystemUI/res/drawable/recents_unlocked_dark.xml
new file mode 100644 (file)
index 0000000..a4216b7
--- /dev/null
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:height="24dp"
+        android:width="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="@color/recents_task_bar_dark_icon_color"
+        android:pathData="M12,17c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM18,8h-1L17,6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6h1.9c0,-1.71 1.39,-3.1 3.1,-3.1 1.71,0 3.1,1.39 3.1,3.1v2L6,8c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,10c0,-1.1 -0.9,-2 -2,-2zM18,20L6,20L6,10h12v10z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/recents_unlocked_light.xml b/packages/SystemUI/res/drawable/recents_unlocked_light.xml
new file mode 100644 (file)
index 0000000..12dedb6
--- /dev/null
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:height="24dp"
+        android:width="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="@color/recents_task_bar_light_icon_color"
+        android:pathData="M12,17c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM18,8h-1L17,6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6h1.9c0,-1.71 1.39,-3.1 3.1,-3.1 1.71,0 3.1,1.39 3.1,3.1v2L6,8c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,10c0,-1.1 -0.9,-2 -2,-2zM18,20L6,20L6,10h12v10z" />
+</vector>
index 5ee242d..a602a02 100644 (file)
         android:background="?android:selectableItemBackground"
         android:alpha="0"
         android:visibility="gone" />
+    <com.android.systemui.recents.views.FixedSizeImageView
+        android:id="@+id/lock_task"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginEnd="@dimen/recents_task_view_header_lock_button_padding"
+        android:layout_gravity="end|center"
+        android:padding="@dimen/recents_task_view_header_button_padding"
+        android:src="@drawable/recents_dismiss_light"
+        android:background="?android:selectableItemBackground"
+        android:alpha="0"
+        android:visibility="gone" />
 
     <!-- The progress indicator shows if auto-paging is enabled -->
     <ViewStub android:id="@+id/focus_timer_indicator_stub"
index e1cd6fa..9d5a7aa 100644 (file)
@@ -29,4 +29,6 @@
 
     <dimen name="navbar_single_hand_mode_horizontal_threshhold">90dp</dimen>
     <dimen name="navbar_single_hand_mode_vertical_threshhold">48dp</dimen>
+
+    <dimen name="recents_task_view_header_lock_button_padding">48dp</dimen>
 </resources>
index ba50c66..0315757 100644 (file)
@@ -57,6 +57,7 @@ import com.android.systemui.recents.events.component.ShowUserToastEvent;
 import com.android.systemui.recents.events.ui.RecentsDrawnEvent;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.recents.model.RecentsTaskLoader;
+import com.android.systemui.recents.model.Task;
 import com.android.systemui.recents.tv.RecentsTvImpl;
 import com.android.systemui.stackdivider.Divider;
 
@@ -85,6 +86,8 @@ public class Recents extends SystemUI
         RECENTS_ACTIVITIES.add(RecentsTvImpl.RECENTS_TV_ACTIVITY);
     }
 
+    public final static Set<Task> sLockedTasks = new HashSet<>();
+
     // Purely for experimentation
     private final static String RECENTS_OVERRIDE_SYSPROP_KEY = "persist.recents_override_pkg";
     private final static String ACTION_SHOW_RECENTS = "com.android.systemui.recents.ACTION_SHOW";
index 9b25ef8..c5fa71a 100644 (file)
@@ -631,6 +631,9 @@ public class TaskStack {
      * how they should update themselves.
      */
     public void removeTask(Task t, AnimationProps animation, boolean fromDockGesture) {
+        if (Recents.sLockedTasks.contains(t)) {
+            Recents.sLockedTasks.remove(t);
+        }
         if (mStackTaskList.contains(t)) {
             removeTaskImpl(mStackTaskList, t);
             Task newFrontMostTask = getStackFrontMostTask(false  /* includeFreeform */);
@@ -650,6 +653,9 @@ public class TaskStack {
         ArrayList<Task> tasks = mStackTaskList.getTasks();
         for (int i = tasks.size() - 1; i >= 0; i--) {
             Task t = tasks.get(i);
+            if (Recents.sLockedTasks.contains(t)) {
+                continue;
+            }
             removeTaskImpl(mStackTaskList, t);
             mRawTaskList.remove(t);
         }
index 3c5a141..37fec65 100644 (file)
@@ -1809,8 +1809,16 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
     public final void onBusEvent(final DismissAllTaskViewsEvent event) {
         // Keep track of the tasks which will have their data removed
         ArrayList<Task> tasks = new ArrayList<>(mStack.getStackTasks());
+        ArrayList<TaskView> deletedTasks = new ArrayList<>();
+        ArrayList<TaskView> taskViews = new ArrayList<>(getTaskViews());
+        for (TaskView t : taskViews) {
+            if (Recents.sLockedTasks.contains(t.getTask())) {
+                deletedTasks.add(t);
+            }
+        }
+        taskViews.removeAll(deletedTasks);
         mAnimationHelper.startDeleteAllTasksAnimation(
-                getTaskViews(), useGridLayout(), event.getAnimationTrigger());
+                taskViews, useGridLayout(), event.getAnimationTrigger());
         event.addPostAnimationCallback(new Runnable() {
             @Override
             public void run() {
@@ -1821,7 +1829,9 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
                 // Remove all tasks and delete the task data for all tasks
                 mStack.removeAllTasks();
                 for (int i = tasks.size() - 1; i >= 0; i--) {
-                    EventBus.getDefault().send(new DeleteTaskDataEvent(tasks.get(i)));
+                    Task t = tasks.get(i);
+                    if (Recents.sLockedTasks.contains(t)) continue;
+                    EventBus.getDefault().send(new DeleteTaskDataEvent(t));
                 }
 
                 MetricsLogger.action(getContext(), MetricsEvent.OVERVIEW_DISMISS_ALL);
index 003138f..b43ed88 100644 (file)
@@ -449,8 +449,8 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
         // Disallow dismissing an already dismissed task
         TaskView tv = (TaskView) v;
         Task task = tv.getTask();
-        return !mSwipeHelperAnimations.containsKey(v) &&
-                (mSv.getStack().indexOfStackTask(task) != -1);
+        return !mSwipeHelperAnimations.containsKey(v) && !Recents.sLockedTasks.contains(task)
+                && (mSv.getStack().indexOfStackTask(task) != -1);
     }
 
     /**
index dc666e9..30e4422 100644 (file)
@@ -56,6 +56,7 @@ import com.android.systemui.recents.events.ui.ShowApplicationInfoEvent;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.recents.misc.Utilities;
 import com.android.systemui.recents.model.Task;
+import com.android.systemui.recents.model.TaskStack;
 
 import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
 import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
@@ -146,6 +147,7 @@ public class TaskViewHeader extends FrameLayout
     TextView mTitleView;
     ImageView mMoveTaskButton;
     ImageView mDismissButton;
+    ImageView mLockTaskButton;
     FrameLayout mAppOverlayView;
     ImageView mAppIconView;
     ImageView mAppInfoView;
@@ -169,6 +171,10 @@ public class TaskViewHeader extends FrameLayout
     Drawable mDarkFullscreenIcon;
     Drawable mLightInfoIcon;
     Drawable mDarkInfoIcon;
+    Drawable mLightLockedDrawable;
+    Drawable mLightUnlockedDrawable;
+    Drawable mDarkLockedDrawable;
+    Drawable mDarkUnlockedDrawable;
     int mTaskBarViewLightTextColor;
     int mTaskBarViewDarkTextColor;
     int mDisabledTaskBarBackgroundColor;
@@ -222,6 +228,10 @@ public class TaskViewHeader extends FrameLayout
         mDarkInfoIcon = context.getDrawable(R.drawable.recents_info_dark);
         mDisabledTaskBarBackgroundColor =
                 context.getColor(R.color.recents_task_bar_disabled_background_color);
+        mLightLockedDrawable = context.getDrawable(R.drawable.recents_locked_light);
+        mLightUnlockedDrawable = context.getDrawable(R.drawable.recents_unlocked_light);
+        mDarkLockedDrawable = context.getDrawable(R.drawable.recents_locked_dark);
+        mDarkUnlockedDrawable = context.getDrawable(R.drawable.recents_unlocked_dark);
 
         // Configure the background and dim
         mBackground = new HighlightColorDrawable();
@@ -248,6 +258,7 @@ public class TaskViewHeader extends FrameLayout
         mIconView.setOnLongClickListener(this);
         mTitleView = (TextView) findViewById(R.id.title);
         mDismissButton = (ImageView) findViewById(R.id.dismiss_task);
+        mLockTaskButton = (ImageView) findViewById(R.id.lock_task);
         if (ssp.hasFreeformWorkspaceSupport()) {
             mMoveTaskButton = (ImageView) findViewById(R.id.move_task);
         }
@@ -361,6 +372,7 @@ public class TaskViewHeader extends FrameLayout
         }
         mDismissButton.setVisibility(showDismissIcon ? View.VISIBLE : View.INVISIBLE);
         mDismissButton.setTranslationX(rightInset);
+        mLockTaskButton.setVisibility(showDismissIcon ? View.VISIBLE : View.INVISIBLE);
 
         setLeftTopRightBottom(0, 0, width, getMeasuredHeight());
     }
@@ -456,6 +468,12 @@ public class TaskViewHeader extends FrameLayout
         mShouldDarkenBackgroundColor = flag;
     }
 
+    private void updateLockTaskDrawable() {
+        mLockTaskButton.setImageDrawable(mTask.useLightOnPrimaryColor ?
+                (Recents.sLockedTasks.contains(mTask) ? mLightLockedDrawable : mLightUnlockedDrawable) :
+                (Recents.sLockedTasks.contains(mTask) ? mDarkLockedDrawable : mDarkUnlockedDrawable));
+    }
+
     /**
      * Binds the bar view to the task.
      */
@@ -480,6 +498,10 @@ public class TaskViewHeader extends FrameLayout
         mDismissButton.setOnClickListener(this);
         mDismissButton.setClickable(false);
         ((RippleDrawable) mDismissButton.getBackground()).setForceSoftware(true);
+        updateLockTaskDrawable();
+        mLockTaskButton.setOnClickListener(this);
+        mLockTaskButton.setClickable(false);
+        ((RippleDrawable) mLockTaskButton.getBackground()).setForceSoftware(true);
 
         // When freeform workspaces are enabled, then update the move-task button depending on the
         // current task
@@ -552,6 +574,17 @@ public class TaskViewHeader extends FrameLayout
         } else {
             mDismissButton.setAlpha(1f);
         }
+        mLockTaskButton.setVisibility(View.VISIBLE);
+        mLockTaskButton.setClickable(true);
+        if (mLockTaskButton.getVisibility() == VISIBLE) {
+            mLockTaskButton.animate()
+                    .alpha(1f)
+                    .setInterpolator(Interpolators.FAST_OUT_LINEAR_IN)
+                    .setDuration(duration)
+                    .start();
+        } else {
+            mLockTaskButton.setAlpha(1f);
+        }
         if (mMoveTaskButton != null) {
             if (mMoveTaskButton.getVisibility() == VISIBLE) {
                 mMoveTaskButton.setVisibility(View.VISIBLE);
@@ -576,6 +609,10 @@ public class TaskViewHeader extends FrameLayout
         mDismissButton.animate().cancel();
         mDismissButton.setAlpha(1f);
         mDismissButton.setClickable(true);
+        mLockTaskButton.setVisibility(View.VISIBLE);
+        mLockTaskButton.animate().cancel();
+        mLockTaskButton.setAlpha(1f);
+        mLockTaskButton.setClickable(true);
         if (mMoveTaskButton != null) {
             mMoveTaskButton.setVisibility(View.VISIBLE);
             mMoveTaskButton.animate().cancel();
@@ -592,6 +629,9 @@ public class TaskViewHeader extends FrameLayout
         mDismissButton.setVisibility(View.INVISIBLE);
         mDismissButton.setAlpha(0f);
         mDismissButton.setClickable(false);
+        mLockTaskButton.setVisibility(View.INVISIBLE);
+        mLockTaskButton.setAlpha(0f);
+        mLockTaskButton.setClickable(false);
         if (mMoveTaskButton != null) {
             mMoveTaskButton.setVisibility(View.INVISIBLE);
             mMoveTaskButton.setAlpha(0f);
@@ -614,11 +654,13 @@ public class TaskViewHeader extends FrameLayout
             EventBus.getDefault().send(new ShowApplicationInfoEvent(mTask));
         } else if (v == mDismissButton) {
             TaskView tv = Utilities.findParent(this, TaskView.class);
-            tv.dismissTask();
+            if (!Recents.sLockedTasks.contains(tv.getTask())) {
+                tv.dismissTask();
 
-            // Keep track of deletions by the dismiss button
-            MetricsLogger.histogram(getContext(), "overview_task_dismissed_source",
-                    Constants.Metrics.DismissSourceHeaderButton);
+                // Keep track of deletions by the dismiss button
+                MetricsLogger.histogram(getContext(), "overview_task_dismissed_source",
+                        Constants.Metrics.DismissSourceHeaderButton);
+            }
         } else if (v == mMoveTaskButton) {
             TaskView tv = Utilities.findParent(this, TaskView.class);
             EventBus.getDefault().send(new LaunchTaskEvent(tv, mTask, null,
@@ -627,6 +669,13 @@ public class TaskViewHeader extends FrameLayout
             EventBus.getDefault().send(new ShowApplicationInfoEvent(mTask));
         } else if (v == mAppIconView) {
             hideAppOverlay(false /* immediate */);
+        } else if (v == mLockTaskButton) {
+            if (Recents.sLockedTasks.contains(mTask)) {
+               Recents.sLockedTasks.remove(mTask);
+            } else {
+               Recents.sLockedTasks.add(mTask);
+            }
+            updateLockTaskDrawable();
         }
     }