diff options
70 files changed, 2038 insertions, 1739 deletions
diff --git a/packages/SystemUI/Android.mk b/packages/SystemUI/Android.mk index 2fd7e87a683e..2c5eb27abe3d 100644 --- a/packages/SystemUI/Android.mk +++ b/packages/SystemUI/Android.mk @@ -31,6 +31,7 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-Iaidl-files-unde LOCAL_STATIC_ANDROID_LIBRARIES := \ SystemUIPluginLib \ + SystemUISharedLib \ android-support-v4 \ android-support-v7-recyclerview \ android-support-v7-preference \ diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 7ccb6b0db128..1536b64dc41f 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -451,8 +451,6 @@ <string name="accessibility_recents_item_open_app_info">Open <xliff:g id="app" example="Calendar">%s</xliff:g> application info.</string> <!-- Content description to tell the user an application has been launched from recents --> <string name="accessibility_recents_item_launched">Starting <xliff:g id="app" example="Calendar">%s</xliff:g>.</string> - <!-- Content description of individual recents task. --> - <string name="accessibility_recents_task_header"><xliff:g id="app" example="Chrome">%1$s</xliff:g> <xliff:g id="activity_label" example="www.google.com">%2$s</xliff:g></string> <!-- Content description to tell the user a notification has been removed from the notification shade --> <string name="accessibility_notification_dismissed">Notification dismissed.</string> @@ -810,10 +808,6 @@ <!-- Recents: Accessibility split to the right --> <string name="recents_accessibility_split_screen_right">Split screen to the right</string> - <!-- Fully qualified activity class names to be blacklisted in Recents, add package names into overlay as needed --> - <string-array name="recents_blacklist_array"> - </string-array> - <!-- Expanded Status Bar Header: Battery Charged [CHAR LIMIT=40] --> <string name="expanded_header_battery_charged">Charged</string> diff --git a/packages/SystemUI/shared/Android.mk b/packages/SystemUI/shared/Android.mk new file mode 100644 index 000000000000..88a89bc8eba2 --- /dev/null +++ b/packages/SystemUI/shared/Android.mk @@ -0,0 +1,42 @@ +# Copyright (C) 2017 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. + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_USE_AAPT2 := true + +LOCAL_MODULE_TAGS := optional + +LOCAL_MODULE := SystemUISharedLib + +LOCAL_SRC_FILES := $(call all-java-files-under, src) + +LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res +LOCAL_JAR_EXCLUDE_FILES := none + +include $(BUILD_STATIC_JAVA_LIBRARY) + +include $(CLEAR_VARS) + +LOCAL_PACKAGE_NAME := SharedDummyLib +LOCAL_SRC_FILES := $(call all-java-files-under, src) + +LOCAL_JAVA_LIBRARIES := SystemUISharedLib + +LOCAL_PROGUARD_ENABLED := disabled + +include $(BUILD_PACKAGE) + +include $(call all-makefiles-under,$(LOCAL_PATH))
\ No newline at end of file diff --git a/packages/SystemUI/shared/AndroidManifest.xml b/packages/SystemUI/shared/AndroidManifest.xml new file mode 100644 index 000000000000..43b9c7574141 --- /dev/null +++ b/packages/SystemUI/shared/AndroidManifest.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2017 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. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.systemui.shared"> + + <uses-sdk + android:minSdkVersion="26" /> + +</manifest> diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/BackgroundTaskLoader.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/BackgroundTaskLoader.java new file mode 100644 index 000000000000..ddd27b0b38ba --- /dev/null +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/BackgroundTaskLoader.java @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2017 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.shared.recents.model; + +import android.content.Context; +import android.content.pm.ActivityInfo; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.os.Handler; +import android.os.HandlerThread; +import android.util.Log; + +import com.android.systemui.shared.system.ActivityManagerWrapper; +import com.android.systemui.shared.system.PackageManagerWrapper; + +/** + * Background task resource loader + */ +class BackgroundTaskLoader implements Runnable { + static String TAG = "BackgroundTaskLoader"; + static boolean DEBUG = false; + + private Context mContext; + private final HandlerThread mLoadThread; + private final Handler mLoadThreadHandler; + private final Handler mMainThreadHandler; + + private final TaskResourceLoadQueue mLoadQueue; + private final TaskKeyLruCache<Drawable> mIconCache; + private final BitmapDrawable mDefaultIcon; + + private boolean mStarted; + private boolean mCancelled; + private boolean mWaitingOnLoadQueue; + + private final OnIdleChangedListener mOnIdleChangedListener; + + /** Constructor, creates a new loading thread that loads task resources in the background */ + public BackgroundTaskLoader(TaskResourceLoadQueue loadQueue, + TaskKeyLruCache<Drawable> iconCache, BitmapDrawable defaultIcon, + OnIdleChangedListener onIdleChangedListener) { + mLoadQueue = loadQueue; + mIconCache = iconCache; + mDefaultIcon = defaultIcon; + mMainThreadHandler = new Handler(); + mOnIdleChangedListener = onIdleChangedListener; + mLoadThread = new HandlerThread("Recents-TaskResourceLoader", + android.os.Process.THREAD_PRIORITY_BACKGROUND); + mLoadThread.start(); + mLoadThreadHandler = new Handler(mLoadThread.getLooper()); + } + + /** Restarts the loader thread */ + void start(Context context) { + mContext = context; + mCancelled = false; + if (!mStarted) { + // Start loading on the load thread + mStarted = true; + mLoadThreadHandler.post(this); + } else { + // Notify the load thread to start loading again + synchronized (mLoadThread) { + mLoadThread.notifyAll(); + } + } + } + + /** Requests the loader thread to stop after the current iteration */ + void stop() { + // Mark as cancelled for the thread to pick up + mCancelled = true; + // If we are waiting for the load queue for more tasks, then we can just reset the + // Context now, since nothing is using it + if (mWaitingOnLoadQueue) { + mContext = null; + } + } + + @Override + public void run() { + while (true) { + if (mCancelled) { + // We have to unset the context here, since the background thread may be using it + // when we call stop() + mContext = null; + // If we are cancelled, then wait until we are started again + synchronized(mLoadThread) { + try { + mLoadThread.wait(); + } catch (InterruptedException ie) { + ie.printStackTrace(); + } + } + } else { + // If we've stopped the loader, then fall through to the above logic to wait on + // the load thread + processLoadQueueItem(); + + // If there are no other items in the list, then just wait until something is added + if (!mCancelled && mLoadQueue.isEmpty()) { + synchronized(mLoadQueue) { + try { + mWaitingOnLoadQueue = true; + mMainThreadHandler.post( + () -> mOnIdleChangedListener.onIdleChanged(true)); + mLoadQueue.wait(); + mMainThreadHandler.post( + () -> mOnIdleChangedListener.onIdleChanged(false)); + mWaitingOnLoadQueue = false; + } catch (InterruptedException ie) { + ie.printStackTrace(); + } + } + } + } + } + } + + /** + * This needs to be in a separate method to work around an surprising interpreter behavior: + * The register will keep the local reference to cachedThumbnailData even if it falls out of + * scope. Putting it into a method fixes this issue. + */ + private void processLoadQueueItem() { + // Load the next item from the queue + final Task t = mLoadQueue.nextTask(); + if (t != null) { + Drawable cachedIcon = mIconCache.get(t.key); + + // Load the icon if it is stale or we haven't cached one yet + if (cachedIcon == null) { + cachedIcon = ActivityManagerWrapper.getInstance().getBadgedTaskDescriptionIcon( + mContext, t.taskDescription, t.key.userId, mContext.getResources()); + + if (cachedIcon == null) { + ActivityInfo info = PackageManagerWrapper.getInstance().getActivityInfo( + t.key.getComponent(), t.key.userId); + if (info != null) { + if (DEBUG) Log.d(TAG, "Loading icon: " + t.key); + cachedIcon = ActivityManagerWrapper.getInstance().getBadgedActivityIcon( + info, t.key.userId); + } + } + + if (cachedIcon == null) { + cachedIcon = mDefaultIcon; + } + + // At this point, even if we can't load the icon, we will set the + // default icon. + mIconCache.put(t.key, cachedIcon); + } + + if (DEBUG) Log.d(TAG, "Loading thumbnail: " + t.key); + final ThumbnailData thumbnailData = + ActivityManagerWrapper.getInstance().getTaskThumbnail(t.key.id, + true /* reducedResolution */); + + if (!mCancelled) { + // Notify that the task data has changed + final Drawable finalIcon = cachedIcon; + mMainThreadHandler.post( + () -> t.notifyTaskDataLoaded(thumbnailData, finalIcon)); + } + } + } + + interface OnIdleChangedListener { + void onIdleChanged(boolean idle); + } +} diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/FilteredTaskList.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/FilteredTaskList.java new file mode 100644 index 000000000000..898d64a1ea1a --- /dev/null +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/FilteredTaskList.java @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2017 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.shared.recents.model; + +import android.util.ArrayMap; +import android.util.SparseArray; + +import com.android.systemui.shared.recents.model.Task.TaskKey; + +import java.util.ArrayList; +import java.util.List; + +/** + * A list of filtered tasks. + */ +class FilteredTaskList { + + private final ArrayList<Task> mTasks = new ArrayList<>(); + private final ArrayList<Task> mFilteredTasks = new ArrayList<>(); + private final ArrayMap<TaskKey, Integer> mFilteredTaskIndices = new ArrayMap<>(); + private TaskFilter mFilter; + + /** Sets the task filter, and returns whether the set of filtered tasks have changed. */ + boolean setFilter(TaskFilter filter) { + ArrayList<Task> prevFilteredTasks = new ArrayList<>(mFilteredTasks); + mFilter = filter; + updateFilteredTasks(); + return !prevFilteredTasks.equals(mFilteredTasks); + } + + /** Adds a new task to the task list */ + void add(Task t) { + mTasks.add(t); + updateFilteredTasks(); + } + + /** Sets the list of tasks */ + void set(List<Task> tasks) { + mTasks.clear(); + mTasks.addAll(tasks); + updateFilteredTasks(); + } + + /** Removes a task from the base list only if it is in the filtered list */ + boolean remove(Task t) { + if (mFilteredTasks.contains(t)) { + boolean removed = mTasks.remove(t); + updateFilteredTasks(); + return removed; + } + return false; + } + + /** Returns the index of this task in the list of filtered tasks */ + int indexOf(Task t) { + if (t != null && mFilteredTaskIndices.containsKey(t.key)) { + return mFilteredTaskIndices.get(t.key); + } + return -1; + } + + /** Returns the size of the list of filtered tasks */ + int size() { + return mFilteredTasks.size(); + } + + /** Returns whether the filtered list contains this task */ + boolean contains(Task t) { + return mFilteredTaskIndices.containsKey(t.key); + } + + /** Updates the list of filtered tasks whenever the base task list changes */ + private void updateFilteredTasks() { + mFilteredTasks.clear(); + if (mFilter != null) { + // Create a sparse array from task id to Task + SparseArray<Task> taskIdMap = new SparseArray<>(); + int taskCount = mTasks.size(); + for (int i = 0; i < taskCount; i++) { + Task t = mTasks.get(i); + taskIdMap.put(t.key.id, t); + } + + for (int i = 0; i < taskCount; i++) { + Task t = mTasks.get(i); + if (mFilter.acceptTask(taskIdMap, t, i)) { + mFilteredTasks.add(t); + } + } + } else { + mFilteredTasks.addAll(mTasks); + } + updateFilteredTaskIndices(); + } + + /** Updates the mapping of tasks to indices. */ + private void updateFilteredTaskIndices() { + int taskCount = mFilteredTasks.size(); + mFilteredTaskIndices.clear(); + for (int i = 0; i < taskCount; i++) { + Task t = mFilteredTasks.get(i); + mFilteredTaskIndices.put(t.key, i); + } + } + + /** Returns the list of filtered tasks */ + ArrayList<Task> getTasks() { + return mFilteredTasks; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/HighResThumbnailLoader.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/HighResThumbnailLoader.java index 6414ea1e9783..24ba99840165 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/HighResThumbnailLoader.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/HighResThumbnailLoader.java @@ -14,7 +14,7 @@ * limitations under the License */ -package com.android.systemui.recents.model; +package com.android.systemui.shared.recents.model; import static android.os.Process.setThreadPriority; @@ -25,10 +25,8 @@ import android.util.ArraySet; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; -import com.android.systemui.recents.Recents; -import com.android.systemui.recents.RecentsConfiguration; -import com.android.systemui.recents.misc.SystemServicesProxy; -import com.android.systemui.recents.model.Task.TaskCallbacks; +import com.android.systemui.shared.recents.model.Task.TaskCallbacks; +import com.android.systemui.shared.system.ActivityManagerWrapper; import java.util.ArrayDeque; import java.util.ArrayList; @@ -38,6 +36,8 @@ import java.util.ArrayList; */ public class HighResThumbnailLoader implements TaskCallbacks { + private final ActivityManagerWrapper mActivityManager; + @GuardedBy("mLoadQueue") private final ArrayDeque<Task> mLoadQueue = new ArrayDeque<>(); @GuardedBy("mLoadQueue") @@ -46,20 +46,21 @@ public class HighResThumbnailLoader implements TaskCallbacks { private boolean mLoaderIdling; private final ArrayList<Task> mVisibleTasks = new ArrayList<>(); + private final Thread mLoadThread; private final Handler mMainThreadHandler; - private final SystemServicesProxy mSystemServicesProxy; private final boolean mIsLowRamDevice; private boolean mLoading; private boolean mVisible; private boolean mFlingingFast; private boolean mTaskLoadQueueIdle; - public HighResThumbnailLoader(SystemServicesProxy ssp, Looper looper, boolean isLowRamDevice) { + public HighResThumbnailLoader(ActivityManagerWrapper activityManager, Looper looper, + boolean isLowRamDevice) { + mActivityManager = activityManager; mMainThreadHandler = new Handler(looper); mLoadThread = new Thread(mLoader, "Recents-HighResThumbnailLoader"); mLoadThread.start(); - mSystemServicesProxy = ssp; mIsLowRamDevice = isLowRamDevice; } @@ -220,7 +221,7 @@ public class HighResThumbnailLoader implements TaskCallbacks { } private void loadTask(Task t) { - ThumbnailData thumbnail = mSystemServicesProxy.getTaskThumbnail(t.key.id, + ThumbnailData thumbnail = mActivityManager.getTaskThumbnail(t.key.id, false /* reducedResolution */); mMainThreadHandler.post(() -> { synchronized (mLoadQueue) { diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoadPlan.java index 62ba30bfd5dd..c9368f3ea34c 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoadPlan.java @@ -14,33 +14,21 @@ * limitations under the License. */ -package com.android.systemui.recents.model; +package com.android.systemui.shared.recents.model; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import android.app.ActivityManager; +import android.app.KeyguardManager; import android.content.Context; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; -import android.content.pm.UserInfo; import android.content.res.Resources; import android.graphics.drawable.Drawable; -import android.os.UserHandle; -import android.os.UserManager; -import android.provider.Settings; -import android.provider.Settings.Secure; -import android.util.ArraySet; -import android.util.SparseArray; import android.util.SparseBooleanArray; -import android.util.SparseIntArray; -import com.android.systemui.Prefs; -import com.android.systemui.R; -import com.android.systemui.recents.Recents; -import com.android.systemui.recents.RecentsDebugFlags; -import com.android.systemui.recents.misc.SystemServicesProxy; -import com.android.systemui.recents.views.lowram.TaskStackLowRamLayoutAlgorithm; -import com.android.systemui.recents.views.grid.TaskGridLayoutAlgorithm; +import com.android.systemui.shared.recents.model.Task.TaskKey; +import com.android.systemui.shared.system.ActivityManagerWrapper; import java.util.ArrayList; import java.util.Collections; @@ -68,14 +56,17 @@ public class RecentsTaskLoadPlan { public int numVisibleTaskThumbnails = 0; } - Context mContext; + private final Context mContext; + private final KeyguardManager mKeyguardManager; - List<ActivityManager.RecentTaskInfo> mRawTasks; - TaskStack mStack; + private List<ActivityManager.RecentTaskInfo> mRawTasks; + private TaskStack mStack; - /** Package level ctor */ - RecentsTaskLoadPlan(Context context) { + private final SparseBooleanArray mTmpLockedUsers = new SparseBooleanArray(); + + public RecentsTaskLoadPlan(Context context) { mContext = context; + mKeyguardManager = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE); } /** @@ -85,9 +76,9 @@ public class RecentsTaskLoadPlan { * Note: Do not lock, callers should synchronize on the loader before making this call. */ void preloadRawTasks() { - SystemServicesProxy ssp = Recents.getSystemServices(); - int currentUserId = ssp.getCurrentUser(); - mRawTasks = ssp.getRecentTasks(ActivityManager.getMaxRecentTasksStatic(), currentUserId); + int currentUserId = ActivityManagerWrapper.getInstance().getCurrentUserId(); + mRawTasks = ActivityManagerWrapper.getInstance().getRecentTasks( + ActivityManager.getMaxRecentTasksStatic(), currentUserId); // Since the raw tasks are given in most-recent to least-recent order, we need to reverse it Collections.reverse(mRawTasks); @@ -111,18 +102,13 @@ public class RecentsTaskLoadPlan { preloadRawTasks(); } - SparseBooleanArray lockedUsers = new SparseBooleanArray(); - String dismissDescFormat = mContext.getString( - R.string.accessibility_recents_item_will_be_dismissed); - String appInfoDescFormat = mContext.getString( - R.string.accessibility_recents_item_open_app_info); int taskCount = mRawTasks.size(); for (int i = 0; i < taskCount; i++) { ActivityManager.RecentTaskInfo t = mRawTasks.get(i); // Compose the task key final int windowingMode = t.configuration.windowConfiguration.getWindowingMode(); - Task.TaskKey taskKey = new Task.TaskKey(t.persistentId, windowingMode, t.baseIntent, + TaskKey taskKey = new TaskKey(t.persistentId, windowingMode, t.baseIntent, t.userId, t.lastActiveTime); boolean isFreeformTask = windowingMode == WINDOWING_MODE_FREEFORM; @@ -133,9 +119,7 @@ public class RecentsTaskLoadPlan { ActivityInfo info = loader.getAndUpdateActivityInfo(taskKey); String title = loader.getAndUpdateActivityTitle(taskKey, t.taskDescription); String titleDescription = loader.getAndUpdateContentDescription(taskKey, - t.taskDescription, res); - String dismissDescription = String.format(dismissDescFormat, titleDescription); - String appInfoDescription = String.format(appInfoDescFormat, titleDescription); + t.taskDescription); Drawable icon = isStackTask ? loader.getAndUpdateActivityIcon(taskKey, t.taskDescription, res, false) : null; @@ -145,17 +129,18 @@ public class RecentsTaskLoadPlan { int backgroundColor = loader.getActivityBackgroundColor(t.taskDescription); boolean isSystemApp = (info != null) && ((info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0); - if (lockedUsers.indexOfKey(t.userId) < 0) { - lockedUsers.put(t.userId, Recents.getSystemServices().isDeviceLocked(t.userId)); + + // TODO: Refactor to not do this every preload + if (mTmpLockedUsers.indexOfKey(t.userId) < 0) { + mTmpLockedUsers.put(t.userId, mKeyguardManager.isDeviceLocked(t.userId)); } - boolean isLocked = lockedUsers.get(t.userId); + boolean isLocked = mTmpLockedUsers.get(t.userId); // Add the task to the stack Task task = new Task(taskKey, icon, - thumbnail, title, titleDescription, dismissDescription, appInfoDescription, - activityColor, backgroundColor, isLaunchTarget, isStackTask, isSystemApp, - t.supportsSplitScreenMultiWindow, t.taskDescription, t.resizeMode, - t.topActivity, isLocked); + thumbnail, title, titleDescription, activityColor, backgroundColor, + isLaunchTarget, isStackTask, isSystemApp, t.supportsSplitScreenMultiWindow, + t.taskDescription, t.resizeMode, t.topActivity, isLocked); allTasks.add(task); } @@ -179,7 +164,7 @@ public class RecentsTaskLoadPlan { int taskCount = tasks.size(); for (int i = 0; i < taskCount; i++) { Task task = tasks.get(i); - Task.TaskKey taskKey = task.key; + TaskKey taskKey = task.key; boolean isRunningTask = (task.key.id == opts.runningTaskId); boolean isVisibleTask = i >= (taskCount - opts.numVisibleTasks); @@ -210,13 +195,6 @@ public class RecentsTaskLoadPlan { return mStack; } - /** - * Returns the raw list of recent tasks. - */ - public List<ActivityManager.RecentTaskInfo> getRawTasks() { - return mRawTasks; - } - /** Returns whether there are any tasks in any stacks. */ public boolean hasTasks() { if (mStack != null) { diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoader.java index 3494a00b2e95..de4c72c2ee6a 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoader.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.recents.model; +package com.android.systemui.shared.recents.model; import android.app.ActivityManager; import android.content.ComponentCallbacks2; @@ -25,234 +25,43 @@ import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; -import android.os.Handler; -import android.os.HandlerThread; import android.os.Looper; import android.os.Trace; import android.util.Log; import android.util.LruCache; import com.android.internal.annotations.GuardedBy; -import com.android.systemui.R; -import com.android.systemui.recents.Recents; -import com.android.systemui.recents.RecentsConfiguration; -import com.android.systemui.recents.RecentsDebugFlags; -import com.android.systemui.recents.events.activity.PackagesChangedEvent; -import com.android.systemui.recents.misc.SystemServicesProxy; +import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan.Options; +import com.android.systemui.shared.recents.model.Task.TaskKey; +import com.android.systemui.shared.recents.model.TaskKeyLruCache.EvictionCallback; +import com.android.systemui.shared.system.ActivityManagerWrapper; +import com.android.systemui.shared.system.PackageManagerWrapper; import java.io.PrintWriter; import java.util.Map; -import java.util.concurrent.ConcurrentLinkedQueue; /** - * A Task load queue - */ -class TaskResourceLoadQueue { - - ConcurrentLinkedQueue<Task> mQueue = new ConcurrentLinkedQueue<Task>(); - - /** Adds a new task to the load queue */ - void addTask(Task t) { - if (!mQueue.contains(t)) { - mQueue.add(t); - } - synchronized(this) { - notifyAll(); - } - } - - /** - * Retrieves the next task from the load queue, as well as whether we want that task to be - * force reloaded. - */ - Task nextTask() { - return mQueue.poll(); - } - - /** Removes a task from the load queue */ - void removeTask(Task t) { - mQueue.remove(t); - } - - /** Clears all the tasks from the load queue */ - void clearTasks() { - mQueue.clear(); - } - - /** Returns whether the load queue is empty */ - boolean isEmpty() { - return mQueue.isEmpty(); - } -} - -/** - * Task resource loader - */ -class BackgroundTaskLoader implements Runnable { - static String TAG = "TaskResourceLoader"; - static boolean DEBUG = false; - - Context mContext; - HandlerThread mLoadThread; - Handler mLoadThreadHandler; - Handler mMainThreadHandler; - - TaskResourceLoadQueue mLoadQueue; - TaskKeyLruCache<Drawable> mIconCache; - BitmapDrawable mDefaultIcon; - - boolean mStarted; - boolean mCancelled; - boolean mWaitingOnLoadQueue; - - private final OnIdleChangedListener mOnIdleChangedListener; - - /** Constructor, creates a new loading thread that loads task resources in the background */ - public BackgroundTaskLoader(TaskResourceLoadQueue loadQueue, - TaskKeyLruCache<Drawable> iconCache, BitmapDrawable defaultIcon, - OnIdleChangedListener onIdleChangedListener) { - mLoadQueue = loadQueue; - mIconCache = iconCache; - mDefaultIcon = defaultIcon; - mMainThreadHandler = new Handler(); - mOnIdleChangedListener = onIdleChangedListener; - mLoadThread = new HandlerThread("Recents-TaskResourceLoader", - android.os.Process.THREAD_PRIORITY_BACKGROUND); - mLoadThread.start(); - mLoadThreadHandler = new Handler(mLoadThread.getLooper()); - } - - /** Restarts the loader thread */ - void start(Context context) { - mContext = context; - mCancelled = false; - if (!mStarted) { - // Start loading on the load thread - mStarted = true; - mLoadThreadHandler.post(this); - } else { - // Notify the load thread to start loading again - synchronized (mLoadThread) { - mLoadThread.notifyAll(); - } - } - } - - /** Requests the loader thread to stop after the current iteration */ - void stop() { - // Mark as cancelled for the thread to pick up - mCancelled = true; - // If we are waiting for the load queue for more tasks, then we can just reset the - // Context now, since nothing is using it - if (mWaitingOnLoadQueue) { - mContext = null; - } - } - - @Override - public void run() { - while (true) { - if (mCancelled) { - // We have to unset the context here, since the background thread may be using it - // when we call stop() - mContext = null; - // If we are cancelled, then wait until we are started again - synchronized(mLoadThread) { - try { - mLoadThread.wait(); - } catch (InterruptedException ie) { - ie.printStackTrace(); - } - } - } else { - SystemServicesProxy ssp = Recents.getSystemServices(); - // If we've stopped the loader, then fall through to the above logic to wait on - // the load thread - if (ssp != null) { - processLoadQueueItem(ssp); - } - - // If there are no other items in the list, then just wait until something is added - if (!mCancelled && mLoadQueue.isEmpty()) { - synchronized(mLoadQueue) { - try { - mWaitingOnLoadQueue = true; - mMainThreadHandler.post( - () -> mOnIdleChangedListener.onIdleChanged(true)); - mLoadQueue.wait(); - mMainThreadHandler.post( - () -> mOnIdleChangedListener.onIdleChanged(false)); - mWaitingOnLoadQueue = false; - } catch (InterruptedException ie) { - ie.printStackTrace(); - } - } - } - } - } - } - - /** - * This needs to be in a separate method to work around an surprising interpreter behavior: - * The register will keep the local reference to cachedThumbnailData even if it falls out of - * scope. Putting it into a method fixes this issue. - */ - private void processLoadQueueItem(SystemServicesProxy ssp) { - // Load the next item from the queue - final Task t = mLoadQueue.nextTask(); - if (t != null) { - Drawable cachedIcon = mIconCache.get(t.key); - - // Load the icon if it is stale or we haven't cached one yet - if (cachedIcon == null) { - cachedIcon = ssp.getBadgedTaskDescriptionIcon(t.taskDescription, - t.key.userId, mContext.getResources()); - - if (cachedIcon == null) { - ActivityInfo info = ssp.getActivityInfo( - t.key.getComponent(), t.key.userId); - if (info != null) { - if (DEBUG) Log.d(TAG, "Loading icon: " + t.key); - cachedIcon = ssp.getBadgedActivityIcon(info, t.key.userId); - } - } - - if (cachedIcon == null) { - cachedIcon = mDefaultIcon; - } - - // At this point, even if we can't load the icon, we will set the - // default icon. - mIconCache.put(t.key, cachedIcon); - } - - if (DEBUG) Log.d(TAG, "Loading thumbnail: " + t.key); - final ThumbnailData thumbnailData = ssp.getTaskThumbnail(t.key.id, - true /* reducedResolution */); - - if (!mCancelled) { - // Notify that the task data has changed - final Drawable finalIcon = cachedIcon; - mMainThreadHandler.post( - () -> t.notifyTaskDataLoaded(thumbnailData, finalIcon)); - } - } - } - - interface OnIdleChangedListener { - void onIdleChanged(boolean idle); - } -} - -/** * Recents task loader */ public class RecentsTaskLoader { - private static final String TAG = "RecentsTaskLoader"; private static final boolean DEBUG = false; + /** Levels of svelte in increasing severity/austerity. */ + // No svelting. + public static final int SVELTE_NONE = 0; + // Limit thumbnail cache to number of visible thumbnails when Recents was loaded, disable + // caching thumbnails as you scroll. + public static final int SVELTE_LIMIT_CACHE = 1; + // Disable the thumbnail cache, load thumbnails asynchronously when the activity loads and + // evict all thumbnails when hidden. + public static final int SVELTE_DISABLE_CACHE = 2; + // Disable all thumbnail loading. + public static final int SVELTE_DISABLE_LOADING = 3; + + private final Context mContext; + // This activity info LruCache is useful because it can be expensive to retrieve ActivityInfos // for many tasks, which we use to get the activity labels and icons. Unlike the other caches // below, this is per-package so we can't invalidate the items in the cache based on the last @@ -272,29 +81,27 @@ public class RecentsTaskLoader { private final int mMaxThumbnailCacheSize; private final int mMaxIconCacheSize; private int mNumVisibleTasksLoaded; + private int mSvelteLevel; - int mDefaultTaskBarBackgroundColor; - int mDefaultTaskViewBackgroundColor; - BitmapDrawable mDefaultIcon; + private int mDefaultTaskBarBackgroundColor; + private int mDefaultTaskViewBackgroundColor; + private final BitmapDrawable mDefaultIcon; - private TaskKeyLruCache.EvictionCallback mClearActivityInfoOnEviction = - new TaskKeyLruCache.EvictionCallback() { + private EvictionCallback mClearActivityInfoOnEviction = new EvictionCallback() { @Override - public void onEntryEvicted(Task.TaskKey key) { + public void onEntryEvicted(TaskKey key) { if (key != null) { mActivityInfoCache.remove(key.getComponent()); } } }; - public RecentsTaskLoader(Context context) { - Resources res = context.getResources(); - mDefaultTaskBarBackgroundColor = - context.getColor(R.color.recents_task_bar_default_background_color); - mDefaultTaskViewBackgroundColor = - context.getColor(R.color.recents_task_view_default_background_color); - mMaxThumbnailCacheSize = res.getInteger(R.integer.config_recents_max_thumbnail_count); - mMaxIconCacheSize = res.getInteger(R.integer.config_recents_max_icon_count); + public RecentsTaskLoader(Context context, int maxThumbnailCacheSize, int maxIconCacheSize, + int svelteLevel) { + mContext = context; + mMaxThumbnailCacheSize = maxThumbnailCacheSize; + mMaxIconCacheSize = maxIconCacheSize; + mSvelteLevel = svelteLevel; // Create the default assets Bitmap icon = Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8); @@ -303,18 +110,27 @@ public class RecentsTaskLoader { // Initialize the proxy, cache and loaders int numRecentTasks = ActivityManager.getMaxRecentTasksStatic(); - mHighResThumbnailLoader = new HighResThumbnailLoader(Recents.getSystemServices(), - Looper.getMainLooper(), Recents.getConfiguration().isLowRamDevice); + mHighResThumbnailLoader = new HighResThumbnailLoader(ActivityManagerWrapper.getInstance(), + Looper.getMainLooper(), ActivityManager.isLowRamDeviceStatic()); mLoadQueue = new TaskResourceLoadQueue(); mIconCache = new TaskKeyLruCache<>(mMaxIconCacheSize, mClearActivityInfoOnEviction); mActivityLabelCache = new TaskKeyLruCache<>(numRecentTasks, mClearActivityInfoOnEviction); mContentDescriptionCache = new TaskKeyLruCache<>(numRecentTasks, mClearActivityInfoOnEviction); - mActivityInfoCache = new LruCache(numRecentTasks); + mActivityInfoCache = new LruCache<>(numRecentTasks); mLoader = new BackgroundTaskLoader(mLoadQueue, mIconCache, mDefaultIcon, mHighResThumbnailLoader::setTaskLoadQueueIdle); } + /** + * Sets the default task bar/view colors if none are provided by the app. + */ + public void setDefaultColors(int defaultTaskBarBackgroundColor, + int defaultTaskViewBackgroundColor) { + mDefaultTaskBarBackgroundColor = defaultTaskBarBackgroundColor; + mDefaultTaskViewBackgroundColor = defaultTaskViewBackgroundColor; + } + /** Returns the size of the app icon cache. */ public int getIconCacheSize() { return mMaxIconCacheSize; @@ -329,12 +145,6 @@ public class RecentsTaskLoader { return mHighResThumbnailLoader; } - /** Creates a new plan for loading the recent tasks. */ - public RecentsTaskLoadPlan createLoadPlan(Context context) { - RecentsTaskLoadPlan plan = new RecentsTaskLoadPlan(context); - return plan; - } - /** Preloads recents tasks using the specified plan to store the output. */ public synchronized void preloadTasks(RecentsTaskLoadPlan plan, int runningTaskId) { try { @@ -346,13 +156,11 @@ public class RecentsTaskLoader { } /** Begins loading the heavy task data according to the specified options. */ - public synchronized void loadTasks(Context context, RecentsTaskLoadPlan plan, - RecentsTaskLoadPlan.Options opts) { + public synchronized void loadTasks(RecentsTaskLoadPlan plan, Options opts) { if (opts == null) { throw new RuntimeException("Requires load options"); } if (opts.onlyLoadForCache && opts.loadThumbnails) { - // If we are loading for the cache, we'd like to have the real cache only include the // visible thumbnails. However, we also don't want to reload already cached thumbnails. // Thus, we copy over the current entries into a second cache, and clear the real cache, @@ -453,9 +261,7 @@ public class RecentsTaskLoader { /** * Returns the cached task label if the task key is not expired, updating the cache if it is. */ - String getAndUpdateActivityTitle(Task.TaskKey taskKey, ActivityManager.TaskDescription td) { - SystemServicesProxy ssp = Recents.getSystemServices(); - + String getAndUpdateActivityTitle(TaskKey taskKey, ActivityManager.TaskDescription td) { // Return the task description label if it exists if (td != null && td.getLabel() != null) { return td.getLabel(); @@ -468,7 +274,8 @@ public class RecentsTaskLoader { // All short paths failed, load the label from the activity info and cache it ActivityInfo activityInfo = getAndUpdateActivityInfo(taskKey); if (activityInfo != null) { - label = ssp.getBadgedActivityLabel(activityInfo, taskKey.userId); + label = ActivityManagerWrapper.getInstance().getBadgedActivityLabel(activityInfo, + taskKey.userId); mActivityLabelCache.put(taskKey, label); return label; } @@ -481,10 +288,7 @@ public class RecentsTaskLoader { * Returns the cached task content description if the task key is not expired, updating the * cache if it is. */ - String getAndUpdateContentDescription(Task.TaskKey taskKey, ActivityManager.TaskDescription td, - Resources res) { - SystemServicesProxy ssp = Recents.getSystemServices(); - + String getAndUpdateContentDescription(TaskKey taskKey, ActivityManager.TaskDescription td) { // Return the cached content description if it exists String label = mContentDescriptionCache.getAndInvalidateIfModified(taskKey); if (label != null) { @@ -494,7 +298,8 @@ public class RecentsTaskLoader { // All short paths failed, load the label from the activity info and cache it ActivityInfo activityInfo = getAndUpdateActivityInfo(taskKey); if (activityInfo != null) { - label = ssp.getBadgedContentDescription(activityInfo, taskKey.userId, td, res); + label = ActivityManagerWrapper.getInstance().getBadgedContentDescription( + activityInfo, taskKey.userId, td); if (td == null) { // Only add to the cache if the task description is null, otherwise, it is possible // for the task description to change between calls without the last active time @@ -513,10 +318,8 @@ public class RecentsTaskLoader { /** * Returns the cached task icon if the task key is not expired, updating the cache if it is. */ - Drawable getAndUpdateActivityIcon(Task.TaskKey taskKey, ActivityManager.TaskDescription td, + Drawable getAndUpdateActivityIcon(TaskKey taskKey, ActivityManager.TaskDescription td, Resources res, boolean loadIfNotCached) { - SystemServicesProxy ssp = Recents.getSystemServices(); - // Return the cached activity icon if it exists Drawable icon = mIconCache.getAndInvalidateIfModified(taskKey); if (icon != null) { @@ -525,7 +328,8 @@ public class RecentsTaskLoader { if (loadIfNotCached) { // Return and cache the task description icon if it exists - icon = ssp.getBadgedTaskDescriptionIcon(td, taskKey.userId, res); + icon = ActivityManagerWrapper.getInstance().getBadgedTaskDescriptionIcon(mContext, td, + taskKey.userId, res); if (icon != null) { mIconCache.put(taskKey, icon); return icon; @@ -534,7 +338,8 @@ public class RecentsTaskLoader { // Load the icon from the activity info and cache it ActivityInfo activityInfo = getAndUpdateActivityInfo(taskKey); if (activityInfo != null) { - icon = ssp.getBadgedActivityIcon(activityInfo, taskKey.userId); + icon = ActivityManagerWrapper.getInstance().getBadgedActivityIcon(activityInfo, + taskKey.userId); if (icon != null) { mIconCache.put(taskKey, icon); return icon; @@ -548,10 +353,8 @@ public class RecentsTaskLoader { /** * Returns the cached thumbnail if the task key is not expired, updating the cache if it is. */ - synchronized ThumbnailData getAndUpdateThumbnail(Task.TaskKey taskKey, boolean loadIfNotCached, + synchronized ThumbnailData getAndUpdateThumbnail(TaskKey taskKey, boolean loadIfNotCached, boolean storeInCache) { - SystemServicesProxy ssp = Recents.getSystemServices(); - ThumbnailData cached = mThumbnailCache.getAndInvalidateIfModified(taskKey); if (cached != null) { return cached; @@ -564,11 +367,10 @@ public class RecentsTaskLoader { } if (loadIfNotCached) { - RecentsConfiguration config = Recents.getConfiguration(); - if (config.svelteLevel < RecentsConfiguration.SVELTE_DISABLE_LOADING) { + if (mSvelteLevel < SVELTE_DISABLE_LOADING) { // Load the thumbnail from the system - ThumbnailData thumbnailData = ssp.getTaskThumbnail(taskKey.id, - true /* reducedResolution */); + ThumbnailData thumbnailData = ActivityManagerWrapper.getInstance().getTaskThumbnail( + taskKey.id, true /* reducedResolution */); if (thumbnailData.thumbnail != null) { if (storeInCache) { mThumbnailCache.put(taskKey, thumbnailData); @@ -607,12 +409,11 @@ public class RecentsTaskLoader { * Returns the activity info for the given task key, retrieving one from the system if the * task key is expired. */ - ActivityInfo getAndUpdateActivityInfo(Task.TaskKey taskKey) { - SystemServicesProxy ssp = Recents.getSystemServices(); + ActivityInfo getAndUpdateActivityInfo(TaskKey taskKey) { ComponentName cn = taskKey.getComponent(); ActivityInfo activityInfo = mActivityInfoCache.get(cn); if (activityInfo == null) { - activityInfo = ssp.getActivityInfo(cn, taskKey.userId); + activityInfo = PackageManagerWrapper.getInstance().getActivityInfo(cn, taskKey.userId); if (cn == null || activityInfo == null) { Log.e(TAG, "Unexpected null component name or activity info: " + cn + ", " + activityInfo); diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java index ae417c0c403f..6bddbe01b11b 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java @@ -14,23 +14,17 @@ * limitations under the License. */ -package com.android.systemui.recents.model; +package com.android.systemui.shared.recents.model; -import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; - -import android.app.ActivityManager; import android.app.ActivityManager.TaskDescription; import android.content.ComponentName; import android.content.Intent; import android.content.pm.ActivityInfo; import android.graphics.Color; -import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.view.ViewDebug; -import com.android.systemui.recents.Recents; -import com.android.systemui.recents.misc.SystemServicesProxy; -import com.android.systemui.recents.misc.Utilities; +import com.android.systemui.shared.recents.utilities.Utilities; import java.io.PrintWriter; import java.util.ArrayList; @@ -46,11 +40,11 @@ public class Task { /* Task callbacks */ public interface TaskCallbacks { /* Notifies when a task has been bound */ - public void onTaskDataLoaded(Task task, ThumbnailData thumbnailData); + void onTaskDataLoaded(Task task, ThumbnailData thumbnailData); /* Notifies when a task has been unbound */ - public void onTaskDataUnloaded(); + void onTaskDataUnloaded(); /* Notifies when a task's windowing mode has changed. */ - public void onTaskWindowingModeChanged(); + void onTaskWindowingModeChanged(); } /* The Task Key represents the unique primary key for the task */ @@ -64,8 +58,6 @@ public class Task { @ViewDebug.ExportedProperty(category="recents") public final int userId; @ViewDebug.ExportedProperty(category="recents") - public long firstActiveTime; - @ViewDebug.ExportedProperty(category="recents") public long lastActiveTime; private int mHashCode; @@ -134,10 +126,6 @@ public class Task { @ViewDebug.ExportedProperty(category="recents") public String titleDescription; @ViewDebug.ExportedProperty(category="recents") - public String dismissDescription; - @ViewDebug.ExportedProperty(category="recents") - public String appInfoDescription; - @ViewDebug.ExportedProperty(category="recents") public int colorPrimary; @ViewDebug.ExportedProperty(category="recents") public int colorBackground; @@ -180,17 +168,15 @@ public class Task { } public Task(TaskKey key, Drawable icon, ThumbnailData thumbnail, String title, - String titleDescription, String dismissDescription, String appInfoDescription, - int colorPrimary, int colorBackground, boolean isLaunchTarget, boolean isStackTask, - boolean isSystemApp, boolean isDockable, TaskDescription taskDescription, - int resizeMode, ComponentName topActivity, boolean isLocked) { + String titleDescription, int colorPrimary, int colorBackground, boolean isLaunchTarget, + boolean isStackTask, boolean isSystemApp, boolean isDockable, + TaskDescription taskDescription, int resizeMode, ComponentName topActivity, + boolean isLocked) { this.key = key; this.icon = icon; this.thumbnail = thumbnail; this.title = title; this.titleDescription = titleDescription; - this.dismissDescription = dismissDescription; - this.appInfoDescription = appInfoDescription; this.colorPrimary = colorPrimary; this.colorBackground = colorBackground; this.useLightOnPrimaryColor = Utilities.computeContrastBetweenColors(this.colorPrimary, @@ -214,8 +200,6 @@ public class Task { this.thumbnail = o.thumbnail; this.title = o.title; this.titleDescription = o.titleDescription; - this.dismissDescription = o.dismissDescription; - this.appInfoDescription = o.appInfoDescription; this.colorPrimary = o.colorPrimary; this.colorBackground = o.colorBackground; this.useLightOnPrimaryColor = o.useLightOnPrimaryColor; diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskFilter.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskFilter.java new file mode 100644 index 000000000000..9a1ff544800d --- /dev/null +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskFilter.java @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2017 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.shared.recents.model; + +import android.util.SparseArray; + +/** + * An interface for a task filter to query whether a particular task should show in a stack. + */ +interface TaskFilter { + /** Returns whether the filter accepts the specified task */ + boolean acceptTask(SparseArray<Task> taskIdMap, Task t, int index); +} diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyCache.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyCache.java index 247a654207c8..4bf3500a3405 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyCache.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyCache.java @@ -14,12 +14,12 @@ * limitations under the License */ -package com.android.systemui.recents.model; +package com.android.systemui.shared.recents.model; import android.util.Log; import android.util.SparseArray; -import com.android.systemui.recents.model.Task.TaskKey; +import com.android.systemui.shared.recents.model.Task.TaskKey; /** * Base class for both strong and LRU task key cache. @@ -34,7 +34,7 @@ public abstract class TaskKeyCache<V> { * Gets a specific entry in the cache with the specified key, regardless of whether the cached * value is valid or not. */ - final V get(Task.TaskKey key) { + final V get(TaskKey key) { return getCacheEntry(key.id); } @@ -42,8 +42,8 @@ public abstract class TaskKeyCache<V> { * Returns the value only if the key is valid (has not been updated since the last time it was * in the cache) */ - final V getAndInvalidateIfModified(Task.TaskKey key) { - Task.TaskKey lastKey = mKeys.get(key.id); + final V getAndInvalidateIfModified(TaskKey key) { + TaskKey lastKey = mKeys.get(key.id); if (lastKey != null) { if ((lastKey.windowingMode != key.windowingMode) || (lastKey.lastActiveTime != key.lastActiveTime)) { @@ -59,7 +59,7 @@ public abstract class TaskKeyCache<V> { } /** Puts an entry in the cache for a specific key. */ - final void put(Task.TaskKey key, V value) { + final void put(TaskKey key, V value) { if (key == null || value == null) { Log.e(TAG, "Unexpected null key or value: " + key + ", " + value); return; @@ -70,7 +70,7 @@ public abstract class TaskKeyCache<V> { /** Removes a cache entry for a specific key. */ - final void remove(Task.TaskKey key) { + final void remove(TaskKey key) { // Remove the key after the cache value because we need it to make the callback removeCacheEntry(key.id); mKeys.remove(key.id); diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyLruCache.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyLruCache.java index 778df6be399b..0ba2c3bf6e3c 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyLruCache.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyLruCache.java @@ -14,14 +14,16 @@ * limitations under the License. */ -package com.android.systemui.recents.model; +package com.android.systemui.shared.recents.model; import android.util.LruCache; +import com.android.systemui.shared.recents.model.Task.TaskKey; + import java.io.PrintWriter; /** - * A mapping of {@link Task.TaskKey} to value, with additional LRU functionality where the least + * A mapping of {@link TaskKey} to value, with additional LRU functionality where the least * recently referenced key/values will be evicted as more values than the given cache size are * inserted. * @@ -31,7 +33,7 @@ import java.io.PrintWriter; public class TaskKeyLruCache<V> extends TaskKeyCache<V> { public interface EvictionCallback { - public void onEntryEvicted(Task.TaskKey key); + void onEntryEvicted(TaskKey key); } private final LruCache<Integer, V> mCache; diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyStrongCache.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyStrongCache.java index c84df8a14288..4408eced3e93 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyStrongCache.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyStrongCache.java @@ -14,13 +14,11 @@ * limitations under the License */ -package com.android.systemui.recents.model; +package com.android.systemui.shared.recents.model; import android.util.ArrayMap; -import android.util.Log; -import android.util.SparseArray; -import com.android.systemui.recents.model.Task.TaskKey; +import com.android.systemui.shared.recents.model.Task.TaskKey; import java.io.PrintWriter; diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskResourceLoadQueue.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskResourceLoadQueue.java new file mode 100644 index 000000000000..fbb6acebc8e0 --- /dev/null +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskResourceLoadQueue.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2017 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.shared.recents.model; + +import java.util.concurrent.ConcurrentLinkedQueue; + +/** + * A Task load queue + */ +class TaskResourceLoadQueue { + + private final ConcurrentLinkedQueue<Task> mQueue = new ConcurrentLinkedQueue<>(); + + /** Adds a new task to the load queue */ + void addTask(Task t) { + if (!mQueue.contains(t)) { + mQueue.add(t); + } + synchronized(this) { + notifyAll(); + } + } + + /** + * Retrieves the next task from the load queue, as well as whether we want that task to be + * force reloaded. + */ + Task nextTask() { + return mQueue.poll(); + } + + /** Removes a task from the load queue */ + void removeTask(Task t) { + mQueue.remove(t); + } + + /** Clears all the tasks from the load queue */ + void clearTasks() { + mQueue.clear(); + } + + /** Returns whether the load queue is empty */ + boolean isEmpty() { + return mQueue.isEmpty(); + } +} diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskStack.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskStack.java new file mode 100644 index 000000000000..693379d3ee13 --- /dev/null +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskStack.java @@ -0,0 +1,403 @@ +/* + * 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.shared.recents.model; + +import android.content.ComponentName; +import android.util.ArrayMap; +import android.util.ArraySet; +import android.util.SparseArray; + +import com.android.systemui.shared.recents.model.Task.TaskKey; +import com.android.systemui.shared.recents.utilities.AnimationProps; +import com.android.systemui.shared.system.PackageManagerWrapper; + +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; + + +/** + * The task stack contains a list of multiple tasks. + */ +public class TaskStack { + + private static final String TAG = "TaskStack"; + + /** Task stack callbacks */ + public interface TaskStackCallbacks { + /** + * Notifies when a new task has been added to the stack. + */ + void onStackTaskAdded(TaskStack stack, Task newTask); + + /** + * Notifies when a task has been removed from the stack. + */ + void onStackTaskRemoved(TaskStack stack, Task removedTask, Task newFrontMostTask, + AnimationProps animation, boolean fromDockGesture, + boolean dismissRecentsIfAllRemoved); + + /** + * Notifies when all tasks have been removed from the stack. + */ + void onStackTasksRemoved(TaskStack stack); + + /** + * Notifies when tasks in the stack have been updated. + */ + void onStackTasksUpdated(TaskStack stack); + } + + private final ArrayList<Task> mRawTaskList = new ArrayList<>(); + private final FilteredTaskList mStackTaskList = new FilteredTaskList(); + private TaskStackCallbacks mCb; + + public TaskStack() { + // Ensure that we only show stack tasks + mStackTaskList.setFilter((taskIdMap, t, index) -> t.isStackTask); + } + + /** Sets the callbacks for this task stack. */ + public void setCallbacks(TaskStackCallbacks cb) { + mCb = cb; + } + + /** + * Removes a task from the stack, with an additional {@param animation} hint to the callbacks on + * how they should update themselves. + */ + public void removeTask(Task t, AnimationProps animation, boolean fromDockGesture) { + removeTask(t, animation, fromDockGesture, true /* dismissRecentsIfAllRemoved */); + } + + /** + * Removes a task from the stack, with an additional {@param animation} hint to the callbacks on + * how they should update themselves. + */ + public void removeTask(Task t, AnimationProps animation, boolean fromDockGesture, + boolean dismissRecentsIfAllRemoved) { + if (mStackTaskList.contains(t)) { + mStackTaskList.remove(t); + Task newFrontMostTask = getStackFrontMostTask(); + if (mCb != null) { + // Notify that a task has been removed + mCb.onStackTaskRemoved(this, t, newFrontMostTask, animation, + fromDockGesture, dismissRecentsIfAllRemoved); + } + } + mRawTaskList.remove(t); + } + + /** + * Removes all tasks from the stack. + */ + public void removeAllTasks(boolean notifyStackChanges) { + ArrayList<Task> tasks = mStackTaskList.getTasks(); + for (int i = tasks.size() - 1; i >= 0; i--) { + Task t = tasks.get(i); + mStackTaskList.remove(t); + mRawTaskList.remove(t); + } + if (mCb != null && notifyStackChanges) { + // Notify that all tasks have been removed + mCb.onStackTasksRemoved(this); + } + } + + + /** + * @see #setTasks(List, boolean) + */ + public void setTasks(TaskStack stack, boolean notifyStackChanges) { + setTasks(stack.mRawTaskList, notifyStackChanges); + } + + /** + * Sets a few tasks in one go, without calling any callbacks. + * + * @param tasks the new set of tasks to replace the current set. + * @param notifyStackChanges whether or not to callback on specific changes to the list of tasks. + */ + public void setTasks(List<Task> tasks, boolean notifyStackChanges) { + // Compute a has set for each of the tasks + ArrayMap<TaskKey, Task> currentTasksMap = createTaskKeyMapFromList(mRawTaskList); + ArrayMap<TaskKey, Task> newTasksMap = createTaskKeyMapFromList(tasks); + ArrayList<Task> addedTasks = new ArrayList<>(); + ArrayList<Task> removedTasks = new ArrayList<>(); + ArrayList<Task> allTasks = new ArrayList<>(); + + // Disable notifications if there are no callbacks + if (mCb == null) { + notifyStackChanges = false; + } + + // Remove any tasks that no longer exist + int taskCount = mRawTaskList.size(); + for (int i = taskCount - 1; i >= 0; i--) { + Task task = mRawTaskList.get(i); + if (!newTasksMap.containsKey(task.key)) { + if (notifyStackChanges) { + removedTasks.add(task); + } + } + } + + // Add any new tasks + taskCount = tasks.size(); + for (int i = 0; i < taskCount; i++) { + Task newTask = tasks.get(i); + Task currentTask = currentTasksMap.get(newTask.key); + if (currentTask == null && notifyStackChanges) { + addedTasks.add(newTask); + } else if (currentTask != null) { + // The current task has bound callbacks, so just copy the data from the new task + // state and add it back into the list + currentTask.copyFrom(newTask); + newTask = currentTask; + } + allTasks.add(newTask); + } + + // Sort all the tasks to ensure they are ordered correctly + for (int i = allTasks.size() - 1; i >= 0; i--) { + allTasks.get(i).temporarySortIndexInStack = i; + } + + mStackTaskList.set(allTasks); + mRawTaskList.clear(); + mRawTaskList.addAll(allTasks); + + // Only callback for the removed tasks after the stack has updated + int removedTaskCount = removedTasks.size(); + Task newFrontMostTask = getStackFrontMostTask(); + for (int i = 0; i < removedTaskCount; i++) { + mCb.onStackTaskRemoved(this, removedTasks.get(i), newFrontMostTask, + AnimationProps.IMMEDIATE, false /* fromDockGesture */, + true /* dismissRecentsIfAllRemoved */); + } + + // Only callback for the newly added tasks after this stack has been updated + int addedTaskCount = addedTasks.size(); + for (int i = 0; i < addedTaskCount; i++) { + mCb.onStackTaskAdded(this, addedTasks.get(i)); + } + + // Notify that the task stack has been updated + if (notifyStackChanges) { + mCb.onStackTasksUpdated(this); + } + } + + /** + * Gets the front-most task in the stack. + */ + public Task getStackFrontMostTask() { + ArrayList<Task> stackTasks = mStackTaskList.getTasks(); + if (stackTasks.isEmpty()) { + return null; + } + return stackTasks.get(stackTasks.size() - 1); + } + + /** Gets the task keys */ + public ArrayList<TaskKey> getTaskKeys() { + ArrayList<TaskKey> taskKeys = new ArrayList<>(); + ArrayList<Task> tasks = computeAllTasksList(); + int taskCount = tasks.size(); + for (int i = 0; i < taskCount; i++) { + Task task = tasks.get(i); + taskKeys.add(task.key); + } + return taskKeys; + } + + /** + * Returns the set of "active" (non-historical) tasks in the stack that have been used recently. + */ + public ArrayList<Task> getStackTasks() { + return mStackTaskList.getTasks(); + } + + /** + * Computes a set of all the active and historical tasks. + */ + public ArrayList<Task> computeAllTasksList() { + ArrayList<Task> tasks = new ArrayList<>(); + tasks.addAll(mStackTaskList.getTasks()); + return tasks; + } + + /** + * Returns the number of stacktasks. + */ + public int getTaskCount() { + return mStackTaskList.size(); + } + + /** + * Returns the number of stack tasks. + */ + public int getStackTaskCount() { + return mStackTaskList.size(); + } + + /** + * Returns the task in stack tasks which is the launch target. + */ + public Task getLaunchTarget() { + ArrayList<Task> tasks = mStackTaskList.getTasks(); + int taskCount = tasks.size(); + for (int i = 0; i < taskCount; i++) { + Task task = tasks.get(i); + if (task.isLaunchTarget) { + return task; + } + } + return null; + } + + /** + * Returns whether the next launch target should actually be the PiP task. + */ + public boolean isNextLaunchTargetPip(long lastPipTime) { + Task launchTarget = getLaunchTarget(); + Task nextLaunchTarget = getNextLaunchTargetRaw(); + if (nextLaunchTarget != null && lastPipTime > 0) { + // If the PiP time is more recent than the next launch target, then launch the PiP task + return lastPipTime > nextLaunchTarget.key.lastActiveTime; + } else if (launchTarget != null && lastPipTime > 0 && getTaskCount() == 1) { + // Otherwise, if there is no next launch target, but there is a PiP, then launch + // the PiP task + return true; + } + return false; + } + + /** + * Returns the task in stack tasks which should be launched next if Recents are toggled + * again, or null if there is no task to be launched. Callers should check + * {@link #isNextLaunchTargetPip(long)} before fetching the next raw launch target from the + * stack. + */ + public Task getNextLaunchTarget() { + Task nextLaunchTarget = getNextLaunchTargetRaw(); + if (nextLaunchTarget != null) { + return nextLaunchTarget; + } + return getStackTasks().get(getTaskCount() - 1); + } + + private Task getNextLaunchTargetRaw() { + int taskCount = getTaskCount(); + if (taskCount == 0) { + return null; + } + int launchTaskIndex = indexOfStackTask(getLaunchTarget()); + if (launchTaskIndex != -1 && launchTaskIndex > 0) { + return getStackTasks().get(launchTaskIndex - 1); + } + return null; + } + + /** Returns the index of this task in this current task stack */ + public int indexOfStackTask(Task t) { + return mStackTaskList.indexOf(t); + } + + /** Finds the task with the specified task id. */ + public Task findTaskWithId(int taskId) { + ArrayList<Task> tasks = computeAllTasksList(); + int taskCount = tasks.size(); + for (int i = 0; i < taskCount; i++) { + Task task = tasks.get(i); + if (task.key.id == taskId) { + return task; + } + } + return null; + } + + /** + * Computes the components of tasks in this stack that have been removed as a result of a change + * in the specified package. + */ + public ArraySet<ComponentName> computeComponentsRemoved(String packageName, int userId) { + // Identify all the tasks that should be removed as a result of the package being removed. + // Using a set to ensure that we callback once per unique component. + ArraySet<ComponentName> existingComponents = new ArraySet<>(); + ArraySet<ComponentName> removedComponents = new ArraySet<>(); + ArrayList<TaskKey> taskKeys = getTaskKeys(); + int taskKeyCount = taskKeys.size(); + for (int i = 0; i < taskKeyCount; i++) { + TaskKey t = taskKeys.get(i); + + // Skip if this doesn't apply to the current user + if (t.userId != userId) continue; + + ComponentName cn = t.getComponent(); + if (cn.getPackageName().equals(packageName)) { + if (existingComponents.contains(cn)) { + // If we know that the component still exists in the package, then skip + continue; + } + if (PackageManagerWrapper.getInstance().getActivityInfo(cn, userId) != null) { + existingComponents.add(cn); + } else { + removedComponents.add(cn); + } + } + } + return removedComponents; + } + + @Override + public String toString() { + String str = "Stack Tasks (" + mStackTaskList.size() + "):\n"; + ArrayList<Task> tasks = mStackTaskList.getTasks(); + int taskCount = tasks.size(); + for (int i = 0; i < taskCount; i++) { + str += " " + tasks.get(i).toString() + "\n"; + } + return str; + } + + /** + * Given a list of tasks, returns a map of each task's key to the task. + */ + private ArrayMap<TaskKey, Task> createTaskKeyMapFromList(List<Task> tasks) { + ArrayMap<TaskKey, Task> map = new ArrayMap<>(tasks.size()); + int taskCount = tasks.size(); + for (int i = 0; i < taskCount; i++) { + Task task = tasks.get(i); + map.put(task.key, task); + } + return map; + } + + public void dump(String prefix, PrintWriter writer) { + String innerPrefix = prefix + " "; + + writer.print(prefix); writer.print(TAG); + writer.print(" numStackTasks="); writer.print(mStackTaskList.size()); + writer.println(); + ArrayList<Task> tasks = mStackTaskList.getTasks(); + int taskCount = tasks.size(); + for (int i = 0; i < taskCount; i++) { + tasks.get(i).dump(innerPrefix, writer); + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/ThumbnailData.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java index 33ff1b634d64..dd1763bb118b 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/ThumbnailData.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java @@ -14,7 +14,9 @@ * limitations under the License. */ -package com.android.systemui.recents.model; +package com.android.systemui.shared.recents.model; + +import static android.content.res.Configuration.ORIENTATION_UNDEFINED; import android.app.ActivityManager.TaskSnapshot; import android.graphics.Bitmap; @@ -25,20 +27,25 @@ import android.graphics.Rect; */ public class ThumbnailData { - // TODO: Make these final once the non-snapshot path is removed. - public Bitmap thumbnail; + public final Bitmap thumbnail; public int orientation; - public final Rect insets = new Rect(); + public Rect insets; public boolean reducedResolution; public float scale; - public static ThumbnailData createFromTaskSnapshot(TaskSnapshot snapshot) { - ThumbnailData out = new ThumbnailData(); - out.thumbnail = Bitmap.createHardwareBitmap(snapshot.getSnapshot()); - out.insets.set(snapshot.getContentInsets()); - out.orientation = snapshot.getOrientation(); - out.reducedResolution = snapshot.isReducedResolution(); - out.scale = snapshot.getScale(); - return out; + public ThumbnailData() { + thumbnail = null; + orientation = ORIENTATION_UNDEFINED; + insets = new Rect(); + reducedResolution = false; + scale = 1f; + } + + public ThumbnailData(TaskSnapshot snapshot) { + thumbnail = Bitmap.createHardwareBitmap(snapshot.getSnapshot()); + insets = new Rect(snapshot.getContentInsets()); + orientation = snapshot.getOrientation(); + reducedResolution = snapshot.isReducedResolution(); + scale = snapshot.getScale(); } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/AnimationProps.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/AnimationProps.java index 716d1bcf78c2..2de7f74ba477 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/AnimationProps.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/AnimationProps.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.recents.views; +package com.android.systemui.shared.recents.utilities; import android.animation.Animator; import android.animation.AnimatorSet; @@ -24,8 +24,7 @@ import android.util.SparseArray; import android.util.SparseLongArray; import android.view.View; import android.view.animation.Interpolator; - -import com.android.systemui.Interpolators; +import android.view.animation.LinearInterpolator; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -37,7 +36,8 @@ import java.util.List; */ public class AnimationProps { - public static final AnimationProps IMMEDIATE = new AnimationProps(0, Interpolators.LINEAR); + private static final Interpolator LINEAR_INTERPOLATOR = new LinearInterpolator(); + public static final AnimationProps IMMEDIATE = new AnimationProps(0, LINEAR_INTERPOLATOR); @Retention(RetentionPolicy.SOURCE) @IntDef({ALL, TRANSLATION_X, TRANSLATION_Y, TRANSLATION_Z, ALPHA, SCALE, BOUNDS}) @@ -51,7 +51,6 @@ public class AnimationProps { public static final int SCALE = 5; public static final int BOUNDS = 6; public static final int DIM_ALPHA = 7; - public static final int FOCUS_STATE = 8; private SparseLongArray mPropStartDelay; private SparseLongArray mPropDuration; @@ -195,9 +194,9 @@ public class AnimationProps { if (interp != null) { return interp; } - return mPropInterpolators.get(ALL, Interpolators.LINEAR); + return mPropInterpolators.get(ALL, LINEAR_INTERPOLATOR); } - return Interpolators.LINEAR; + return LINEAR_INTERPOLATOR; } /** diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/RectFEvaluator.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/RectFEvaluator.java index 72511de9ec80..51c1b5aa13d7 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/misc/RectFEvaluator.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/RectFEvaluator.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.systemui.recents.misc; +package com.android.systemui.shared.recents.utilities; import android.animation.TypeEvaluator; import android.graphics.RectF; @@ -23,7 +23,7 @@ import android.graphics.RectF; */ public class RectFEvaluator implements TypeEvaluator<RectF> { - private RectF mRect = new RectF(); + private final RectF mRect = new RectF(); /** * This function returns the result of linearly interpolating the start and diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java index 4349e30f60e0..a5d19639580e 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.recents.misc; +package com.android.systemui.shared.recents.utilities; import android.animation.Animator; import android.animation.AnimatorSet; @@ -38,12 +38,8 @@ import android.view.ViewGroup; import android.view.ViewParent; import android.view.ViewStub; -import com.android.systemui.recents.model.Task; -import com.android.systemui.recents.views.TaskViewTransform; - import java.util.ArrayList; import java.util.Collections; -import java.util.List; /* Common code */ public class Utilities { @@ -76,7 +72,6 @@ public class Utilities { public static final RectFEvaluator RECTF_EVALUATOR = new RectFEvaluator(); public static final RectEvaluator RECT_EVALUATOR = new RectEvaluator(new Rect()); - public static final Rect EMPTY_RECT = new Rect(); /** * @return the first parent walking up the view hierarchy that has the given class type. @@ -253,24 +248,6 @@ public class Utilities { } /** - * Updates {@param transforms} to be the same size as {@param tasks}. - */ - public static void matchTaskListSize(List<Task> tasks, List<TaskViewTransform> transforms) { - // We can reuse the task transforms where possible to reduce object allocation - int taskTransformCount = transforms.size(); - int taskCount = tasks.size(); - if (taskTransformCount < taskCount) { - // If there are less transforms than tasks, then add as many transforms as necessary - for (int i = taskTransformCount; i < taskCount; i++) { - transforms.add(new TaskViewTransform()); - } - } else if (taskTransformCount > taskCount) { - // If there are more transforms than tasks, then just subset the transform list - transforms.subList(taskCount, taskTransformCount).clear(); - } - } - - /** * Used for debugging, converts DP to PX. */ public static float dpToPx(Resources res, float dp) { diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java new file mode 100644 index 000000000000..3f93f76af7e4 --- /dev/null +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2015 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.shared.system; + +import static android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE; + +import android.annotation.NonNull; +import android.app.ActivityManager; +import android.app.ActivityManager.RecentTaskInfo; +import android.app.AppGlobals; +import android.content.Context; +import android.content.pm.ActivityInfo; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.content.pm.UserInfo; +import android.content.res.Resources; +import android.content.res.Resources.NotFoundException; +import android.graphics.Bitmap; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.os.RemoteException; +import android.os.UserHandle; +import android.util.IconDrawableFactory; +import android.util.Log; + +import com.android.systemui.shared.recents.model.ThumbnailData; + +import java.util.ArrayList; +import java.util.List; + +public class ActivityManagerWrapper { + + private static final String TAG = "ActivityManagerWrapper"; + + private static final ActivityManagerWrapper sInstance = new ActivityManagerWrapper(); + + private final PackageManager mPackageManager; + private final IconDrawableFactory mDrawableFactory; + + private ActivityManagerWrapper() { + final Context context = AppGlobals.getInitialApplication(); + mPackageManager = context.getPackageManager(); + mDrawableFactory = IconDrawableFactory.newInstance(context); + } + + public static ActivityManagerWrapper getInstance() { + return sInstance; + } + + /** + * @return the current user's id. + */ + public int getCurrentUserId() { + UserInfo ui; + try { + ui = ActivityManager.getService().getCurrentUser(); + return ui != null ? ui.id : 0; + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * @return a list of the recents tasks. + */ + public List<RecentTaskInfo> getRecentTasks(int numTasks, int userId) { + try { + return ActivityManager.getService().getRecentTasks(numTasks, + RECENT_IGNORE_UNAVAILABLE, userId).getList(); + } catch (RemoteException e) { + Log.e(TAG, "Failed to get recent tasks", e); + return new ArrayList<>(); + } + } + + /** + * @return the task snapshot for the given {@param taskId}. + */ + public @NonNull ThumbnailData getTaskThumbnail(int taskId, boolean reducedResolution) { + ActivityManager.TaskSnapshot snapshot = null; + try { + snapshot = ActivityManager.getService().getTaskSnapshot(taskId, reducedResolution); + } catch (RemoteException e) { + Log.w(TAG, "Failed to retrieve task snapshot", e); + } + if (snapshot != null) { + return new ThumbnailData(snapshot); + } else { + return new ThumbnailData(); + } + } + + /** + * @return the task description icon, loading and badging it if it necessary. + */ + public Drawable getBadgedTaskDescriptionIcon(Context context, + ActivityManager.TaskDescription taskDescription, int userId, Resources res) { + Bitmap tdIcon = taskDescription.getInMemoryIcon(); + Drawable dIcon = null; + if (tdIcon != null) { + dIcon = new BitmapDrawable(res, tdIcon); + } else if (taskDescription.getIconResource() != 0) { + try { + dIcon = context.getDrawable(taskDescription.getIconResource()); + } catch (NotFoundException e) { + Log.e(TAG, "Could not find icon drawable from resource", e); + } + } else { + tdIcon = ActivityManager.TaskDescription.loadTaskDescriptionIcon( + taskDescription.getIconFilename(), userId); + if (tdIcon != null) { + dIcon = new BitmapDrawable(res, tdIcon); + } + } + if (dIcon != null) { + return getBadgedIcon(dIcon, userId); + } + return null; + } + + /** + * @return the given icon for a user, badging if necessary. + */ + private Drawable getBadgedIcon(Drawable icon, int userId) { + if (userId != UserHandle.myUserId()) { + icon = mPackageManager.getUserBadgedIcon(icon, new UserHandle(userId)); + } + return icon; + } + + /** + * @return the activity icon for the ActivityInfo for a user, badging if necessary. + */ + public Drawable getBadgedActivityIcon(ActivityInfo info, int userId) { + return mDrawableFactory.getBadgedIcon(info, info.applicationInfo, userId); + } + + /** + * @return the application icon for the ApplicationInfo for a user, badging if necessary. + */ + public Drawable getBadgedApplicationIcon(ApplicationInfo appInfo, int userId) { + return mDrawableFactory.getBadgedIcon(appInfo, userId); + } + + /** + * @return the activity label, badging if necessary. + */ + public String getBadgedActivityLabel(ActivityInfo info, int userId) { + return getBadgedLabel(info.loadLabel(mPackageManager).toString(), userId); + } + + /** + * @return the application label, badging if necessary. + */ + public String getBadgedApplicationLabel(ApplicationInfo appInfo, int userId) { + return getBadgedLabel(appInfo.loadLabel(mPackageManager).toString(), userId); + } + + /** + * @return the content description for a given task, badging it if necessary. The content + * description joins the app and activity labels. + */ + public String getBadgedContentDescription(ActivityInfo info, int userId, + ActivityManager.TaskDescription td) { + String activityLabel; + if (td != null && td.getLabel() != null) { + activityLabel = td.getLabel(); + } else { + activityLabel = info.loadLabel(mPackageManager).toString(); + } + String applicationLabel = info.applicationInfo.loadLabel(mPackageManager).toString(); + String badgedApplicationLabel = getBadgedLabel(applicationLabel, userId); + return applicationLabel.equals(activityLabel) + ? badgedApplicationLabel + : badgedApplicationLabel + " " + activityLabel; + } + + /** + * @return the given label for a user, badging if necessary. + */ + private String getBadgedLabel(String label, int userId) { + if (userId != UserHandle.myUserId()) { + label = mPackageManager.getUserBadgedLabel(label, new UserHandle(userId)).toString(); + } + return label; + } +} diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/PackageManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/PackageManagerWrapper.java new file mode 100644 index 000000000000..d5e6e6efb3cf --- /dev/null +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/PackageManagerWrapper.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2015 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.shared.system; + +import android.app.AppGlobals; +import android.content.ComponentName; +import android.content.pm.ActivityInfo; +import android.content.pm.IPackageManager; +import android.content.pm.PackageManager; +import android.os.RemoteException; + +public class PackageManagerWrapper { + + private static final String TAG = "PackageManagerWrapper"; + + private static final PackageManagerWrapper sInstance = new PackageManagerWrapper(); + + private static final IPackageManager mIPackageManager = AppGlobals.getPackageManager(); + + public static PackageManagerWrapper getInstance() { + return sInstance; + } + + /** + * @return the activity info for a given {@param componentName} and {@param userId}. + */ + public ActivityInfo getActivityInfo(ComponentName componentName, int userId) { + try { + return mIPackageManager.getActivityInfo(componentName, PackageManager.GET_META_DATA, + userId); + } catch (RemoteException e) { + e.printStackTrace(); + return null; + } + } +} diff --git a/packages/SystemUI/shared/tests/Android.mk b/packages/SystemUI/shared/tests/Android.mk new file mode 100644 index 000000000000..ce3b4424de50 --- /dev/null +++ b/packages/SystemUI/shared/tests/Android.mk @@ -0,0 +1,53 @@ +# Copyright (C) 2017 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. + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_USE_AAPT2 := true +LOCAL_MODULE_TAGS := tests + +LOCAL_JACK_FLAGS := --multi-dex native +LOCAL_DX_FLAGS := --multi-dex + +LOCAL_PROTOC_OPTIMIZE_TYPE := nano +LOCAL_PROTOC_FLAGS := -I$(LOCAL_PATH)/.. +LOCAL_PROTO_JAVA_OUTPUT_PARAMS := optional_field_style=accessors + +LOCAL_PACKAGE_NAME := SystemUISharedLibTests +LOCAL_COMPATIBILITY_SUITE := device-tests + +# Add local path sources as well as shared lib sources +LOCAL_SRC_FILES := $(call all-java-files-under, src) \ + $(call all-java-files-under, ../src) + +LOCAL_STATIC_JAVA_LIBRARIES := \ + metrics-helper-lib \ + android-support-test \ + mockito-target-minus-junit4 \ + SystemUI-proto \ + SystemUI-tags \ + legacy-android-test \ + testables \ + truth-prebuilt \ + +LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common android.car + +# sign this with platform cert, so this test is allowed to inject key events into +# UI it doesn't own. This is necessary to allow screenshots to be taken +LOCAL_CERTIFICATE := platform + +ifeq ($(EXCLUDE_SYSTEMUI_TESTS),) + include $(BUILD_PACKAGE) +endif
\ No newline at end of file diff --git a/packages/SystemUI/shared/tests/AndroidManifest.xml b/packages/SystemUI/shared/tests/AndroidManifest.xml new file mode 100644 index 000000000000..3e1de499c801 --- /dev/null +++ b/packages/SystemUI/shared/tests/AndroidManifest.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2017 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. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.systemui.shared.tests"> + + <uses-permission android:name="android.permission.READ_FRAME_BUFFER" /> + + <application> + <uses-library android:name="android.test.runner" /> + </application> + + <instrumentation android:name="android.testing.TestableInstrumentation" + android:targetPackage="com.android.systemui.shared.tests" + android:label="Tests for SystemUISharedLib"> + </instrumentation> +</manifest> diff --git a/packages/SystemUI/shared/tests/AndroidTest.xml b/packages/SystemUI/shared/tests/AndroidTest.xml new file mode 100644 index 000000000000..b3de8368deec --- /dev/null +++ b/packages/SystemUI/shared/tests/AndroidTest.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2017 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. +--> +<configuration description="Runs Tests for SystemUISharedLib."> + <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup"> + <option name="test-file-name" value="SystemUISharedLibTests.apk" /> + </target_preparer> + + <option name="test-suite-tag" value="apct" /> + <option name="test-suite-tag" value="framework-base-presubmit" /> + <option name="test-tag" value="SystemUISharedLibTests" /> + <test class="com.android.tradefed.testtype.AndroidJUnitTest" > + <option name="package" value="com.android.systemui.shared.tests" /> + <option name="runner" value="android.testing.TestableInstrumentation" /> + </test> +</configuration> diff --git a/packages/SystemUI/shared/tests/src/com/android/systemui/shared/SysuiSharedLibTestCase.java b/packages/SystemUI/shared/tests/src/com/android/systemui/shared/SysuiSharedLibTestCase.java new file mode 100644 index 000000000000..04b341e38c04 --- /dev/null +++ b/packages/SystemUI/shared/tests/src/com/android/systemui/shared/SysuiSharedLibTestCase.java @@ -0,0 +1,113 @@ +/* + * 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.shared; + +import android.content.Context; +import android.os.Handler; +import android.os.Looper; +import android.os.MessageQueue; +import android.support.test.InstrumentationRegistry; + +import org.junit.After; +import org.junit.Before; + +/** + * Base class that does System UI Shared Lib specific setup. + */ +public abstract class SysuiSharedLibTestCase { + + private static final String TAG = "SysuiSharedLibTestCase"; + + private Handler mHandler; + private Context mContext = InstrumentationRegistry.getContext(); + + @Before + public void SysuiSetup() throws Exception { + // Enable shared class loader to test package-private classes/methods + System.setProperty("dexmaker.share_classloader", "true"); + } + + @After + public void SysuiTeardown() { + // Do nothing + } + + public Context getContext() { + return mContext; + } + + protected void waitForIdleSync() { + if (mHandler == null) { + mHandler = new Handler(Looper.getMainLooper()); + } + waitForIdleSync(mHandler); + } + + public static void waitForIdleSync(Handler h) { + validateThread(h.getLooper()); + Idler idler = new Idler(null); + h.getLooper().getQueue().addIdleHandler(idler); + // Ensure we are non-idle, so the idle handler can run. + h.post(new EmptyRunnable()); + idler.waitForIdle(); + } + + private static final void validateThread(Looper l) { + if (Looper.myLooper() == l) { + throw new RuntimeException( + "This method can not be called from the looper being synced"); + } + } + + public static final class EmptyRunnable implements Runnable { + public void run() { + } + } + + public static final class Idler implements MessageQueue.IdleHandler { + private final Runnable mCallback; + private boolean mIdle; + + public Idler(Runnable callback) { + mCallback = callback; + mIdle = false; + } + + @Override + public boolean queueIdle() { + if (mCallback != null) { + mCallback.run(); + } + synchronized (this) { + mIdle = true; + notifyAll(); + } + return false; + } + + public void waitForIdle() { + synchronized (this) { + while (!mIdle) { + try { + wait(); + } catch (InterruptedException e) { + } + } + } + } + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/recents/model/HighResThumbnailLoaderTest.java b/packages/SystemUI/shared/tests/src/com/android/systemui/shared/recents/model/HighResThumbnailLoaderTest.java index 4564c8c79814..b03ea90fb1db 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/recents/model/HighResThumbnailLoaderTest.java +++ b/packages/SystemUI/shared/tests/src/com/android/systemui/shared/recents/model/HighResThumbnailLoaderTest.java @@ -14,9 +14,10 @@ * limitations under the License */ -package com.android.systemui.recents.model; +package com.android.systemui.shared.recents.model; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; + import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.anyBoolean; @@ -29,9 +30,9 @@ import android.os.Looper; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; -import com.android.systemui.SysuiTestCase; -import com.android.systemui.recents.misc.SystemServicesProxy; -import com.android.systemui.recents.model.Task.TaskKey; +import com.android.systemui.shared.SysuiSharedLibTestCase; +import com.android.systemui.shared.recents.model.Task.TaskKey; +import com.android.systemui.shared.system.ActivityManagerWrapper; import org.junit.Before; import org.junit.Test; @@ -40,16 +41,16 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; /** - * runtest systemui -c com.android.systemui.recents.model.HighResThumbnailLoaderTest + * runtest --path frameworks/base/packages/SystemUI/shared/tests/src/com/android/systemui/shared/recents/model/HighResThumbnailLoaderTest.java */ @SmallTest @RunWith(AndroidJUnit4.class) -public class HighResThumbnailLoaderTest extends SysuiTestCase { +public class HighResThumbnailLoaderTest extends SysuiSharedLibTestCase { private HighResThumbnailLoader mLoader; @Mock - private SystemServicesProxy mMockSystemServicesProxy; + private ActivityManagerWrapper mMockActivityManagerWrapper; @Mock private Task mTask; @@ -58,10 +59,10 @@ public class HighResThumbnailLoaderTest extends SysuiTestCase { @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); - mLoader = new HighResThumbnailLoader(mMockSystemServicesProxy, Looper.getMainLooper(), - false); + mLoader = new HighResThumbnailLoader(mMockActivityManagerWrapper, Looper.getMainLooper(), + false /* reducedResolution */); mTask.key = new TaskKey(0, WINDOWING_MODE_UNDEFINED, null, 0, 0); - when(mMockSystemServicesProxy.getTaskThumbnail(anyInt(), anyBoolean())) + when(mMockActivityManagerWrapper.getTaskThumbnail(anyInt(), anyBoolean())) .thenReturn(mThumbnailData); mLoader.setVisible(true); mLoader.setTaskLoadQueueIdle(true); diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/InputConsumerController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/InputConsumerController.java index abc5667251ea..e6d6c5586ad8 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/InputConsumerController.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/InputConsumerController.java @@ -28,8 +28,6 @@ import android.view.InputEvent; import android.view.IWindowManager; import android.view.MotionEvent; -import com.android.systemui.recents.misc.Utilities; - import java.io.PrintWriter; /** diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java index ed4e674c0a55..ce1438a14e52 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java +++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java @@ -29,14 +29,13 @@ import android.content.Intent; import android.content.ServiceConnection; import android.content.pm.ActivityInfo; import android.content.res.Configuration; +import android.content.res.Resources; import android.graphics.Point; import android.graphics.Rect; import android.hardware.display.DisplayManager; -import android.os.Build; import android.os.Handler; import android.os.IBinder; import android.os.RemoteException; -import android.os.SystemProperties; import android.os.UserHandle; import android.provider.Settings; import android.util.EventLog; @@ -63,7 +62,7 @@ import com.android.systemui.recents.events.component.SetWaitingForTransitionStar 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.shared.recents.model.RecentsTaskLoader; import com.android.systemui.stackdivider.Divider; import com.android.systemui.statusbar.CommandQueue; @@ -192,10 +191,20 @@ public class Recents extends SystemUI @Override public void start() { + final Resources res = mContext.getResources(); + final int defaultTaskBarBackgroundColor = + mContext.getColor(R.color.recents_task_bar_default_background_color); + final int defaultTaskViewBackgroundColor = + mContext.getColor(R.color.recents_task_view_default_background_color); sDebugFlags = new RecentsDebugFlags(); sSystemServicesProxy = SystemServicesProxy.getInstance(mContext); sConfiguration = new RecentsConfiguration(mContext); - sTaskLoader = new RecentsTaskLoader(mContext); + sTaskLoader = new RecentsTaskLoader(mContext, + // TODO: Once we start building the AAR, move these into the loader + res.getInteger(R.integer.config_recents_max_thumbnail_count), + res.getInteger(R.integer.config_recents_max_icon_count), + res.getInteger(R.integer.recents_svelte_level)); + sTaskLoader.setDefaultColors(defaultTaskBarBackgroundColor, defaultTaskViewBackgroundColor); mHandler = new Handler(); mImpl = new RecentsImpl(mContext); diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java index 711885c40692..b75a142864e8 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java @@ -85,11 +85,11 @@ import com.android.systemui.recents.events.ui.focus.FocusPreviousTaskViewEvent; import com.android.systemui.recents.events.ui.focus.NavigateTaskViewEvent; import com.android.systemui.recents.events.ui.focus.NavigateTaskViewEvent.Direction; import com.android.systemui.recents.misc.SystemServicesProxy; -import com.android.systemui.recents.misc.Utilities; -import com.android.systemui.recents.model.RecentsTaskLoadPlan; -import com.android.systemui.recents.model.RecentsTaskLoader; -import com.android.systemui.recents.model.Task; -import com.android.systemui.recents.model.TaskStack; +import com.android.systemui.shared.recents.utilities.Utilities; +import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan; +import com.android.systemui.shared.recents.model.RecentsTaskLoader; +import com.android.systemui.shared.recents.model.Task; +import com.android.systemui.shared.recents.model.TaskStack; import com.android.systemui.recents.views.RecentsView; import com.android.systemui.recents.views.SystemBarScrimViews; import com.android.systemui.statusbar.phone.StatusBar; @@ -427,7 +427,7 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD RecentsTaskLoader loader = Recents.getTaskLoader(); RecentsTaskLoadPlan loadPlan = RecentsImpl.consumeInstanceLoadPlan(); if (loadPlan == null) { - loadPlan = loader.createLoadPlan(this); + loadPlan = new RecentsTaskLoadPlan(this); } // Start loading tasks according to the load plan @@ -441,7 +441,7 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD loadOpts.runningTaskId = launchState.launchedToTaskId; loadOpts.numVisibleTasks = launchState.launchedNumVisibleTasks; loadOpts.numVisibleTaskThumbnails = launchState.launchedNumVisibleThumbnails; - loader.loadTasks(this, loadPlan, loadOpts); + loader.loadTasks(loadPlan, loadOpts); TaskStack stack = loadPlan.getTaskStack(); mRecentsView.onReload(stack, mIsVisible); @@ -815,13 +815,13 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD RecentsConfiguration config = Recents.getConfiguration(); RecentsActivityLaunchState launchState = config.getLaunchState(); RecentsTaskLoader loader = Recents.getTaskLoader(); - RecentsTaskLoadPlan loadPlan = loader.createLoadPlan(this); + RecentsTaskLoadPlan loadPlan = new RecentsTaskLoadPlan(this); loader.preloadTasks(loadPlan, -1 /* runningTaskId */); RecentsTaskLoadPlan.Options loadOpts = new RecentsTaskLoadPlan.Options(); loadOpts.numVisibleTasks = launchState.launchedNumVisibleTasks; loadOpts.numVisibleTaskThumbnails = launchState.launchedNumVisibleThumbnails; - loader.loadTasks(this, loadPlan, loadOpts); + loader.loadTasks(loadPlan, loadOpts); TaskStack stack = loadPlan.getTaskStack(); int numStackTasks = stack.getStackTaskCount(); diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java index 2c3a727e00b9..d2326ce2673d 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java @@ -33,7 +33,6 @@ public class RecentsActivityLaunchState { public boolean launchedFromPipApp; // Set if the next activity that quick-switch will launch is the PiP activity public boolean launchedWithNextPipApp; - public boolean launchedFromBlacklistedApp; public boolean launchedFromHome; public boolean launchedViaDragGesture; public boolean launchedViaDockGesture; @@ -44,7 +43,6 @@ public class RecentsActivityLaunchState { public void reset() { launchedFromHome = false; launchedFromApp = false; - launchedFromBlacklistedApp = false; launchedFromPipApp = false; launchedWithNextPipApp = false; launchedToTaskId = -1; @@ -60,12 +58,6 @@ public class RecentsActivityLaunchState { RecentsDebugFlags debugFlags = Recents.getDebugFlags(); RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState(); if (launchedFromApp) { - if (launchState.launchedFromBlacklistedApp) { - // If we are launching from a blacklisted app, focus the front most task so that the - // next tap will launch the task - return numTasks - 1; - } - if (useGridLayout) { // If coming from another app to the grid layout, focus the front most task return numTasks - 1; diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java index 5dc6f31cae9a..68df1d5bd322 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java @@ -20,31 +20,31 @@ import android.app.ActivityManager; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; -import android.graphics.Rect; import android.os.SystemProperties; import com.android.systemui.R; import com.android.systemui.recents.misc.SystemServicesProxy; -import com.android.systemui.recents.model.TaskStack; +import com.android.systemui.recents.views.DockState; +import com.android.systemui.shared.recents.model.TaskStack; /** * Represents the dock regions for each orientation. */ class DockRegion { - public static TaskStack.DockState[] PHONE_LANDSCAPE = { + public static DockState[] PHONE_LANDSCAPE = { // We only allow docking to the left in landscape for now on small devices - TaskStack.DockState.LEFT + DockState.LEFT }; - public static TaskStack.DockState[] PHONE_PORTRAIT = { + public static DockState[] PHONE_PORTRAIT = { // We only allow docking to the top for now on small devices - TaskStack.DockState.TOP + DockState.TOP }; - public static TaskStack.DockState[] TABLET_LANDSCAPE = { - TaskStack.DockState.LEFT, - TaskStack.DockState.RIGHT + public static DockState[] TABLET_LANDSCAPE = { + DockState.LEFT, + DockState.RIGHT }; - public static TaskStack.DockState[] TABLET_PORTRAIT = PHONE_PORTRAIT; + public static DockState[] TABLET_PORTRAIT = PHONE_PORTRAIT; } /** @@ -56,18 +56,6 @@ public class RecentsConfiguration { private static final int LARGE_SCREEN_MIN_DP = 600; private static final int XLARGE_SCREEN_MIN_DP = 720; - /** Levels of svelte in increasing severity/austerity. */ - // No svelting. - public static final int SVELTE_NONE = 0; - // Limit thumbnail cache to number of visible thumbnails when Recents was loaded, disable - // caching thumbnails as you scroll. - public static final int SVELTE_LIMIT_CACHE = 1; - // Disable the thumbnail cache, load thumbnails asynchronously when the activity loads and - // evict all thumbnails when hidden. - public static final int SVELTE_DISABLE_CACHE = 2; - // Disable all thumbnail loading. - public static final int SVELTE_DISABLE_LOADING = 3; - // Launch states public RecentsActivityLaunchState mLaunchState = new RecentsActivityLaunchState(); @@ -125,7 +113,7 @@ public class RecentsConfiguration { * Returns the preferred dock states for the current orientation. * @return a list of dock states for device and its orientation */ - public TaskStack.DockState[] getDockStatesForCurrentOrientation() { + public DockState[] getDockStatesForCurrentOrientation() { boolean isLandscape = mAppContext.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE; RecentsConfiguration config = Recents.getConfiguration(); diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java index a8dafbf70f4e..19185939c553 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java @@ -21,8 +21,6 @@ public class RecentsDebugFlags { public static class Static { // Enables debug drawing for the transition thumbnail public static final boolean EnableTransitionThumbnailDebugMode = false; - // Enables debug thumbnail to be fetched - public static final boolean EnableThumbnailDebugMode = false; // Disables enter and exit transitions for other tasks for low ram devices public static final boolean DisableRecentsLowRamEnterExitAnimation = false; diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java index 3f8d53f10616..868ed64bab2e 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java @@ -71,12 +71,12 @@ import com.android.systemui.recents.misc.DozeTrigger; import com.android.systemui.recents.misc.ForegroundThread; import com.android.systemui.recents.misc.SystemServicesProxy; import com.android.systemui.recents.misc.TaskStackChangeListener; -import com.android.systemui.recents.model.RecentsTaskLoadPlan; -import com.android.systemui.recents.model.RecentsTaskLoader; -import com.android.systemui.recents.model.Task; -import com.android.systemui.recents.model.Task.TaskKey; -import com.android.systemui.recents.model.TaskStack; -import com.android.systemui.recents.model.ThumbnailData; +import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan; +import com.android.systemui.shared.recents.model.RecentsTaskLoader; +import com.android.systemui.shared.recents.model.Task; +import com.android.systemui.shared.recents.model.Task.TaskKey; +import com.android.systemui.shared.recents.model.TaskStack; +import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.recents.views.RecentsTransitionHelper; import com.android.systemui.recents.views.RecentsTransitionHelper.AppTransitionAnimationSpecsFuture; import com.android.systemui.recents.views.TaskStackLayoutAlgorithm; @@ -127,7 +127,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener // Preloads the next task RecentsConfiguration config = Recents.getConfiguration(); - if (config.svelteLevel == RecentsConfiguration.SVELTE_NONE) { + if (config.svelteLevel == RecentsTaskLoader.SVELTE_NONE) { Rect windowRect = getWindowRect(null /* windowRectOverride */); if (windowRect.isEmpty()) { return; @@ -137,7 +137,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener SystemServicesProxy ssp = Recents.getSystemServices(); ActivityManager.RunningTaskInfo runningTaskInfo = ssp.getRunningTask(); RecentsTaskLoader loader = Recents.getTaskLoader(); - RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext); + RecentsTaskLoadPlan plan = new RecentsTaskLoadPlan(mContext); loader.preloadTasks(plan, -1); TaskStack stack = plan.getTaskStack(); RecentsActivityLaunchState launchState = new RecentsActivityLaunchState(); @@ -164,7 +164,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener launchOpts.onlyLoadPausedActivities = true; launchOpts.loadThumbnails = true; } - loader.loadTasks(mContext, plan, launchOpts); + loader.loadTasks(plan, launchOpts); } } @@ -203,7 +203,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener } EventBus.getDefault().send(new TaskSnapshotChangedEvent(taskId, - ThumbnailData.createFromTaskSnapshot(snapshot))); + new ThumbnailData(snapshot))); } } @@ -278,13 +278,13 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener // When we start, preload the data associated with the previous recent tasks. // We can use a new plan since the caches will be the same. RecentsTaskLoader loader = Recents.getTaskLoader(); - RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext); + RecentsTaskLoadPlan plan = new RecentsTaskLoadPlan(mContext); loader.preloadTasks(plan, -1); RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options(); launchOpts.numVisibleTasks = loader.getIconCacheSize(); launchOpts.numVisibleTaskThumbnails = loader.getThumbnailCacheSize(); launchOpts.onlyLoadForCache = true; - loader.loadTasks(mContext, plan, launchOpts); + loader.loadTasks(plan, launchOpts); } public void onConfigurationChanged() { @@ -471,7 +471,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener } RecentsTaskLoader loader = Recents.getTaskLoader(); - sInstanceLoadPlan = loader.createLoadPlan(mContext); + sInstanceLoadPlan = new RecentsTaskLoadPlan(mContext); loader.preloadTasks(sInstanceLoadPlan, runningTask.id); TaskStack stack = sInstanceLoadPlan.getTaskStack(); if (stack.getTaskCount() > 0) { @@ -511,7 +511,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener public void showNextTask() { SystemServicesProxy ssp = Recents.getSystemServices(); RecentsTaskLoader loader = Recents.getTaskLoader(); - RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext); + RecentsTaskLoadPlan plan = new RecentsTaskLoadPlan(mContext); loader.preloadTasks(plan, -1); TaskStack focusedStack = plan.getTaskStack(); @@ -566,7 +566,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener public void showRelativeAffiliatedTask(boolean showNextTask) { SystemServicesProxy ssp = Recents.getSystemServices(); RecentsTaskLoader loader = Recents.getTaskLoader(); - RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext); + RecentsTaskLoadPlan plan = new RecentsTaskLoadPlan(mContext); loader.preloadTasks(plan, -1); TaskStack focusedStack = plan.getTaskStack(); @@ -827,7 +827,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener launchOpts.runningTaskId = runningTaskId; launchOpts.loadThumbnails = false; launchOpts.onlyLoadForCache = true; - Recents.getTaskLoader().loadTasks(mContext, sInstanceLoadPlan, launchOpts); + Recents.getTaskLoader().loadTasks(sInstanceLoadPlan, launchOpts); } /** @@ -947,12 +947,8 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener boolean isHomeStackVisible, boolean animate, int growTarget) { RecentsTaskLoader loader = Recents.getTaskLoader(); RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState(); - SystemServicesProxy ssp = Recents.getSystemServices(); - boolean isBlacklisted = (runningTask != null) - ? ssp.isBlackListedActivity(runningTask.baseActivity.getClassName()) - : false; - int runningTaskId = !mLaunchedWhileDocking && !isBlacklisted && (runningTask != null) + int runningTaskId = !mLaunchedWhileDocking && (runningTask != null) ? runningTask.id : -1; @@ -961,7 +957,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener // the stacks might have changed. if (mLaunchedWhileDocking || mTriggeredFromAltTab || sInstanceLoadPlan == null) { // Create a new load plan if preloadRecents() was never triggered - sInstanceLoadPlan = loader.createLoadPlan(mContext); + sInstanceLoadPlan = new RecentsTaskLoadPlan(mContext); } if (mLaunchedWhileDocking || mTriggeredFromAltTab || !sInstanceLoadPlan.hasTasks()) { loader.preloadTasks(sInstanceLoadPlan, runningTaskId); @@ -975,7 +971,6 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener // Update the launch state that we need in updateHeaderBarLayout() launchState.launchedFromHome = !useThumbnailTransition && !mLaunchedWhileDocking; launchState.launchedFromApp = useThumbnailTransition || mLaunchedWhileDocking; - launchState.launchedFromBlacklistedApp = launchState.launchedFromApp && isBlacklisted; launchState.launchedFromPipApp = false; launchState.launchedWithNextPipApp = stack.isNextLaunchTargetPip(RecentsImpl.getLastPipTime()); @@ -1011,9 +1006,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener } Pair<ActivityOptions, AppTransitionAnimationSpecsFuture> pair; - if (isBlacklisted) { - pair = new Pair<>(getUnknownTransitionActivityOptions(), null); - } else if (useThumbnailTransition) { + if (useThumbnailTransition) { // Try starting with a thumbnail transition pair = getThumbnailTransitionActivityOptions(runningTask, windowOverrideRect); } else { diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/CancelEnterRecentsWindowAnimationEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/CancelEnterRecentsWindowAnimationEvent.java index 7604de1d05d0..fec34e3cd23d 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/CancelEnterRecentsWindowAnimationEvent.java +++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/CancelEnterRecentsWindowAnimationEvent.java @@ -17,7 +17,7 @@ package com.android.systemui.recents.events.activity; import com.android.systemui.recents.events.EventBus; -import com.android.systemui.recents.model.Task; +import com.android.systemui.shared.recents.model.Task; /** * This is sent when we want to cancel the enter-recents window animation for the launch task. diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskEvent.java index 862a1eee8c39..2409f39d3760 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskEvent.java +++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskEvent.java @@ -22,7 +22,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import android.graphics.Rect; import com.android.systemui.recents.events.EventBus; -import com.android.systemui.recents.model.Task; +import com.android.systemui.shared.recents.model.Task; import com.android.systemui.recents.views.TaskView; /** diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/MultiWindowStateChangedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/MultiWindowStateChangedEvent.java index 64eeafa1ae17..e4972b1fd7f4 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/MultiWindowStateChangedEvent.java +++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/MultiWindowStateChangedEvent.java @@ -17,7 +17,7 @@ package com.android.systemui.recents.events.activity; import com.android.systemui.recents.events.EventBus; -import com.android.systemui.recents.model.TaskStack; +import com.android.systemui.shared.recents.model.TaskStack; /** * This is sent by the activity whenever the multi-window state has changed. diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/TaskStackUpdatedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/TaskStackUpdatedEvent.java index 0d614e8c675c..51d02b5b0018 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/TaskStackUpdatedEvent.java +++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/TaskStackUpdatedEvent.java @@ -17,7 +17,7 @@ package com.android.systemui.recents.events.activity; import com.android.systemui.recents.events.EventBus; -import com.android.systemui.recents.model.TaskStack; +import com.android.systemui.shared.recents.model.TaskStack; /** * This is sent by the activity whenever the task stach has changed. diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/DeleteTaskDataEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/DeleteTaskDataEvent.java index 4ed027084def..b52e83b81649 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/DeleteTaskDataEvent.java +++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/DeleteTaskDataEvent.java @@ -17,7 +17,7 @@ package com.android.systemui.recents.events.ui; import com.android.systemui.recents.events.EventBus; -import com.android.systemui.recents.model.Task; +import com.android.systemui.shared.recents.model.Task; /** * This is sent when the data associated with a given {@link Task} should be deleted from the diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/ShowApplicationInfoEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/ShowApplicationInfoEvent.java index 40c30b884eae..da19384ae93a 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/ShowApplicationInfoEvent.java +++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/ShowApplicationInfoEvent.java @@ -17,7 +17,7 @@ package com.android.systemui.recents.events.ui; import com.android.systemui.recents.events.EventBus; -import com.android.systemui.recents.model.Task; +import com.android.systemui.shared.recents.model.Task; /** * This is sent when a user wants to show the application info for a {@link Task}. diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/TaskSnapshotChangedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/TaskSnapshotChangedEvent.java index e0ed7a9e7e35..f08292801b62 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/TaskSnapshotChangedEvent.java +++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/TaskSnapshotChangedEvent.java @@ -17,7 +17,7 @@ package com.android.systemui.recents.events.ui; import com.android.systemui.recents.events.EventBus; -import com.android.systemui.recents.model.ThumbnailData; +import com.android.systemui.shared.recents.model.ThumbnailData; /** * Sent when a task snapshot has changed. diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/TaskViewDismissedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/TaskViewDismissedEvent.java index 0628c5015153..881a64af5b0f 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/TaskViewDismissedEvent.java +++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/TaskViewDismissedEvent.java @@ -17,8 +17,8 @@ package com.android.systemui.recents.events.ui; import com.android.systemui.recents.events.EventBus; -import com.android.systemui.recents.model.Task; -import com.android.systemui.recents.views.AnimationProps; +import com.android.systemui.shared.recents.model.Task; +import com.android.systemui.shared.recents.utilities.AnimationProps; import com.android.systemui.recents.views.TaskView; /** diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragDropTargetChangedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragDropTargetChangedEvent.java index 216be6121f8d..cf61b1ef7637 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragDropTargetChangedEvent.java +++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragDropTargetChangedEvent.java @@ -17,7 +17,7 @@ package com.android.systemui.recents.events.ui.dragndrop; import com.android.systemui.recents.events.EventBus; -import com.android.systemui.recents.model.Task; +import com.android.systemui.shared.recents.model.Task; import com.android.systemui.recents.views.DropTarget; /** diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragEndCancelledEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragEndCancelledEvent.java index edd799597ea6..297afc53c557 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragEndCancelledEvent.java +++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragEndCancelledEvent.java @@ -17,9 +17,8 @@ package com.android.systemui.recents.events.ui.dragndrop; import com.android.systemui.recents.events.EventBus; -import com.android.systemui.recents.model.Task; -import com.android.systemui.recents.model.TaskStack; -import com.android.systemui.recents.views.DropTarget; +import com.android.systemui.shared.recents.model.Task; +import com.android.systemui.shared.recents.model.TaskStack; import com.android.systemui.recents.views.TaskView; /** diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragEndEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragEndEvent.java index 73c282fe8816..73cbde998319 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragEndEvent.java +++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragEndEvent.java @@ -17,7 +17,7 @@ package com.android.systemui.recents.events.ui.dragndrop; import com.android.systemui.recents.events.EventBus; -import com.android.systemui.recents.model.Task; +import com.android.systemui.shared.recents.model.Task; import com.android.systemui.recents.views.DropTarget; import com.android.systemui.recents.views.TaskView; diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragStartEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragStartEvent.java index e57fa2d86a66..021be77bcc8b 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragStartEvent.java +++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragStartEvent.java @@ -19,7 +19,7 @@ package com.android.systemui.recents.events.ui.dragndrop; import android.graphics.Point; import com.android.systemui.recents.events.EventBus; -import com.android.systemui.recents.model.Task; +import com.android.systemui.shared.recents.model.Task; import com.android.systemui.recents.views.TaskView; /** diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragStartInitializeDropTargetsEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragStartInitializeDropTargetsEvent.java index 7030729d2a04..64ba5748bb89 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragStartInitializeDropTargetsEvent.java +++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragStartInitializeDropTargetsEvent.java @@ -17,7 +17,7 @@ package com.android.systemui.recents.events.ui.dragndrop; import com.android.systemui.recents.events.EventBus; -import com.android.systemui.recents.model.Task; +import com.android.systemui.shared.recents.model.Task; import com.android.systemui.recents.views.RecentsViewTouchHandler; import com.android.systemui.recents.views.TaskView; 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 2f21148e63f3..c5f07fd79b0a 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java +++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java @@ -16,7 +16,6 @@ package com.android.systemui.recents.misc; -import static android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; @@ -27,25 +26,20 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMAR import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; -import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityManager.StackInfo; import android.app.ActivityOptions; import android.app.AppGlobals; import android.app.IActivityManager; -import android.app.KeyguardManager; import android.app.WindowConfiguration; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; -import android.content.pm.ActivityInfo; -import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.content.res.Resources; -import android.content.res.Resources.NotFoundException; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; @@ -54,7 +48,6 @@ import android.graphics.Point; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.Rect; -import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.Handler; import android.os.IRemoteCallback; @@ -67,8 +60,6 @@ import android.os.UserManager; import android.provider.Settings; import android.service.dreams.DreamService; import android.service.dreams.IDreamManager; -import android.util.ArraySet; -import android.util.IconDrawableFactory; import android.util.Log; import android.util.MutableBoolean; import android.view.Display; @@ -85,17 +76,11 @@ import com.android.internal.os.BackgroundThread; import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.UiOffloadThread; -import com.android.systemui.pip.tv.PipMenuActivity; import com.android.systemui.recents.Recents; -import com.android.systemui.recents.RecentsDebugFlags.Static; import com.android.systemui.recents.RecentsImpl; -import com.android.systemui.recents.model.Task; -import com.android.systemui.recents.model.ThumbnailData; +import com.android.systemui.shared.recents.model.Task; import com.android.systemui.statusbar.policy.UserInfoController; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Iterator; import java.util.List; /** @@ -112,26 +97,18 @@ public class SystemServicesProxy { sBitmapOptions.inPreferredConfig = Bitmap.Config.RGB_565; } - final static List<String> sRecentsBlacklist; - static { - sRecentsBlacklist = new ArrayList<>(); - sRecentsBlacklist.add(PipMenuActivity.class.getName()); - } - private static SystemServicesProxy sSystemServicesProxy; AccessibilityManager mAccm; ActivityManager mAm; IActivityManager mIam; PackageManager mPm; - IconDrawableFactory mDrawableFactory; IPackageManager mIpm; private final IDreamManager mDreamManager; private final Context mContext; AssistUtils mAssistUtils; WindowManager mWm; IWindowManager mIwm; - KeyguardManager mKgm; UserManager mUm; Display mDisplay; String mRecentsPackage; @@ -167,12 +144,10 @@ public class SystemServicesProxy { mAm = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); mIam = ActivityManager.getService(); mPm = context.getPackageManager(); - mDrawableFactory = IconDrawableFactory.newInstance(context); mIpm = AppGlobals.getPackageManager(); mAssistUtils = new AssistUtils(context); mWm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); mIwm = WindowManagerGlobal.getWindowManagerService(); - mKgm = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE); mUm = UserManager.get(context); mDreamManager = IDreamManager.Stub.asInterface( ServiceManager.checkService(DreamService.DREAM_SERVICE)); @@ -200,9 +175,6 @@ public class SystemServicesProxy { // calls to fetch it. UserInfoController userInfoController = Dependency.get(UserInfoController.class); userInfoController.addCallback(mOnUserInfoChangedListener); - - Collections.addAll(sRecentsBlacklist, - res.getStringArray(R.array.recents_blacklist_array)); } /** @@ -224,38 +196,6 @@ public class SystemServicesProxy { } /** - * @return whether the provided {@param className} is blacklisted - */ - public boolean isBlackListedActivity(String className) { - return sRecentsBlacklist.contains(className); - } - - /** - * Returns a list of the recents tasks. - */ - public List<ActivityManager.RecentTaskInfo> getRecentTasks(int numTasks, int userId) { - if (mAm == null) return null; - try { - List<ActivityManager.RecentTaskInfo> tasks = mIam.getRecentTasks(numTasks, - RECENT_IGNORE_UNAVAILABLE, userId).getList(); - Iterator<ActivityManager.RecentTaskInfo> iter = tasks.iterator(); - while (iter.hasNext()) { - ActivityManager.RecentTaskInfo t = iter.next(); - - // Remove the task if it or it's package are blacklsited - if (sRecentsBlacklist.contains(t.realActivity.getClassName()) || - sRecentsBlacklist.contains(t.realActivity.getPackageName())) { - iter.remove(); - } - } - return tasks; - } catch (Exception e) { - Log.e(TAG, "Failed to get recent tasks", e); - return new ArrayList<>(); - } - } - - /** * Returns the top running task. */ public ActivityManager.RunningTaskInfo getRunningTask() { @@ -457,43 +397,6 @@ public class SystemServicesProxy { } } - /** Returns the top task thumbnail for the given task id */ - public ThumbnailData getTaskThumbnail(int taskId, boolean reduced) { - if (mAm == null) return null; - - // If we are mocking, then just return a dummy thumbnail - if (Static.EnableTransitionThumbnailDebugMode) { - ThumbnailData thumbnailData = new ThumbnailData(); - thumbnailData.thumbnail = Bitmap.createBitmap(mDummyThumbnailWidth, - mDummyThumbnailHeight, Bitmap.Config.ARGB_8888); - thumbnailData.thumbnail.eraseColor(0xff333333); - return thumbnailData; - } - - return getThumbnail(taskId, reduced); - } - - /** - * Returns a task thumbnail from the activity manager - */ - public @NonNull ThumbnailData getThumbnail(int taskId, boolean reducedResolution) { - if (mAm == null) { - return new ThumbnailData(); - } - - ActivityManager.TaskSnapshot snapshot = null; - try { - snapshot = mIam.getTaskSnapshot(taskId, reducedResolution); - } catch (RemoteException e) { - Log.w(TAG, "Failed to retrieve snapshot", e); - } - if (snapshot != null) { - return ThumbnailData.createFromTaskSnapshot(snapshot); - } else { - return new ThumbnailData(); - } - } - /** Set the task's windowing mode. */ public void setTaskWindowingMode(int taskId, int windowingMode) { if (mIam == null) return; @@ -531,124 +434,6 @@ public class SystemServicesProxy { }); } - /** - * Returns the activity info for a given component name. - * - * @param cn The component name of the activity. - * @param userId The userId of the user that this is for. - */ - public ActivityInfo getActivityInfo(ComponentName cn, int userId) { - if (mIpm == null) return null; - - try { - return mIpm.getActivityInfo(cn, PackageManager.GET_META_DATA, userId); - } catch (RemoteException e) { - e.printStackTrace(); - return null; - } - } - - /** - * Returns the activity info for a given component name. - * - * @param cn The component name of the activity. - */ - public ActivityInfo getActivityInfo(ComponentName cn) { - if (mPm == null) return null; - - try { - return mPm.getActivityInfo(cn, PackageManager.GET_META_DATA); - } catch (PackageManager.NameNotFoundException e) { - e.printStackTrace(); - return null; - } - } - - /** - * Returns the activity label, badging if necessary. - */ - public String getBadgedActivityLabel(ActivityInfo info, int userId) { - if (mPm == null) return null; - - return getBadgedLabel(info.loadLabel(mPm).toString(), userId); - } - - /** - * Returns the application label, badging if necessary. - */ - public String getBadgedApplicationLabel(ApplicationInfo appInfo, int userId) { - if (mPm == null) return null; - - return getBadgedLabel(appInfo.loadLabel(mPm).toString(), userId); - } - - /** - * Returns the content description for a given task, badging it if necessary. The content - * description joins the app and activity labels. - */ - public String getBadgedContentDescription(ActivityInfo info, int userId, - ActivityManager.TaskDescription td, Resources res) { - String activityLabel; - if (td != null && td.getLabel() != null) { - activityLabel = td.getLabel(); - } else { - activityLabel = info.loadLabel(mPm).toString(); - } - String applicationLabel = info.applicationInfo.loadLabel(mPm).toString(); - String badgedApplicationLabel = getBadgedLabel(applicationLabel, userId); - return applicationLabel.equals(activityLabel) ? badgedApplicationLabel - : res.getString(R.string.accessibility_recents_task_header, - badgedApplicationLabel, activityLabel); - } - - /** - * Returns the activity icon for the ActivityInfo for a user, badging if - * necessary. - */ - public Drawable getBadgedActivityIcon(ActivityInfo info, int userId) { - if (mPm == null) return null; - - return mDrawableFactory.getBadgedIcon(info, info.applicationInfo, userId); - } - - /** - * Returns the application icon for the ApplicationInfo for a user, badging if - * necessary. - */ - public Drawable getBadgedApplicationIcon(ApplicationInfo appInfo, int userId) { - if (mPm == null) return null; - - return mDrawableFactory.getBadgedIcon(appInfo, userId); - } - - /** - * Returns the task description icon, loading and badging it if it necessary. - */ - public Drawable getBadgedTaskDescriptionIcon(ActivityManager.TaskDescription taskDescription, - int userId, Resources res) { - Bitmap tdIcon = taskDescription.getInMemoryIcon(); - Drawable dIcon = null; - if (tdIcon != null) { - dIcon = new BitmapDrawable(res, tdIcon); - } else if (taskDescription.getIconResource() != 0) { - try { - dIcon = mContext.getDrawable(taskDescription.getIconResource()); - } catch (NotFoundException e) { - Log.e(TAG, "Could not find icon drawable from resource", e); - } - } else { - tdIcon = ActivityManager.TaskDescription.loadTaskDescriptionIcon( - taskDescription.getIconFilename(), userId); - if (tdIcon != null) { - dIcon = new BitmapDrawable(res, tdIcon); - } - } - if (dIcon != null) { - return getBadgedIcon(dIcon, userId); - } - return null; - } - public ActivityManager.TaskDescription getTaskDescription(int taskId) { try { return mIam.getTaskDescription(taskId); @@ -658,46 +443,6 @@ public class SystemServicesProxy { } /** - * Returns the given icon for a user, badging if necessary. - */ - private Drawable getBadgedIcon(Drawable icon, int userId) { - if (userId != UserHandle.myUserId()) { - icon = mPm.getUserBadgedIcon(icon, new UserHandle(userId)); - } - return icon; - } - - /** - * Returns a banner used on TV for the specified Activity. - */ - public Drawable getActivityBanner(ActivityInfo info) { - if (mPm == null) return null; - - Drawable banner = info.loadBanner(mPm); - return banner; - } - - /** - * Returns the given label for a user, badging if necessary. - */ - private String getBadgedLabel(String label, int userId) { - if (userId != UserHandle.myUserId()) { - label = mPm.getUserBadgedLabel(label, new UserHandle(userId)).toString(); - } - return label; - } - - /** - * Returns whether the provided {@param userId} is currently locked (and showing Keyguard). - */ - public boolean isDeviceLocked(int userId) { - if (mKgm == null) { - return false; - } - return mKgm.isDeviceLocked(userId); - } - - /** * Returns whether the provided {@param userId} represents the system user. */ public boolean isSystemUser(int userId) { diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java deleted file mode 100644 index 32e62cf29a4e..000000000000 --- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java +++ /dev/null @@ -1,856 +0,0 @@ -/* - * 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.model; - -import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT; -import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT; -import static android.view.WindowManager.DOCKED_BOTTOM; -import static android.view.WindowManager.DOCKED_INVALID; -import static android.view.WindowManager.DOCKED_LEFT; -import static android.view.WindowManager.DOCKED_RIGHT; -import static android.view.WindowManager.DOCKED_TOP; - -import android.animation.Animator; -import android.animation.AnimatorSet; -import android.animation.ObjectAnimator; -import android.animation.PropertyValuesHolder; -import android.annotation.IntDef; -import android.content.ComponentName; -import android.content.Context; -import android.content.res.Configuration; -import android.content.res.Resources; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.Point; -import android.graphics.Rect; -import android.graphics.RectF; -import android.graphics.drawable.ColorDrawable; -import android.util.ArrayMap; -import android.util.ArraySet; -import android.util.IntProperty; -import android.util.SparseArray; -import android.view.animation.Interpolator; - -import com.android.internal.policy.DockedDividerUtils; -import com.android.systemui.Interpolators; -import com.android.systemui.R; -import com.android.systemui.recents.Recents; -import com.android.systemui.recents.misc.SystemServicesProxy; -import com.android.systemui.recents.misc.Utilities; -import com.android.systemui.recents.views.AnimationProps; -import com.android.systemui.recents.views.DropTarget; -import com.android.systemui.recents.views.TaskStackLayoutAlgorithm; - -import java.io.PrintWriter; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.ArrayList; -import java.util.List; - - -/** - * An interface for a task filter to query whether a particular task should show in a stack. - */ -interface TaskFilter { - /** Returns whether the filter accepts the specified task */ - boolean acceptTask(SparseArray<Task> taskIdMap, Task t, int index); -} - -/** - * A list of filtered tasks. - */ -class FilteredTaskList { - - ArrayList<Task> mTasks = new ArrayList<>(); - ArrayList<Task> mFilteredTasks = new ArrayList<>(); - ArrayMap<Task.TaskKey, Integer> mFilteredTaskIndices = new ArrayMap<>(); - TaskFilter mFilter; - - /** Sets the task filter, saving the current touch state */ - boolean setFilter(TaskFilter filter) { - ArrayList<Task> prevFilteredTasks = new ArrayList<>(mFilteredTasks); - mFilter = filter; - updateFilteredTasks(); - if (!prevFilteredTasks.equals(mFilteredTasks)) { - return true; - } else { - return false; - } - } - - /** Removes the task filter and returns the previous touch state */ - void removeFilter() { - mFilter = null; - updateFilteredTasks(); - } - - /** Adds a new task to the task list */ - void add(Task t) { - mTasks.add(t); - updateFilteredTasks(); - } - - /** Sets the list of tasks */ - void set(List<Task> tasks) { - mTasks.clear(); - mTasks.addAll(tasks); - updateFilteredTasks(); - } - - /** Removes a task from the base list only if it is in the filtered list */ - boolean remove(Task t) { - if (mFilteredTasks.contains(t)) { - boolean removed = mTasks.remove(t); - updateFilteredTasks(); - return removed; - } - return false; - } - - /** Returns the index of this task in the list of filtered tasks */ - int indexOf(Task t) { - if (t != null && mFilteredTaskIndices.containsKey(t.key)) { - return mFilteredTaskIndices.get(t.key); - } - return -1; - } - - /** Returns the size of the list of filtered tasks */ - int size() { - return mFilteredTasks.size(); - } - - /** Returns whether the filtered list contains this task */ - boolean contains(Task t) { - return mFilteredTaskIndices.containsKey(t.key); - } - - /** Updates the list of filtered tasks whenever the base task list changes */ - private void updateFilteredTasks() { - mFilteredTasks.clear(); - if (mFilter != null) { - // Create a sparse array from task id to Task - SparseArray<Task> taskIdMap = new SparseArray<>(); - int taskCount = mTasks.size(); - for (int i = 0; i < taskCount; i++) { - Task t = mTasks.get(i); - taskIdMap.put(t.key.id, t); - } - - for (int i = 0; i < taskCount; i++) { - Task t = mTasks.get(i); - if (mFilter.acceptTask(taskIdMap, t, i)) { - mFilteredTasks.add(t); - } - } - } else { - mFilteredTasks.addAll(mTasks); - } - updateFilteredTaskIndices(); - } - - /** Updates the mapping of tasks to indices. */ - private void updateFilteredTaskIndices() { - int taskCount = mFilteredTasks.size(); - mFilteredTaskIndices.clear(); - for (int i = 0; i < taskCount; i++) { - Task t = mFilteredTasks.get(i); - mFilteredTaskIndices.put(t.key, i); - } - } - - /** Returns the list of filtered tasks */ - ArrayList<Task> getTasks() { - return mFilteredTasks; - } -} - -/** - * The task stack contains a list of multiple tasks. - */ -public class TaskStack { - - private static final String TAG = "TaskStack"; - - /** Task stack callbacks */ - public interface TaskStackCallbacks { - /** - * Notifies when a new task has been added to the stack. - */ - void onStackTaskAdded(TaskStack stack, Task newTask); - - /** - * Notifies when a task has been removed from the stack. - */ - void onStackTaskRemoved(TaskStack stack, Task removedTask, Task newFrontMostTask, - AnimationProps animation, boolean fromDockGesture, - boolean dismissRecentsIfAllRemoved); - - /** - * Notifies when all tasks have been removed from the stack. - */ - void onStackTasksRemoved(TaskStack stack); - - /** - * Notifies when tasks in the stack have been updated. - */ - void onStackTasksUpdated(TaskStack stack); - } - - /** - * The various possible dock states when dragging and dropping a task. - */ - public static class DockState implements DropTarget { - - public static final int DOCK_AREA_BG_COLOR = 0xFFffffff; - public static final int DOCK_AREA_GRID_BG_COLOR = 0xFF000000; - - // The rotation to apply to the hint text - @Retention(RetentionPolicy.SOURCE) - @IntDef({HORIZONTAL, VERTICAL}) - public @interface TextOrientation {} - private static final int HORIZONTAL = 0; - private static final int VERTICAL = 1; - - private static final int DOCK_AREA_ALPHA = 80; - public static final DockState NONE = new DockState(DOCKED_INVALID, -1, 80, 255, HORIZONTAL, - null, null, null); - public static final DockState LEFT = new DockState(DOCKED_LEFT, - DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, DOCK_AREA_ALPHA, 0, VERTICAL, - new RectF(0, 0, 0.125f, 1), new RectF(0, 0, 0.125f, 1), - new RectF(0, 0, 0.5f, 1)); - public static final DockState TOP = new DockState(DOCKED_TOP, - DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, DOCK_AREA_ALPHA, 0, HORIZONTAL, - new RectF(0, 0, 1, 0.125f), new RectF(0, 0, 1, 0.125f), - new RectF(0, 0, 1, 0.5f)); - public static final DockState RIGHT = new DockState(DOCKED_RIGHT, - DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT, DOCK_AREA_ALPHA, 0, VERTICAL, - new RectF(0.875f, 0, 1, 1), new RectF(0.875f, 0, 1, 1), - new RectF(0.5f, 0, 1, 1)); - public static final DockState BOTTOM = new DockState(DOCKED_BOTTOM, - DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT, DOCK_AREA_ALPHA, 0, HORIZONTAL, - new RectF(0, 0.875f, 1, 1), new RectF(0, 0.875f, 1, 1), - new RectF(0, 0.5f, 1, 1)); - - @Override - public boolean acceptsDrop(int x, int y, int width, int height, Rect insets, - boolean isCurrentTarget) { - if (isCurrentTarget) { - getMappedRect(expandedTouchDockArea, width, height, mTmpRect); - return mTmpRect.contains(x, y); - } else { - getMappedRect(touchArea, width, height, mTmpRect); - updateBoundsWithSystemInsets(mTmpRect, insets); - return mTmpRect.contains(x, y); - } - } - - // Represents the view state of this dock state - public static class ViewState { - private static final IntProperty<ViewState> HINT_ALPHA = - new IntProperty<ViewState>("drawableAlpha") { - @Override - public void setValue(ViewState object, int alpha) { - object.mHintTextAlpha = alpha; - object.dockAreaOverlay.invalidateSelf(); - } - - @Override - public Integer get(ViewState object) { - return object.mHintTextAlpha; - } - }; - - public final int dockAreaAlpha; - public final ColorDrawable dockAreaOverlay; - public final int hintTextAlpha; - public final int hintTextOrientation; - - private final int mHintTextResId; - private String mHintText; - private Paint mHintTextPaint; - private Point mHintTextBounds = new Point(); - private int mHintTextAlpha = 255; - private AnimatorSet mDockAreaOverlayAnimator; - private Rect mTmpRect = new Rect(); - - private ViewState(int areaAlpha, int hintAlpha, @TextOrientation int hintOrientation, - int hintTextResId) { - dockAreaAlpha = areaAlpha; - dockAreaOverlay = new ColorDrawable(Recents.getConfiguration().isGridEnabled - ? DOCK_AREA_GRID_BG_COLOR : DOCK_AREA_BG_COLOR); - dockAreaOverlay.setAlpha(0); - hintTextAlpha = hintAlpha; - hintTextOrientation = hintOrientation; - mHintTextResId = hintTextResId; - mHintTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - mHintTextPaint.setColor(Color.WHITE); - } - - /** - * Updates the view state with the given context. - */ - public void update(Context context) { - Resources res = context.getResources(); - mHintText = context.getString(mHintTextResId); - mHintTextPaint.setTextSize(res.getDimensionPixelSize( - R.dimen.recents_drag_hint_text_size)); - mHintTextPaint.getTextBounds(mHintText, 0, mHintText.length(), mTmpRect); - mHintTextBounds.set((int) mHintTextPaint.measureText(mHintText), mTmpRect.height()); - } - - /** - * Draws the current view state. - */ - public void draw(Canvas canvas) { - // Draw the overlay background - if (dockAreaOverlay.getAlpha() > 0) { - dockAreaOverlay.draw(canvas); - } - - // Draw the hint text - if (mHintTextAlpha > 0) { - Rect bounds = dockAreaOverlay.getBounds(); - int x = bounds.left + (bounds.width() - mHintTextBounds.x) / 2; - int y = bounds.top + (bounds.height() + mHintTextBounds.y) / 2; - mHintTextPaint.setAlpha(mHintTextAlpha); - if (hintTextOrientation == VERTICAL) { - canvas.save(); - canvas.rotate(-90f, bounds.centerX(), bounds.centerY()); - } - canvas.drawText(mHintText, x, y, mHintTextPaint); - if (hintTextOrientation == VERTICAL) { - canvas.restore(); - } - } - } - - /** - * Creates a new bounds and alpha animation. - */ - public void startAnimation(Rect bounds, int areaAlpha, int hintAlpha, int duration, - Interpolator interpolator, boolean animateAlpha, boolean animateBounds) { - if (mDockAreaOverlayAnimator != null) { - mDockAreaOverlayAnimator.cancel(); - } - - ObjectAnimator anim; - ArrayList<Animator> animators = new ArrayList<>(); - if (dockAreaOverlay.getAlpha() != areaAlpha) { - if (animateAlpha) { - anim = ObjectAnimator.ofInt(dockAreaOverlay, - Utilities.DRAWABLE_ALPHA, dockAreaOverlay.getAlpha(), areaAlpha); - anim.setDuration(duration); - anim.setInterpolator(interpolator); - animators.add(anim); - } else { - dockAreaOverlay.setAlpha(areaAlpha); - } - } - if (mHintTextAlpha != hintAlpha) { - if (animateAlpha) { - anim = ObjectAnimator.ofInt(this, HINT_ALPHA, mHintTextAlpha, - hintAlpha); - anim.setDuration(150); - anim.setInterpolator(hintAlpha > mHintTextAlpha - ? Interpolators.ALPHA_IN - : Interpolators.ALPHA_OUT); - animators.add(anim); - } else { - mHintTextAlpha = hintAlpha; - dockAreaOverlay.invalidateSelf(); - } - } - if (bounds != null && !dockAreaOverlay.getBounds().equals(bounds)) { - if (animateBounds) { - PropertyValuesHolder prop = PropertyValuesHolder.ofObject( - Utilities.DRAWABLE_RECT, Utilities.RECT_EVALUATOR, - new Rect(dockAreaOverlay.getBounds()), bounds); - anim = ObjectAnimator.ofPropertyValuesHolder(dockAreaOverlay, prop); - anim.setDuration(duration); - anim.setInterpolator(interpolator); - animators.add(anim); - } else { - dockAreaOverlay.setBounds(bounds); - } - } - if (!animators.isEmpty()) { - mDockAreaOverlayAnimator = new AnimatorSet(); - mDockAreaOverlayAnimator.playTogether(animators); - mDockAreaOverlayAnimator.start(); - } - } - } - - public final int dockSide; - public final int createMode; - public final ViewState viewState; - private final RectF touchArea; - private final RectF dockArea; - private final RectF expandedTouchDockArea; - private static final Rect mTmpRect = new Rect(); - - /** - * @param createMode used to pass to ActivityManager to dock the task - * @param touchArea the area in which touch will initiate this dock state - * @param dockArea the visible dock area - * @param expandedTouchDockArea the area in which touch will continue to dock after entering - * the initial touch area. This is also the new dock area to - * draw. - */ - DockState(int dockSide, int createMode, int dockAreaAlpha, int hintTextAlpha, - @TextOrientation int hintTextOrientation, RectF touchArea, RectF dockArea, - RectF expandedTouchDockArea) { - this.dockSide = dockSide; - this.createMode = createMode; - this.viewState = new ViewState(dockAreaAlpha, hintTextAlpha, hintTextOrientation, - R.string.recents_drag_hint_message); - this.dockArea = dockArea; - this.touchArea = touchArea; - this.expandedTouchDockArea = expandedTouchDockArea; - } - - /** - * Updates the dock state with the given context. - */ - public void update(Context context) { - viewState.update(context); - } - - /** - * Returns the docked task bounds with the given {@param width} and {@param height}. - */ - public Rect getPreDockedBounds(int width, int height, Rect insets) { - getMappedRect(dockArea, width, height, mTmpRect); - return updateBoundsWithSystemInsets(mTmpRect, insets); - } - - /** - * Returns the expanded docked task bounds with the given {@param width} and - * {@param height}. - */ - public Rect getDockedBounds(int width, int height, int dividerSize, Rect insets, - Resources res) { - // Calculate the docked task bounds - boolean isHorizontalDivision = - res.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT; - int position = DockedDividerUtils.calculateMiddlePosition(isHorizontalDivision, - insets, width, height, dividerSize); - Rect newWindowBounds = new Rect(); - DockedDividerUtils.calculateBoundsForPosition(position, dockSide, newWindowBounds, - width, height, dividerSize); - return newWindowBounds; - } - - /** - * Returns the task stack bounds with the given {@param width} and - * {@param height}. - */ - public Rect getDockedTaskStackBounds(Rect displayRect, int width, int height, - int dividerSize, Rect insets, TaskStackLayoutAlgorithm layoutAlgorithm, - Resources res, Rect windowRectOut) { - // Calculate the inverse docked task bounds - boolean isHorizontalDivision = - res.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT; - int position = DockedDividerUtils.calculateMiddlePosition(isHorizontalDivision, - insets, width, height, dividerSize); - DockedDividerUtils.calculateBoundsForPosition(position, - DockedDividerUtils.invertDockSide(dockSide), windowRectOut, width, height, - dividerSize); - - // Calculate the task stack bounds from the new window bounds - Rect taskStackBounds = new Rect(); - // If the task stack bounds is specifically under the dock area, then ignore the top - // inset - int top = dockArea.bottom < 1f - ? 0 - : insets.top; - // For now, ignore the left insets since we always dock on the left and show Recents - // on the right - layoutAlgorithm.getTaskStackBounds(displayRect, windowRectOut, top, 0, insets.right, - taskStackBounds); - return taskStackBounds; - } - - /** - * Returns the expanded bounds in certain dock sides such that the bounds account for the - * system insets (namely the vertical nav bar). This call modifies and returns the given - * {@param bounds}. - */ - private Rect updateBoundsWithSystemInsets(Rect bounds, Rect insets) { - if (dockSide == DOCKED_LEFT) { - bounds.right += insets.left; - } else if (dockSide == DOCKED_RIGHT) { - bounds.left -= insets.right; - } - return bounds; - } - - /** - * Returns the mapped rect to the given dimensions. - */ - private void getMappedRect(RectF bounds, int width, int height, Rect out) { - out.set((int) (bounds.left * width), (int) (bounds.top * height), - (int) (bounds.right * width), (int) (bounds.bottom * height)); - } - } - - ArrayList<Task> mRawTaskList = new ArrayList<>(); - FilteredTaskList mStackTaskList = new FilteredTaskList(); - TaskStackCallbacks mCb; - - public TaskStack() { - // Ensure that we only show stack tasks - mStackTaskList.setFilter(new TaskFilter() { - @Override - public boolean acceptTask(SparseArray<Task> taskIdMap, Task t, int index) { - return t.isStackTask; - } - }); - } - - /** Sets the callbacks for this task stack. */ - public void setCallbacks(TaskStackCallbacks cb) { - mCb = cb; - } - - /** - * Removes a task from the stack, with an additional {@param animation} hint to the callbacks on - * how they should update themselves. - */ - public void removeTask(Task t, AnimationProps animation, boolean fromDockGesture) { - removeTask(t, animation, fromDockGesture, true /* dismissRecentsIfAllRemoved */); - } - - /** - * Removes a task from the stack, with an additional {@param animation} hint to the callbacks on - * how they should update themselves. - */ - public void removeTask(Task t, AnimationProps animation, boolean fromDockGesture, - boolean dismissRecentsIfAllRemoved) { - if (mStackTaskList.contains(t)) { - mStackTaskList.remove(t); - Task newFrontMostTask = getStackFrontMostTask(); - if (mCb != null) { - // Notify that a task has been removed - mCb.onStackTaskRemoved(this, t, newFrontMostTask, animation, - fromDockGesture, dismissRecentsIfAllRemoved); - } - } - mRawTaskList.remove(t); - } - - /** - * Removes all tasks from the stack. - */ - public void removeAllTasks(boolean notifyStackChanges) { - ArrayList<Task> tasks = mStackTaskList.getTasks(); - for (int i = tasks.size() - 1; i >= 0; i--) { - Task t = tasks.get(i); - mStackTaskList.remove(t); - mRawTaskList.remove(t); - } - if (mCb != null && notifyStackChanges) { - // Notify that all tasks have been removed - mCb.onStackTasksRemoved(this); - } - } - - - /** - * @see #setTasks(List, boolean) - */ - public void setTasks(TaskStack stack, boolean notifyStackChanges) { - setTasks(stack.mRawTaskList, notifyStackChanges); - } - - /** - * Sets a few tasks in one go, without calling any callbacks. - * - * @param tasks the new set of tasks to replace the current set. - * @param notifyStackChanges whether or not to callback on specific changes to the list of tasks. - */ - public void setTasks(List<Task> tasks, boolean notifyStackChanges) { - // Compute a has set for each of the tasks - ArrayMap<Task.TaskKey, Task> currentTasksMap = createTaskKeyMapFromList(mRawTaskList); - ArrayMap<Task.TaskKey, Task> newTasksMap = createTaskKeyMapFromList(tasks); - ArrayList<Task> addedTasks = new ArrayList<>(); - ArrayList<Task> removedTasks = new ArrayList<>(); - ArrayList<Task> allTasks = new ArrayList<>(); - - // Disable notifications if there are no callbacks - if (mCb == null) { - notifyStackChanges = false; - } - - // Remove any tasks that no longer exist - int taskCount = mRawTaskList.size(); - for (int i = taskCount - 1; i >= 0; i--) { - Task task = mRawTaskList.get(i); - if (!newTasksMap.containsKey(task.key)) { - if (notifyStackChanges) { - removedTasks.add(task); - } - } - } - - // Add any new tasks - taskCount = tasks.size(); - for (int i = 0; i < taskCount; i++) { - Task newTask = tasks.get(i); - Task currentTask = currentTasksMap.get(newTask.key); - if (currentTask == null && notifyStackChanges) { - addedTasks.add(newTask); - } else if (currentTask != null) { - // The current task has bound callbacks, so just copy the data from the new task - // state and add it back into the list - currentTask.copyFrom(newTask); - newTask = currentTask; - } - allTasks.add(newTask); - } - - // Sort all the tasks to ensure they are ordered correctly - for (int i = allTasks.size() - 1; i >= 0; i--) { - allTasks.get(i).temporarySortIndexInStack = i; - } - - mStackTaskList.set(allTasks); - mRawTaskList = allTasks; - - // Only callback for the removed tasks after the stack has updated - int removedTaskCount = removedTasks.size(); - Task newFrontMostTask = getStackFrontMostTask(); - for (int i = 0; i < removedTaskCount; i++) { - mCb.onStackTaskRemoved(this, removedTasks.get(i), newFrontMostTask, - AnimationProps.IMMEDIATE, false /* fromDockGesture */, - true /* dismissRecentsIfAllRemoved */); - } - - // Only callback for the newly added tasks after this stack has been updated - int addedTaskCount = addedTasks.size(); - for (int i = 0; i < addedTaskCount; i++) { - mCb.onStackTaskAdded(this, addedTasks.get(i)); - } - - // Notify that the task stack has been updated - if (notifyStackChanges) { - mCb.onStackTasksUpdated(this); - } - } - - /** - * Gets the front-most task in the stack. - */ - public Task getStackFrontMostTask() { - ArrayList<Task> stackTasks = mStackTaskList.getTasks(); - if (stackTasks.isEmpty()) { - return null; - } - return stackTasks.get(stackTasks.size() - 1); - } - - /** Gets the task keys */ - public ArrayList<Task.TaskKey> getTaskKeys() { - ArrayList<Task.TaskKey> taskKeys = new ArrayList<>(); - ArrayList<Task> tasks = computeAllTasksList(); - int taskCount = tasks.size(); - for (int i = 0; i < taskCount; i++) { - Task task = tasks.get(i); - taskKeys.add(task.key); - } - return taskKeys; - } - - /** - * Returns the set of "active" (non-historical) tasks in the stack that have been used recently. - */ - public ArrayList<Task> getStackTasks() { - return mStackTaskList.getTasks(); - } - - /** - * Computes a set of all the active and historical tasks. - */ - public ArrayList<Task> computeAllTasksList() { - ArrayList<Task> tasks = new ArrayList<>(); - tasks.addAll(mStackTaskList.getTasks()); - return tasks; - } - - /** - * Returns the number of stacktasks. - */ - public int getTaskCount() { - return mStackTaskList.size(); - } - - /** - * Returns the number of stack tasks. - */ - public int getStackTaskCount() { - return mStackTaskList.size(); - } - - /** - * Returns the task in stack tasks which is the launch target. - */ - public Task getLaunchTarget() { - ArrayList<Task> tasks = mStackTaskList.getTasks(); - int taskCount = tasks.size(); - for (int i = 0; i < taskCount; i++) { - Task task = tasks.get(i); - if (task.isLaunchTarget) { - return task; - } - } - return null; - } - - /** - * Returns whether the next launch target should actually be the PiP task. - */ - public boolean isNextLaunchTargetPip(long lastPipTime) { - Task launchTarget = getLaunchTarget(); - Task nextLaunchTarget = getNextLaunchTargetRaw(); - if (nextLaunchTarget != null && lastPipTime > 0) { - // If the PiP time is more recent than the next launch target, then launch the PiP task - return lastPipTime > nextLaunchTarget.key.lastActiveTime; - } else if (launchTarget != null && lastPipTime > 0 && getTaskCount() == 1) { - // Otherwise, if there is no next launch target, but there is a PiP, then launch - // the PiP task - return true; - } - return false; - } - - /** - * Returns the task in stack tasks which should be launched next if Recents are toggled - * again, or null if there is no task to be launched. Callers should check - * {@link #isNextLaunchTargetPip(long)} before fetching the next raw launch target from the - * stack. - */ - public Task getNextLaunchTarget() { - Task nextLaunchTarget = getNextLaunchTargetRaw(); - if (nextLaunchTarget != null) { - return nextLaunchTarget; - } - return getStackTasks().get(getTaskCount() - 1); - } - - private Task getNextLaunchTargetRaw() { - int taskCount = getTaskCount(); - if (taskCount == 0) { - return null; - } - int launchTaskIndex = indexOfStackTask(getLaunchTarget()); - if (launchTaskIndex != -1 && launchTaskIndex > 0) { - return getStackTasks().get(launchTaskIndex - 1); - } - return null; - } - - /** Returns the index of this task in this current task stack */ - public int indexOfStackTask(Task t) { - return mStackTaskList.indexOf(t); - } - - /** Finds the task with the specified task id. */ - public Task findTaskWithId(int taskId) { - ArrayList<Task> tasks = computeAllTasksList(); - int taskCount = tasks.size(); - for (int i = 0; i < taskCount; i++) { - Task task = tasks.get(i); - if (task.key.id == taskId) { - return task; - } - } - return null; - } - - /** - * Computes the components of tasks in this stack that have been removed as a result of a change - * in the specified package. - */ - public ArraySet<ComponentName> computeComponentsRemoved(String packageName, int userId) { - // Identify all the tasks that should be removed as a result of the package being removed. - // Using a set to ensure that we callback once per unique component. - SystemServicesProxy ssp = Recents.getSystemServices(); - ArraySet<ComponentName> existingComponents = new ArraySet<>(); - ArraySet<ComponentName> removedComponents = new ArraySet<>(); - ArrayList<Task.TaskKey> taskKeys = getTaskKeys(); - int taskKeyCount = taskKeys.size(); - for (int i = 0; i < taskKeyCount; i++) { - Task.TaskKey t = taskKeys.get(i); - - // Skip if this doesn't apply to the current user - if (t.userId != userId) continue; - - ComponentName cn = t.getComponent(); - if (cn.getPackageName().equals(packageName)) { - if (existingComponents.contains(cn)) { - // If we know that the component still exists in the package, then skip - continue; - } - if (ssp.getActivityInfo(cn, userId) != null) { - existingComponents.add(cn); - } else { - removedComponents.add(cn); - } - } - } - return removedComponents; - } - - @Override - public String toString() { - String str = "Stack Tasks (" + mStackTaskList.size() + "):\n"; - ArrayList<Task> tasks = mStackTaskList.getTasks(); - int taskCount = tasks.size(); - for (int i = 0; i < taskCount; i++) { - str += " " + tasks.get(i).toString() + "\n"; - } - return str; - } - - /** - * Given a list of tasks, returns a map of each task's key to the task. - */ - private ArrayMap<Task.TaskKey, Task> createTaskKeyMapFromList(List<Task> tasks) { - ArrayMap<Task.TaskKey, Task> map = new ArrayMap<>(tasks.size()); - int taskCount = tasks.size(); - for (int i = 0; i < taskCount; i++) { - Task task = tasks.get(i); - map.put(task.key, task); - } - return map; - } - - public void dump(String prefix, PrintWriter writer) { - String innerPrefix = prefix + " "; - - writer.print(prefix); writer.print(TAG); - writer.print(" numStackTasks="); writer.print(mStackTaskList.size()); - writer.println(); - ArrayList<Task> tasks = mStackTaskList.getTasks(); - int taskCount = tasks.size(); - for (int i = 0; i < taskCount; i++) { - tasks.get(i).dump(innerPrefix, writer); - } - } -} diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java b/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java index 7998ecb4290a..b598ec6fc31f 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java @@ -22,7 +22,7 @@ import android.view.View; import android.view.ViewDebug; import android.view.ViewOutlineProvider; -import com.android.systemui.recents.misc.Utilities; +import com.android.systemui.shared.recents.utilities.Utilities; /* An outline provider that has a clip and outline that can be animated. */ public class AnimateableViewBounds extends ViewOutlineProvider { diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/DockState.java b/packages/SystemUI/src/com/android/systemui/recents/views/DockState.java new file mode 100644 index 000000000000..59f28680a6e0 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/recents/views/DockState.java @@ -0,0 +1,351 @@ +/* + * Copyright (C) 2017 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.views; + +import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT; +import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT; +import static android.view.WindowManager.DOCKED_BOTTOM; +import static android.view.WindowManager.DOCKED_INVALID; +import static android.view.WindowManager.DOCKED_LEFT; +import static android.view.WindowManager.DOCKED_RIGHT; +import static android.view.WindowManager.DOCKED_TOP; + +import android.animation.Animator; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; +import android.animation.PropertyValuesHolder; +import android.annotation.IntDef; +import android.content.Context; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Point; +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.drawable.ColorDrawable; +import android.util.IntProperty; +import android.view.animation.Interpolator; + +import com.android.internal.policy.DockedDividerUtils; +import com.android.systemui.Interpolators; +import com.android.systemui.R; +import com.android.systemui.recents.Recents; +import com.android.systemui.shared.recents.utilities.Utilities; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; + +/** + * The various possible dock states when dragging and dropping a task. + */ +public class DockState implements DropTarget { + + public static final int DOCK_AREA_BG_COLOR = 0xFFffffff; + public static final int DOCK_AREA_GRID_BG_COLOR = 0xFF000000; + + // The rotation to apply to the hint text + @Retention(RetentionPolicy.SOURCE) + @IntDef({HORIZONTAL, VERTICAL}) + public @interface TextOrientation {} + private static final int HORIZONTAL = 0; + private static final int VERTICAL = 1; + + private static final int DOCK_AREA_ALPHA = 80; + public static final DockState NONE = new DockState(DOCKED_INVALID, -1, 80, 255, HORIZONTAL, + null, null, null); + public static final DockState LEFT = new DockState(DOCKED_LEFT, + DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, DOCK_AREA_ALPHA, 0, VERTICAL, + new RectF(0, 0, 0.125f, 1), new RectF(0, 0, 0.125f, 1), + new RectF(0, 0, 0.5f, 1)); + public static final DockState TOP = new DockState(DOCKED_TOP, + DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, DOCK_AREA_ALPHA, 0, HORIZONTAL, + new RectF(0, 0, 1, 0.125f), new RectF(0, 0, 1, 0.125f), + new RectF(0, 0, 1, 0.5f)); + public static final DockState RIGHT = new DockState(DOCKED_RIGHT, + DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT, DOCK_AREA_ALPHA, 0, VERTICAL, + new RectF(0.875f, 0, 1, 1), new RectF(0.875f, 0, 1, 1), + new RectF(0.5f, 0, 1, 1)); + public static final DockState BOTTOM = new DockState(DOCKED_BOTTOM, + DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT, DOCK_AREA_ALPHA, 0, HORIZONTAL, + new RectF(0, 0.875f, 1, 1), new RectF(0, 0.875f, 1, 1), + new RectF(0, 0.5f, 1, 1)); + + @Override + public boolean acceptsDrop(int x, int y, int width, int height, Rect insets, + boolean isCurrentTarget) { + if (isCurrentTarget) { + getMappedRect(expandedTouchDockArea, width, height, mTmpRect); + return mTmpRect.contains(x, y); + } else { + getMappedRect(touchArea, width, height, mTmpRect); + updateBoundsWithSystemInsets(mTmpRect, insets); + return mTmpRect.contains(x, y); + } + } + + // Represents the view state of this dock state + public static class ViewState { + private static final IntProperty<ViewState> HINT_ALPHA = + new IntProperty<ViewState>("drawableAlpha") { + @Override + public void setValue(ViewState object, int alpha) { + object.mHintTextAlpha = alpha; + object.dockAreaOverlay.invalidateSelf(); + } + + @Override + public Integer get(ViewState object) { + return object.mHintTextAlpha; + } + }; + + public final int dockAreaAlpha; + public final ColorDrawable dockAreaOverlay; + public final int hintTextAlpha; + public final int hintTextOrientation; + + private final int mHintTextResId; + private String mHintText; + private Paint mHintTextPaint; + private Point mHintTextBounds = new Point(); + private int mHintTextAlpha = 255; + private AnimatorSet mDockAreaOverlayAnimator; + private Rect mTmpRect = new Rect(); + + private ViewState(int areaAlpha, int hintAlpha, @TextOrientation int hintOrientation, + int hintTextResId) { + dockAreaAlpha = areaAlpha; + dockAreaOverlay = new ColorDrawable(Recents.getConfiguration().isGridEnabled + ? DOCK_AREA_GRID_BG_COLOR : DOCK_AREA_BG_COLOR); + dockAreaOverlay.setAlpha(0); + hintTextAlpha = hintAlpha; + hintTextOrientation = hintOrientation; + mHintTextResId = hintTextResId; + mHintTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mHintTextPaint.setColor(Color.WHITE); + } + + /** + * Updates the view state with the given context. + */ + public void update(Context context) { + Resources res = context.getResources(); + mHintText = context.getString(mHintTextResId); + mHintTextPaint.setTextSize(res.getDimensionPixelSize( + R.dimen.recents_drag_hint_text_size)); + mHintTextPaint.getTextBounds(mHintText, 0, mHintText.length(), mTmpRect); + mHintTextBounds.set((int) mHintTextPaint.measureText(mHintText), mTmpRect.height()); + } + + /** + * Draws the current view state. + */ + public void draw(Canvas canvas) { + // Draw the overlay background + if (dockAreaOverlay.getAlpha() > 0) { + dockAreaOverlay.draw(canvas); + } + + // Draw the hint text + if (mHintTextAlpha > 0) { + Rect bounds = dockAreaOverlay.getBounds(); + int x = bounds.left + (bounds.width() - mHintTextBounds.x) / 2; + int y = bounds.top + (bounds.height() + mHintTextBounds.y) / 2; + mHintTextPaint.setAlpha(mHintTextAlpha); + if (hintTextOrientation == VERTICAL) { + canvas.save(); + canvas.rotate(-90f, bounds.centerX(), bounds.centerY()); + } + canvas.drawText(mHintText, x, y, mHintTextPaint); + if (hintTextOrientation == VERTICAL) { + canvas.restore(); + } + } + } + + /** + * Creates a new bounds and alpha animation. + */ + public void startAnimation(Rect bounds, int areaAlpha, int hintAlpha, int duration, + Interpolator interpolator, boolean animateAlpha, boolean animateBounds) { + if (mDockAreaOverlayAnimator != null) { + mDockAreaOverlayAnimator.cancel(); + } + + ObjectAnimator anim; + ArrayList<Animator> animators = new ArrayList<>(); + if (dockAreaOverlay.getAlpha() != areaAlpha) { + if (animateAlpha) { + anim = ObjectAnimator.ofInt(dockAreaOverlay, + Utilities.DRAWABLE_ALPHA, dockAreaOverlay.getAlpha(), areaAlpha); + anim.setDuration(duration); + anim.setInterpolator(interpolator); + animators.add(anim); + } else { + dockAreaOverlay.setAlpha(areaAlpha); + } + } + if (mHintTextAlpha != hintAlpha) { + if (animateAlpha) { + anim = ObjectAnimator.ofInt(this, HINT_ALPHA, mHintTextAlpha, + hintAlpha); + anim.setDuration(150); + anim.setInterpolator(hintAlpha > mHintTextAlpha + ? Interpolators.ALPHA_IN + : Interpolators.ALPHA_OUT); + animators.add(anim); + } else { + mHintTextAlpha = hintAlpha; + dockAreaOverlay.invalidateSelf(); + } + } + if (bounds != null && !dockAreaOverlay.getBounds().equals(bounds)) { + if (animateBounds) { + PropertyValuesHolder prop = PropertyValuesHolder.ofObject( + Utilities.DRAWABLE_RECT, Utilities.RECT_EVALUATOR, + new Rect(dockAreaOverlay.getBounds()), bounds); + anim = ObjectAnimator.ofPropertyValuesHolder(dockAreaOverlay, prop); + anim.setDuration(duration); + anim.setInterpolator(interpolator); + animators.add(anim); + } else { + dockAreaOverlay.setBounds(bounds); + } + } + if (!animators.isEmpty()) { + mDockAreaOverlayAnimator = new AnimatorSet(); + mDockAreaOverlayAnimator.playTogether(animators); + mDockAreaOverlayAnimator.start(); + } + } + } + + public final int dockSide; + public final int createMode; + public final ViewState viewState; + private final RectF touchArea; + private final RectF dockArea; + private final RectF expandedTouchDockArea; + private static final Rect mTmpRect = new Rect(); + + /** + * @param createMode used to pass to ActivityManager to dock the task + * @param touchArea the area in which touch will initiate this dock state + * @param dockArea the visible dock area + * @param expandedTouchDockArea the area in which touch will continue to dock after entering + * the initial touch area. This is also the new dock area to + * draw. + */ + DockState(int dockSide, int createMode, int dockAreaAlpha, int hintTextAlpha, + @TextOrientation int hintTextOrientation, RectF touchArea, RectF dockArea, + RectF expandedTouchDockArea) { + this.dockSide = dockSide; + this.createMode = createMode; + this.viewState = new ViewState(dockAreaAlpha, hintTextAlpha, hintTextOrientation, + R.string.recents_drag_hint_message); + this.dockArea = dockArea; + this.touchArea = touchArea; + this.expandedTouchDockArea = expandedTouchDockArea; + } + + /** + * Updates the dock state with the given context. + */ + public void update(Context context) { + viewState.update(context); + } + + /** + * Returns the docked task bounds with the given {@param width} and {@param height}. + */ + public Rect getPreDockedBounds(int width, int height, Rect insets) { + getMappedRect(dockArea, width, height, mTmpRect); + return updateBoundsWithSystemInsets(mTmpRect, insets); + } + + /** + * Returns the expanded docked task bounds with the given {@param width} and + * {@param height}. + */ + public Rect getDockedBounds(int width, int height, int dividerSize, Rect insets, + Resources res) { + // Calculate the docked task bounds + boolean isHorizontalDivision = + res.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT; + int position = DockedDividerUtils.calculateMiddlePosition(isHorizontalDivision, + insets, width, height, dividerSize); + Rect newWindowBounds = new Rect(); + DockedDividerUtils.calculateBoundsForPosition(position, dockSide, newWindowBounds, + width, height, dividerSize); + return newWindowBounds; + } + + /** + * Returns the task stack bounds with the given {@param width} and + * {@param height}. + */ + public Rect getDockedTaskStackBounds(Rect displayRect, int width, int height, + int dividerSize, Rect insets, TaskStackLayoutAlgorithm layoutAlgorithm, + Resources res, Rect windowRectOut) { + // Calculate the inverse docked task bounds + boolean isHorizontalDivision = + res.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT; + int position = DockedDividerUtils.calculateMiddlePosition(isHorizontalDivision, + insets, width, height, dividerSize); + DockedDividerUtils.calculateBoundsForPosition(position, + DockedDividerUtils.invertDockSide(dockSide), windowRectOut, width, height, + dividerSize); + + // Calculate the task stack bounds from the new window bounds + Rect taskStackBounds = new Rect(); + // If the task stack bounds is specifically under the dock area, then ignore the top + // inset + int top = dockArea.bottom < 1f + ? 0 + : insets.top; + // For now, ignore the left insets since we always dock on the left and show Recents + // on the right + layoutAlgorithm.getTaskStackBounds(displayRect, windowRectOut, top, 0, insets.right, + taskStackBounds); + return taskStackBounds; + } + + /** + * Returns the expanded bounds in certain dock sides such that the bounds account for the + * system insets (namely the vertical nav bar). This call modifies and returns the given + * {@param bounds}. + */ + private Rect updateBoundsWithSystemInsets(Rect bounds, Rect insets) { + if (dockSide == DOCKED_LEFT) { + bounds.right += insets.left; + } else if (dockSide == DOCKED_RIGHT) { + bounds.left -= insets.right; + } + return bounds; + } + + /** + * Returns the mapped rect to the given dimensions. + */ + private void getMappedRect(RectF bounds, int width, int height, Rect out) { + out.set((int) (bounds.left * width), (int) (bounds.top * height), + (int) (bounds.right * width), (int) (bounds.bottom * height)); + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java index baa5e6273e5e..25c2fc97eda4 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java @@ -30,8 +30,6 @@ import android.app.ActivityOptions; import android.app.ActivityOptions.OnAnimationStartedListener; import android.content.Context; import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Color; import android.graphics.GraphicBuffer; import android.graphics.Rect; import android.os.Bundle; @@ -58,8 +56,8 @@ import com.android.systemui.recents.events.activity.LaunchTaskSucceededEvent; import com.android.systemui.recents.events.component.ScreenPinningRequestEvent; import com.android.systemui.recents.events.component.SetWaitingForTransitionStartEvent; import com.android.systemui.recents.misc.SystemServicesProxy; -import com.android.systemui.recents.model.Task; -import com.android.systemui.recents.model.TaskStack; +import com.android.systemui.shared.recents.model.Task; +import com.android.systemui.shared.recents.model.TaskStack; import com.android.systemui.statusbar.phone.StatusBar; import java.util.ArrayList; 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 e1b22b4452fd..5f12a04b5e4d 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java @@ -53,7 +53,6 @@ import com.android.systemui.recents.Recents; import com.android.systemui.recents.RecentsActivity; import com.android.systemui.recents.RecentsActivityLaunchState; import com.android.systemui.recents.RecentsConfiguration; -import com.android.systemui.recents.RecentsDebugFlags; import com.android.systemui.recents.events.EventBus; import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted; import com.android.systemui.recents.events.activity.DockedFirstAnimationFrameEvent; @@ -74,9 +73,9 @@ import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent; import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent; import com.android.systemui.recents.misc.ReferenceCountedTrigger; 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 com.android.systemui.shared.recents.utilities.Utilities; +import com.android.systemui.shared.recents.model.Task; +import com.android.systemui.shared.recents.model.TaskStack; import com.android.systemui.recents.views.RecentsTransitionHelper.AnimationSpecComposer; import com.android.systemui.recents.views.RecentsTransitionHelper.AppTransitionAnimationSpecsFuture; import com.android.systemui.stackdivider.WindowManagerProxy; @@ -498,7 +497,7 @@ public class RecentsView extends FrameLayout { public void onDrawForeground(Canvas canvas) { super.onDrawForeground(canvas); - ArrayList<TaskStack.DockState> visDockStates = mTouchHandler.getVisibleDockStates(); + ArrayList<DockState> visDockStates = mTouchHandler.getVisibleDockStates(); for (int i = visDockStates.size() - 1; i >= 0; i--) { visDockStates.get(i).viewState.draw(canvas); } @@ -506,7 +505,7 @@ public class RecentsView extends FrameLayout { @Override protected boolean verifyDrawable(Drawable who) { - ArrayList<TaskStack.DockState> visDockStates = mTouchHandler.getVisibleDockStates(); + ArrayList<DockState> visDockStates = mTouchHandler.getVisibleDockStates(); for (int i = visDockStates.size() - 1; i >= 0; i--) { Drawable d = visDockStates.get(i).viewState.dockAreaOverlay; if (d == who) { @@ -540,8 +539,8 @@ public class RecentsView extends FrameLayout { public final void onBusEvent(DragStartEvent event) { updateVisibleDockRegions(Recents.getConfiguration().getDockStatesForCurrentOrientation(), - true /* isDefaultDockState */, TaskStack.DockState.NONE.viewState.dockAreaAlpha, - TaskStack.DockState.NONE.viewState.hintTextAlpha, + true /* isDefaultDockState */, DockState.NONE.viewState.dockAreaAlpha, + DockState.NONE.viewState.hintTextAlpha, true /* animateAlpha */, false /* animateBounds */); // Temporarily hide the stack action button without changing visibility @@ -555,15 +554,15 @@ public class RecentsView extends FrameLayout { } public final void onBusEvent(DragDropTargetChangedEvent event) { - if (event.dropTarget == null || !(event.dropTarget instanceof TaskStack.DockState)) { + if (event.dropTarget == null || !(event.dropTarget instanceof DockState)) { updateVisibleDockRegions( Recents.getConfiguration().getDockStatesForCurrentOrientation(), - true /* isDefaultDockState */, TaskStack.DockState.NONE.viewState.dockAreaAlpha, - TaskStack.DockState.NONE.viewState.hintTextAlpha, + true /* isDefaultDockState */, DockState.NONE.viewState.dockAreaAlpha, + DockState.NONE.viewState.hintTextAlpha, true /* animateAlpha */, true /* animateBounds */); } else { - final TaskStack.DockState dockState = (TaskStack.DockState) event.dropTarget; - updateVisibleDockRegions(new TaskStack.DockState[] {dockState}, + final DockState dockState = (DockState) event.dropTarget; + updateVisibleDockRegions(new DockState[] {dockState}, false /* isDefaultDockState */, -1, -1, true /* animateAlpha */, true /* animateBounds */); } @@ -582,8 +581,8 @@ public class RecentsView extends FrameLayout { public final void onBusEvent(final DragEndEvent event) { // Handle the case where we drop onto a dock region - if (event.dropTarget instanceof TaskStack.DockState) { - final TaskStack.DockState dockState = (TaskStack.DockState) event.dropTarget; + if (event.dropTarget instanceof DockState) { + final DockState dockState = (DockState) event.dropTarget; // Hide the dock region updateVisibleDockRegions(null, false /* isDefaultDockState */, -1, -1, @@ -812,15 +811,15 @@ public class RecentsView extends FrameLayout { /** * Updates the dock region to match the specified dock state. */ - private void updateVisibleDockRegions(TaskStack.DockState[] newDockStates, + private void updateVisibleDockRegions(DockState[] newDockStates, boolean isDefaultDockState, int overrideAreaAlpha, int overrideHintAlpha, boolean animateAlpha, boolean animateBounds) { - ArraySet<TaskStack.DockState> newDockStatesSet = Utilities.arrayToSet(newDockStates, - new ArraySet<TaskStack.DockState>()); - ArrayList<TaskStack.DockState> visDockStates = mTouchHandler.getVisibleDockStates(); + ArraySet<DockState> newDockStatesSet = Utilities.arrayToSet(newDockStates, + new ArraySet<DockState>()); + ArrayList<DockState> visDockStates = mTouchHandler.getVisibleDockStates(); for (int i = visDockStates.size() - 1; i >= 0; i--) { - TaskStack.DockState dockState = visDockStates.get(i); - TaskStack.DockState.ViewState viewState = dockState.viewState; + DockState dockState = visDockStates.get(i); + DockState.ViewState viewState = dockState.viewState; if (newDockStates == null || !newDockStatesSet.contains(dockState)) { // This is no longer visible, so hide it viewState.startAnimation(null, 0, 0, TaskStackView.SLOW_SYNC_STACK_DURATION, diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java index b6b24bcd8800..0cfdbdecdf2a 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java @@ -17,7 +17,6 @@ package com.android.systemui.recents.views; import android.app.ActivityManager; -import android.content.res.Configuration; import android.graphics.Point; import android.graphics.Rect; import android.view.InputDevice; @@ -32,7 +31,6 @@ import com.android.systemui.recents.Recents; import com.android.systemui.recents.events.EventBus; import com.android.systemui.recents.events.activity.ConfigurationChangedEvent; import com.android.systemui.recents.events.activity.HideRecentsEvent; -import com.android.systemui.recents.events.activity.HideStackActionButtonEvent; import com.android.systemui.recents.events.ui.DismissAllTaskViewsEvent; import com.android.systemui.recents.events.ui.HideIncompatibleAppOverlayEvent; import com.android.systemui.recents.events.ui.ShowIncompatibleAppOverlayEvent; @@ -41,8 +39,8 @@ import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent; import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent; import com.android.systemui.recents.events.ui.dragndrop.DragStartInitializeDropTargetsEvent; import com.android.systemui.recents.misc.SystemServicesProxy; -import com.android.systemui.recents.model.Task; -import com.android.systemui.recents.model.TaskStack; +import com.android.systemui.shared.recents.model.Task; +import com.android.systemui.shared.recents.model.TaskStack; import java.util.ArrayList; @@ -72,7 +70,7 @@ public class RecentsViewTouchHandler { private DropTarget mLastDropTarget; private DividerSnapAlgorithm mDividerSnapAlgorithm; private ArrayList<DropTarget> mDropTargets = new ArrayList<>(); - private ArrayList<TaskStack.DockState> mVisibleDockStates = new ArrayList<>(); + private ArrayList<DockState> mVisibleDockStates = new ArrayList<>(); public RecentsViewTouchHandler(RecentsView rv) { mRv = rv; @@ -96,7 +94,7 @@ public class RecentsViewTouchHandler { /** * Returns the set of visible dock states for this current drag. */ - public ArrayList<TaskStack.DockState> getVisibleDockStates() { + public ArrayList<DockState> getVisibleDockStates() { return mVisibleDockStates; } @@ -148,9 +146,9 @@ public class RecentsViewTouchHandler { EventBus.getDefault().send(new ShowIncompatibleAppOverlayEvent()); } else { // Add the dock state drop targets (these take priority) - TaskStack.DockState[] dockStates = Recents.getConfiguration() + DockState[] dockStates = Recents.getConfiguration() .getDockStatesForCurrentOrientation(); - for (TaskStack.DockState dockState : dockStates) { + for (DockState dockState : dockStates) { registerDropTargetForCurrentDrag(dockState); dockState.update(mRv.getContext()); mVisibleDockStates.add(dockState); 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 8f784b832e4c..7827c590ed81 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java @@ -30,7 +30,7 @@ import com.android.systemui.recents.events.ui.DismissAllTaskViewsEvent; import com.android.systemui.recents.events.activity.MultiWindowStateChangedEvent; import com.android.systemui.recents.events.ui.dragndrop.DragEndCancelledEvent; import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent; -import com.android.systemui.recents.model.TaskStack; +import com.android.systemui.shared.recents.utilities.AnimationProps; /** Manages the scrims for the various system bars. */ public class SystemBarScrimViews { @@ -159,7 +159,7 @@ public class SystemBarScrimViews { public final void onBusEvent(final DragEndEvent event) { // Hide the nav bar scrims once we drop to a dock region - if (event.dropTarget instanceof TaskStack.DockState) { + if (event.dropTarget instanceof DockState) { animateScrimToCurrentNavBarState(false /* hasStackTasks */); } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java index f47c1d2877bf..26db26fa3c36 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java @@ -18,13 +18,11 @@ package com.android.systemui.recents.views; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; -import android.animation.TimeInterpolator; import android.animation.ValueAnimator; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; import android.util.Log; -import android.view.View; import android.view.animation.Interpolator; import android.view.animation.PathInterpolator; @@ -37,9 +35,10 @@ import com.android.systemui.recents.RecentsDebugFlags; import com.android.systemui.recents.events.EventBus; import com.android.systemui.recents.events.component.SetWaitingForTransitionStartEvent; import com.android.systemui.recents.misc.ReferenceCountedTrigger; -import com.android.systemui.recents.model.Task; -import com.android.systemui.recents.model.TaskStack; +import com.android.systemui.shared.recents.model.Task; +import com.android.systemui.shared.recents.model.TaskStack; import com.android.systemui.recents.views.lowram.TaskStackLowRamLayoutAlgorithm; +import com.android.systemui.shared.recents.utilities.AnimationProps; import java.util.ArrayList; import java.util.List; diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java index 5ba5f44a4433..acb058cee716 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java @@ -24,7 +24,6 @@ import android.graphics.Path; import android.graphics.Rect; import android.util.ArraySet; import android.util.Log; -import android.util.MutableFloat; import android.util.SparseArray; import android.util.SparseIntArray; import android.view.ViewDebug; @@ -36,9 +35,9 @@ import com.android.systemui.recents.RecentsConfiguration; import com.android.systemui.recents.RecentsDebugFlags; import com.android.systemui.recents.misc.FreePathInterpolator; 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 com.android.systemui.shared.recents.utilities.Utilities; +import com.android.systemui.shared.recents.model.Task; +import com.android.systemui.shared.recents.model.TaskStack; import com.android.systemui.recents.views.lowram.TaskStackLowRamLayoutAlgorithm; import com.android.systemui.recents.views.grid.TaskGridLayoutAlgorithm; @@ -505,9 +504,7 @@ public class TaskStackLayoutAlgorithm { boolean scrollToFront = launchState.launchedFromHome || launchState.launchedFromPipApp || launchState.launchedWithNextPipApp || launchState.launchedViaDockGesture; - if (launchState.launchedFromBlacklistedApp) { - mInitialScrollP = mMaxScrollP; - } else if (launchState.launchedWithAltTab) { + if (launchState.launchedWithAltTab) { mInitialScrollP = Utilities.clamp(launchTaskIndex, mMinScrollP, mMaxScrollP); } else if (Recents.getConfiguration().isLowRamDevice) { mInitialScrollP = mTaskStackLowRamLayoutAlgorithm.getInitialScrollP(mNumStackTasks, @@ -535,7 +532,6 @@ public class TaskStackLayoutAlgorithm { boolean scrollToFront = launchState.launchedFromHome || launchState.launchedFromPipApp || launchState.launchedWithNextPipApp || - launchState.launchedFromBlacklistedApp || launchState.launchedViaDockGesture; if (getInitialFocusState() == STATE_UNFOCUSED && mNumStackTasks > 1) { if (ignoreScrollToFront || (!launchState.launchedWithAltTab && !scrollToFront)) { 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 cda5fb825d5f..428113a2a065 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java @@ -87,9 +87,10 @@ import com.android.systemui.recents.events.ui.focus.NavigateTaskViewEvent; import com.android.systemui.recents.misc.DozeTrigger; import com.android.systemui.recents.misc.ReferenceCountedTrigger; 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 com.android.systemui.shared.recents.utilities.AnimationProps; +import com.android.systemui.shared.recents.utilities.Utilities; +import com.android.systemui.shared.recents.model.Task; +import com.android.systemui.shared.recents.model.TaskStack; import com.android.systemui.recents.views.grid.GridTaskView; import com.android.systemui.recents.views.grid.TaskGridLayoutAlgorithm; import com.android.systemui.recents.views.grid.TaskViewFocusFrame; @@ -470,7 +471,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal boolean useTargetStackScroll = Float.compare(curStackScroll, targetStackScroll) != 0; // We can reuse the task transforms where possible to reduce object allocation - Utilities.matchTaskListSize(tasks, taskTransforms); + matchTaskListSize(tasks, taskTransforms); // Update the stack transforms TaskViewTransform frontTransform = null; @@ -700,7 +701,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal */ public void getCurrentTaskTransforms(ArrayList<Task> tasks, ArrayList<TaskViewTransform> transformsOut) { - Utilities.matchTaskListSize(tasks, transformsOut); + matchTaskListSize(tasks, transformsOut); int focusState = mLayoutAlgorithm.getFocusState(); for (int i = tasks.size() - 1; i >= 0; i--) { Task task = tasks.get(i); @@ -723,7 +724,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal */ public void getLayoutTaskTransforms(float stackScroll, int focusState, ArrayList<Task> tasks, boolean ignoreTaskOverrides, ArrayList<TaskViewTransform> transformsOut) { - Utilities.matchTaskListSize(tasks, transformsOut); + matchTaskListSize(tasks, transformsOut); for (int i = tasks.size() - 1; i >= 0; i--) { Task task = tasks.get(i); TaskViewTransform transform = transformsOut.get(i); @@ -1901,10 +1902,10 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal AnimationProps animation = new AnimationProps(SLOW_SYNC_STACK_DURATION, Interpolators.FAST_OUT_SLOW_IN); boolean ignoreTaskOverrides = false; - if (event.dropTarget instanceof TaskStack.DockState) { + if (event.dropTarget instanceof DockState) { // Calculate the new task stack bounds that matches the window size that Recents will // have after the drop - final TaskStack.DockState dockState = (TaskStack.DockState) event.dropTarget; + final DockState dockState = (DockState) event.dropTarget; Rect systemInsets = new Rect(mStableLayoutAlgorithm.mSystemInsets); // When docked, the nav bar insets are consumed and the activity is measured without // insets. However, the window bounds include the insets, so we need to subtract them @@ -1931,7 +1932,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal public final void onBusEvent(final DragEndEvent event) { // We don't handle drops on the dock regions - if (event.dropTarget instanceof TaskStack.DockState) { + if (event.dropTarget instanceof DockState) { // However, we do need to reset the overrides, since the last state of this task stack // view layout was ignoring task overrides (see DragDropTargetChangedEvent handler) mLayoutAlgorithm.clearUnfocusedTaskOverrides(); @@ -2199,6 +2200,24 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } } + /** + * Updates {@param transforms} to be the same size as {@param tasks}. + */ + private void matchTaskListSize(List<Task> tasks, List<TaskViewTransform> transforms) { + // We can reuse the task transforms where possible to reduce object allocation + int taskTransformCount = transforms.size(); + int taskCount = tasks.size(); + if (taskTransformCount < taskCount) { + // If there are less transforms than tasks, then add as many transforms as necessary + for (int i = taskTransformCount; i < taskCount; i++) { + transforms.add(new TaskViewTransform()); + } + } else if (taskTransformCount > taskCount) { + // If there are more transforms than tasks, then just subset the transform list + transforms.subList(taskCount, taskTransformCount).clear(); + } + } + public void dump(String prefix, PrintWriter writer) { String innerPrefix = prefix + " "; String id = Integer.toHexString(System.identityHashCode(this)); 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 0b20b105617d..6b23977410c7 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java @@ -24,7 +24,6 @@ import android.animation.ValueAnimator; import android.content.Context; import android.util.FloatProperty; import android.util.Log; -import android.util.MutableFloat; import android.util.Property; import android.view.ViewConfiguration; import android.view.ViewDebug; @@ -33,7 +32,8 @@ import android.widget.OverScroller; import com.android.systemui.Interpolators; import com.android.systemui.R; import com.android.systemui.recents.Recents; -import com.android.systemui.recents.misc.Utilities; +import com.android.systemui.shared.recents.utilities.AnimationProps; +import com.android.systemui.shared.recents.utilities.Utilities; import com.android.systemui.recents.views.lowram.TaskStackLowRamLayoutAlgorithm; import com.android.systemui.statusbar.FlingAnimationUtils; 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 1abaced83969..b9ca2483f3be 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java @@ -21,7 +21,6 @@ import android.animation.ValueAnimator; import android.content.Context; import android.content.res.Resources; import android.graphics.Path; -import android.graphics.Rect; import android.util.ArrayMap; import android.util.MutableBoolean; import android.view.InputDevice; @@ -45,9 +44,9 @@ import com.android.systemui.recents.events.activity.HideRecentsEvent; import com.android.systemui.recents.events.ui.StackViewScrolledEvent; import com.android.systemui.recents.events.ui.TaskViewDismissedEvent; import com.android.systemui.recents.misc.FreePathInterpolator; -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.shared.recents.utilities.AnimationProps; +import com.android.systemui.shared.recents.utilities.Utilities; +import com.android.systemui.shared.recents.model.Task; import com.android.systemui.statusbar.FlingAnimationUtils; import java.util.ArrayList; 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 a75034a123ee..b44084743896 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java @@ -51,10 +51,10 @@ import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent; import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent; import com.android.systemui.recents.misc.ReferenceCountedTrigger; 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 com.android.systemui.recents.model.ThumbnailData; +import com.android.systemui.shared.recents.utilities.AnimationProps; +import com.android.systemui.shared.recents.utilities.Utilities; +import com.android.systemui.shared.recents.model.Task; +import com.android.systemui.shared.recents.model.ThumbnailData; import java.io.PrintWriter; import java.util.ArrayList; @@ -709,7 +709,7 @@ public class TaskView extends FixedSizeFrameLayout implements Task.TaskCallbacks /**** Events ****/ public final void onBusEvent(DragEndEvent event) { - if (!(event.dropTarget instanceof TaskStack.DockState)) { + if (!(event.dropTarget instanceof DockState)) { event.addPostAnimationCallback(() -> { // Reset the clip state for the drag view after the end animation completes setClipViewInStack(true); diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewAccessibilityDelegate.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewAccessibilityDelegate.java index 0c6b6b842655..0fc507b92bf3 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewAccessibilityDelegate.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewAccessibilityDelegate.java @@ -28,11 +28,10 @@ import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; import com.android.systemui.R; import com.android.systemui.recents.Recents; import com.android.systemui.recents.events.EventBus; -import com.android.systemui.recents.events.ui.ShowApplicationInfoEvent; import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent; import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent; -import com.android.systemui.recents.misc.Utilities; -import com.android.systemui.recents.model.TaskStack; +import com.android.systemui.shared.recents.utilities.Utilities; +import com.android.systemui.shared.recents.model.TaskStack; public class TaskViewAccessibilityDelegate extends View.AccessibilityDelegate { private static final String TAG = "TaskViewAccessibilityDelegate"; @@ -61,14 +60,14 @@ public class TaskViewAccessibilityDelegate extends View.AccessibilityDelegate { super.onInitializeAccessibilityNodeInfo(host, info); if (ActivityManager.supportsSplitScreenMultiWindow(mTaskView.getContext()) && !Recents.getSystemServices().hasDockedTask()) { - TaskStack.DockState[] dockStates = Recents.getConfiguration() + DockState[] dockStates = Recents.getConfiguration() .getDockStatesForCurrentOrientation(); - for (TaskStack.DockState dockState: dockStates) { - if (dockState == TaskStack.DockState.TOP) { + for (DockState dockState: dockStates) { + if (dockState == DockState.TOP) { info.addAction(mActions.get(SPLIT_TASK_TOP)); - } else if (dockState == TaskStack.DockState.LEFT) { + } else if (dockState == DockState.LEFT) { info.addAction(mActions.get(SPLIT_TASK_LEFT)); - } else if (dockState == TaskStack.DockState.RIGHT) { + } else if (dockState == DockState.RIGHT) { info.addAction(mActions.get(SPLIT_TASK_RIGHT)); } } @@ -78,11 +77,11 @@ public class TaskViewAccessibilityDelegate extends View.AccessibilityDelegate { @Override public boolean performAccessibilityAction(View host, int action, Bundle args) { if (action == SPLIT_TASK_TOP) { - simulateDragIntoMultiwindow(TaskStack.DockState.TOP); + simulateDragIntoMultiwindow(DockState.TOP); } else if (action == SPLIT_TASK_LEFT) { - simulateDragIntoMultiwindow(TaskStack.DockState.LEFT); + simulateDragIntoMultiwindow(DockState.LEFT); } else if (action == SPLIT_TASK_RIGHT) { - simulateDragIntoMultiwindow(TaskStack.DockState.RIGHT); + simulateDragIntoMultiwindow(DockState.RIGHT); } else { return super.performAccessibilityAction(host, action, args); } @@ -90,8 +89,7 @@ public class TaskViewAccessibilityDelegate extends View.AccessibilityDelegate { } /** Simulate a user drag event to split the screen to the respected side */ - private void simulateDragIntoMultiwindow(TaskStack.DockState dockState) { - int orientation = Utilities.getAppConfiguration(mTaskView.getContext()).orientation; + private void simulateDragIntoMultiwindow(DockState dockState) { EventBus.getDefault().send(new DragStartEvent(mTaskView.getTask(), mTaskView, new Point(0,0), false /* isUserTouchInitiated */)); EventBus.getDefault().send(new DragEndEvent(mTaskView.getTask(), mTaskView, dockState)); 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 1420a0125f20..0272a9038ba8 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java @@ -17,7 +17,6 @@ package com.android.systemui.recents.views; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; -import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import android.animation.Animator; @@ -32,7 +31,6 @@ import android.graphics.Color; import android.graphics.ColorFilter; import android.graphics.Paint; import android.graphics.PixelFormat; -import android.graphics.PorterDuff; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.graphics.drawable.RippleDrawable; @@ -58,8 +56,10 @@ import com.android.systemui.recents.events.EventBus; import com.android.systemui.recents.events.activity.LaunchTaskEvent; 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.shared.system.ActivityManagerWrapper; +import com.android.systemui.shared.system.PackageManagerWrapper; +import com.android.systemui.shared.recents.utilities.Utilities; +import com.android.systemui.shared.recents.model.Task; /* The task bar view */ public class TaskViewHeader extends FrameLayout @@ -170,6 +170,8 @@ public class TaskViewHeader extends FrameLayout int mTaskBarViewLightTextColor; int mTaskBarViewDarkTextColor; int mDisabledTaskBarBackgroundColor; + String mDismissDescFormat; + String mAppInfoDescFormat; int mTaskWindowingMode = WINDOWING_MODE_UNDEFINED; // Header background @@ -218,6 +220,9 @@ public class TaskViewHeader extends FrameLayout mDarkInfoIcon = context.getDrawable(R.drawable.recents_info_dark); mDisabledTaskBarBackgroundColor = context.getColor(R.color.recents_task_bar_disabled_background_color); + mDismissDescFormat = mContext.getString( + R.string.accessibility_recents_item_will_be_dismissed); + mAppInfoDescFormat = mContext.getString(R.string.accessibility_recents_item_open_app_info); // Configure the background and dim mBackground = new HighlightColorDrawable(); @@ -455,14 +460,14 @@ public class TaskViewHeader extends FrameLayout mTaskBarViewLightTextColor : mTaskBarViewDarkTextColor); mDismissButton.setImageDrawable(t.useLightOnPrimaryColor ? mLightDismissDrawable : mDarkDismissDrawable); - mDismissButton.setContentDescription(t.dismissDescription); + mDismissButton.setContentDescription(String.format(mDismissDescFormat, t.titleDescription)); mDismissButton.setOnClickListener(this); mDismissButton.setClickable(false); ((RippleDrawable) mDismissButton.getBackground()).setForceSoftware(true); // In accessibility, a single click on the focused app info button will show it if (touchExplorationEnabled) { - mIconView.setContentDescription(t.appInfoDescription); + mIconView.setContentDescription(String.format(mAppInfoDescFormat, t.titleDescription)); mIconView.setOnClickListener(this); mIconView.setClickable(true); } @@ -599,7 +604,7 @@ public class TaskViewHeader extends FrameLayout SystemServicesProxy ssp = Recents.getSystemServices(); ComponentName cn = mTask.key.getComponent(); int userId = mTask.key.userId; - ActivityInfo activityInfo = ssp.getActivityInfo(cn, userId); + ActivityInfo activityInfo = PackageManagerWrapper.getInstance().getActivityInfo(cn, userId); if (activityInfo == null) { return; } @@ -619,11 +624,12 @@ public class TaskViewHeader extends FrameLayout } // Update the overlay contents for the current app - mAppTitleView.setText(ssp.getBadgedApplicationLabel(activityInfo.applicationInfo, userId)); + mAppTitleView.setText(ActivityManagerWrapper.getInstance().getBadgedApplicationLabel( + activityInfo.applicationInfo, userId)); mAppTitleView.setTextColor(mTask.useLightOnPrimaryColor ? mTaskBarViewLightTextColor : mTaskBarViewDarkTextColor); - mAppIconView.setImageDrawable(ssp.getBadgedApplicationIcon(activityInfo.applicationInfo, - userId)); + mAppIconView.setImageDrawable(ActivityManagerWrapper.getInstance().getBadgedApplicationIcon( + activityInfo.applicationInfo, userId)); mAppInfoView.setImageDrawable(mTask.useLightOnPrimaryColor ? mLightInfoIcon : mDarkInfoIcon); 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 d0ebc8dfc21f..4152b05a960e 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java @@ -37,9 +37,9 @@ import android.view.ViewDebug; import com.android.systemui.R; import com.android.systemui.recents.events.EventBus; import com.android.systemui.recents.events.ui.TaskSnapshotChangedEvent; -import com.android.systemui.recents.misc.Utilities; -import com.android.systemui.recents.model.Task; -import com.android.systemui.recents.model.ThumbnailData; +import com.android.systemui.shared.recents.utilities.Utilities; +import com.android.systemui.shared.recents.model.Task; +import com.android.systemui.shared.recents.model.ThumbnailData; import java.io.PrintWriter; diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java index c9dbe2ad2c4a..9b717e0e5e2f 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java @@ -21,11 +21,11 @@ import android.animation.ObjectAnimator; import android.animation.PropertyValuesHolder; import android.graphics.Rect; import android.graphics.RectF; -import android.util.IntProperty; import android.util.Property; import android.view.View; -import com.android.systemui.recents.misc.Utilities; +import com.android.systemui.shared.recents.utilities.AnimationProps; +import com.android.systemui.shared.recents.utilities.Utilities; import java.util.ArrayList; diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java index c5132024d505..ccda4b5aaf1f 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java @@ -25,10 +25,9 @@ import android.graphics.Rect; import android.view.WindowManager; import com.android.systemui.R; -import com.android.systemui.recents.events.ui.focus.NavigateTaskViewEvent; import com.android.systemui.recents.events.ui.focus.NavigateTaskViewEvent.Direction; -import com.android.systemui.recents.misc.Utilities; -import com.android.systemui.recents.model.Task; +import com.android.systemui.shared.recents.utilities.Utilities; +import com.android.systemui.shared.recents.model.Task; import com.android.systemui.recents.views.TaskStackLayoutAlgorithm; import com.android.systemui.recents.views.TaskViewTransform; diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskViewFocusFrame.java b/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskViewFocusFrame.java index 86ed583b07aa..95f1d5837e8e 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskViewFocusFrame.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskViewFocusFrame.java @@ -23,7 +23,7 @@ import android.view.View; import android.view.ViewTreeObserver.OnGlobalFocusChangeListener; import com.android.systemui.R; -import com.android.systemui.recents.model.TaskStack; +import com.android.systemui.shared.recents.model.TaskStack; import com.android.systemui.recents.views.TaskStackView; public class TaskViewFocusFrame extends View implements OnGlobalFocusChangeListener { diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/lowram/TaskStackLowRamLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/lowram/TaskStackLowRamLayoutAlgorithm.java index 17e6b9e3c195..49cac269f51d 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/lowram/TaskStackLowRamLayoutAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/lowram/TaskStackLowRamLayoutAlgorithm.java @@ -23,8 +23,8 @@ import android.view.ViewConfiguration; import com.android.systemui.R; import com.android.systemui.recents.Recents; import com.android.systemui.recents.RecentsActivityLaunchState; -import com.android.systemui.recents.misc.Utilities; -import com.android.systemui.recents.model.Task; +import com.android.systemui.shared.recents.utilities.Utilities; +import com.android.systemui.shared.recents.model.Task; import com.android.systemui.recents.views.TaskStackLayoutAlgorithm; import com.android.systemui.recents.views.TaskViewTransform; diff --git a/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java b/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java index 9211e3f6e86c..195f4d3f480d 100644 --- a/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java +++ b/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java @@ -20,37 +20,24 @@ import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIG import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT; import static android.os.UserHandle.USER_CURRENT; -import android.accessibilityservice.AccessibilityServiceInfo; import android.app.ActivityManager; -import android.app.IActivityManager; -import android.content.ComponentName; -import android.content.Context; -import android.content.pm.ServiceInfo; import android.content.res.Configuration; import android.os.RemoteException; -import android.os.UserHandle; -import android.util.ArraySet; -import android.util.DisplayMetrics; import android.util.Log; import android.view.IWindowManager; import android.view.KeyEvent; import android.view.WindowManager; import android.view.WindowManagerGlobal; -import android.view.accessibility.AccessibilityManager; -import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.nano.MetricsProto.MetricsEvent; + import com.android.internal.policy.DividerSnapAlgorithm; -import com.android.settingslib.accessibility.AccessibilityUtils; -import com.android.systemui.R; import com.android.systemui.SystemUI; import com.android.systemui.recents.Recents; import com.android.systemui.recents.misc.SystemServicesProxy; +import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.stackdivider.Divider; import com.android.systemui.stackdivider.DividerView; -import com.android.systemui.statusbar.phone.NavigationBarGestureHelper; import java.util.List; -import java.util.Set; /** * Dispatches shortcut to System UI components @@ -62,7 +49,6 @@ public class ShortcutKeyDispatcher extends SystemUI private ShortcutKeyServiceProxy mShortcutKeyServiceProxy = new ShortcutKeyServiceProxy(this); private IWindowManager mWindowManagerService = WindowManagerGlobal.getWindowManagerService(); - private IActivityManager mActivityManager = ActivityManager.getService(); protected final long META_MASK = ((long) KeyEvent.META_META_ON) << Integer.SIZE; protected final long ALT_MASK = ((long) KeyEvent.META_ALT_ON) << Integer.SIZE; @@ -109,7 +95,7 @@ public class ShortcutKeyDispatcher extends SystemUI ? DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT : DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT; List<ActivityManager.RecentTaskInfo> taskList = - SystemServicesProxy.getInstance(mContext).getRecentTasks(1, USER_CURRENT); + ActivityManagerWrapper.getInstance().getRecentTasks(1, USER_CURRENT); recents.showRecentApps( false /* triggeredFromAltTab */, false /* fromHome */); diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk index 27c16d53ce78..b695919dc2b5 100644 --- a/packages/SystemUI/tests/Android.mk +++ b/packages/SystemUI/tests/Android.mk @@ -38,6 +38,7 @@ LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res \ LOCAL_STATIC_ANDROID_LIBRARIES := \ SystemUIPluginLib \ + SystemUISharedLib \ android-support-v4 \ android-support-v7-recyclerview \ android-support-v7-preference \ |