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 \ |