• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.quickstep;
18 
19 import androidx.annotation.Nullable;
20 
21 import com.android.quickstep.util.DesksUtils;
22 import com.android.quickstep.util.GroupTask;
23 import com.android.quickstep.views.TaskViewType;
24 import com.android.systemui.shared.recents.model.Task;
25 
26 import java.util.HashMap;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.Objects;
30 import java.util.function.Predicate;
31 
32 /**
33  * Keeps track of the state of {@code RecentsView}.
34  *
35  * <p> More specifically, used for keeping track of the state of filters applied on tasks
36  * in {@code RecentsView} for multi-instance management.
37  */
38 public class RecentsFilterState {
39     // the minimum number of tasks per package present to allow filtering
40     public static final int MIN_FILTERING_TASK_COUNT = 2;
41 
42     // default filter that returns true for any input
43     public static final Predicate<GroupTask> EMPTY_FILTER = (groupTask -> true);
44 
45     // the package name to filter recent tasks by
46     @Nullable
47     private String mPackageNameToFilter = null;
48 
49     // the callback that gets executed upon filter change
50     @Nullable
51     private Runnable mOnFilterUpdatedListener = null;
52 
53     // map maintaining the count for each unique base activity package name currently in the recents
54     @Nullable
55     private Map<String, Integer> mInstanceCountMap;
56 
57     /**
58      * Returns {@code true} if {@code RecentsView} filters tasks by some package name.
59      */
isFiltered()60     public boolean isFiltered() {
61         return mPackageNameToFilter != null;
62     }
63 
64     /**
65      * Returns the package name that tasks are filtered by.
66      */
67     @Nullable
getPackageNameToFilter()68     public String getPackageNameToFilter() {
69         return mPackageNameToFilter;
70     }
71 
72 
73     /**
74      * Sets a listener on any changes to the filter.
75      *
76      * @param callback listener to be executed upon filter updates
77      */
setOnFilterUpdatedListener(@ullable Runnable callback)78     public void setOnFilterUpdatedListener(@Nullable Runnable callback) {
79         mOnFilterUpdatedListener = callback;
80     }
81 
82     /**
83      * Updates the filter such that tasks are filtered by a certain package name.
84      *
85      * @param packageName package name of the base activity to filter tasks by;
86      *                    if null, filter is turned off
87      */
setFilterBy(@ullable String packageName)88     public void setFilterBy(@Nullable String packageName) {
89         if (Objects.equals(packageName, mPackageNameToFilter)) {
90             return;
91         }
92 
93         mPackageNameToFilter = packageName;
94 
95         if (mOnFilterUpdatedListener != null) {
96             mOnFilterUpdatedListener.run();
97         }
98     }
99 
100     /**
101      * Updates the map of package names to their count in the most recent list of tasks.
102      *
103      * @param groupTaskList the list of tasks that map update is be based on
104      */
updateInstanceCountMap(List<GroupTask> groupTaskList)105     public void updateInstanceCountMap(List<GroupTask> groupTaskList) {
106         mInstanceCountMap = getInstanceCountMap(groupTaskList);
107     }
108 
109     /**
110      * Returns the map of package names to their count in the most recent list of tasks.
111      */
112     @Nullable
getInstanceCountMap()113     public Map<String, Integer> getInstanceCountMap() {
114         return mInstanceCountMap;
115     }
116 
117     /**
118      * Returns a predicate for filtering out GroupTasks by package name.
119      *
120      * @param packageName package name to filter GroupTasks by
121      *                    if null, Predicate filters out desktop tasks with no non-minimized tasks,
122      *                    unless the multiple desks feature is enabled, which allows empty desks.
123      */
getFilter(@ullable String packageName)124     public static Predicate<GroupTask> getFilter(@Nullable String packageName) {
125         if (packageName == null) {
126             return getDesktopTaskFilter();
127         }
128 
129         return (groupTask) -> (groupTask.containsPackage(packageName)
130                 && shouldKeepGroupTask(groupTask));
131     }
132 
133     /**
134      * Returns a predicate that filters out desk tasks that contain no non-minimized desktop tasks,
135      * unless the multiple desks feature is enabled, which allows empty desks.
136      */
getDesktopTaskFilter()137     public static Predicate<GroupTask> getDesktopTaskFilter() {
138         return (groupTask -> shouldKeepGroupTask(groupTask));
139     }
140 
141     /**
142      * Returns true if the given `groupTask` should be kept, and false if it should be filtered out.
143      * Desks will be filtered out if they are empty unless the multiple desks feature is enabled.
144      *
145      * @param groupTask The group task to check.
146      */
shouldKeepGroupTask(GroupTask groupTask)147     private static boolean shouldKeepGroupTask(GroupTask groupTask) {
148         if (groupTask.taskViewType != TaskViewType.DESKTOP) {
149             return true;
150         }
151 
152         if (DesksUtils.areMultiDesksFlagsEnabled()) {
153             return true;
154         }
155 
156         return groupTask.getTasks().stream()
157                 .anyMatch(task -> !task.isMinimized);
158     }
159 
160     /**
161      * Returns a map of package names to their frequencies in a list of GroupTasks.
162      *
163      * @param groupTasks the list to go through to create the map
164      */
getInstanceCountMap(List<GroupTask> groupTasks)165     public static Map<String, Integer> getInstanceCountMap(List<GroupTask> groupTasks) {
166         Map<String, Integer> instanceCountMap = new HashMap<>();
167 
168         for (GroupTask groupTask : groupTasks) {
169             for (Task t : groupTask.getTasks()) {
170                 final String taskPkgName = t.key.getPackageName();
171                 incrementOrAddIfNotExists(instanceCountMap, taskPkgName);
172             }
173         }
174 
175         return instanceCountMap;
176     }
177 
178     /**
179      * Returns true if tasks of provided package name should show filter UI.
180      *
181      * @param taskPackageName package name of the task in question
182      */
shouldShowFilterUI(String taskPackageName)183     public boolean shouldShowFilterUI(String taskPackageName) {
184         // number of occurrences in recents overview with the package name of this task
185         int instanceCount = getInstanceCountMap().get(taskPackageName);
186 
187         // if the number of occurrences isn't enough make sure tasks can't be filtered by
188         // the package name of this task
189         return !(isFiltered() || instanceCount < MIN_FILTERING_TASK_COUNT);
190     }
191 
incrementOrAddIfNotExists(Map<String, Integer> map, String pkgName)192     private static void incrementOrAddIfNotExists(Map<String, Integer> map, String pkgName) {
193         if (!map.containsKey(pkgName)) {
194             map.put(pkgName, 0);
195         }
196         map.put(pkgName, map.get(pkgName) + 1);
197     }
198 }
199