Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4c71aefc authored by Winson Chung's avatar Winson Chung
Browse files

Fixing crash with multiple touch pointers

- Adding support for force-reloading certain thumbnails (in prep for fix to Bug. 13587139)
- Use withLayer and withEndAction on ViewPropertyAnimator animations
- Ensuring that we close the notifications panel when we toggle recents

Change-Id: Ied2d841de42046fcb09fffb615156b07b4a67136
parent a4c1ccf3
Loading
Loading
Loading
Loading
+62 −12
Original line number Diff line number Diff line
@@ -29,45 +29,73 @@ import android.os.Handler;
import android.os.HandlerThread;
import android.os.UserHandle;
import android.util.LruCache;
import android.util.Pair;
import com.android.systemui.recents.model.SpaceNode;
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.model.TaskStack;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;


/** A bitmap load queue */
class TaskResourceLoadQueue {
    ConcurrentLinkedQueue<Task> mQueue = new ConcurrentLinkedQueue<Task>();
    ConcurrentHashMap<Task.TaskKey, Boolean> mForceLoadSet =
            new ConcurrentHashMap<Task.TaskKey, Boolean>();

    Task nextTask() {
        Console.log(Constants.DebugFlags.App.TaskDataLoader, "  [TaskResourceLoadQueue|nextTask]");
        return mQueue.poll();
    }
    static final Boolean sFalse = new Boolean(false);

    void addTask(Task t) {
    /** Adds a new task to the load queue */
    void addTask(Task t, boolean forceLoad) {
        Console.log(Constants.DebugFlags.App.TaskDataLoader, "  [TaskResourceLoadQueue|addTask]");
        if (!mQueue.contains(t)) {
            mQueue.add(t);
        }
        if (forceLoad) {
            mForceLoadSet.put(t.key, new Boolean(true));
        }
        synchronized(this) {
            notifyAll();
        }
    }

    /**
     * Retrieves the next task from the load queue, as well as whether we want that task to be
     * force reloaded.
     */
    Pair<Task, Boolean> nextTask() {
        Console.log(Constants.DebugFlags.App.TaskDataLoader, "  [TaskResourceLoadQueue|nextTask]");
        Task task = mQueue.poll();
        Boolean forceLoadTask = null;
        if (task != null) {
            forceLoadTask = mForceLoadSet.remove(task.key);
        }
        if (forceLoadTask == null) {
            forceLoadTask = sFalse;
        }
        return new Pair<Task, Boolean>(task, forceLoadTask);
    }

    /** Removes a task from the load queue */
    void removeTask(Task t) {
        Console.log(Constants.DebugFlags.App.TaskDataLoader, "  [TaskResourceLoadQueue|removeTask]");
        mQueue.remove(t);
        mForceLoadSet.remove(t.key);
    }

    /** Clears all the tasks from the load queue */
    void clearTasks() {
        Console.log(Constants.DebugFlags.App.TaskDataLoader, "  [TaskResourceLoadQueue|clearTasks]");
        mQueue.clear();
        mForceLoadSet.clear();
    }

    /** Returns whether the load queue is empty */
    boolean isEmpty() {
        return mQueue.isEmpty();
    }
@@ -147,16 +175,19 @@ class TaskResourceLoader implements Runnable {
                }
            } else {
                // Load the next item from the queue
                final Task t = mLoadQueue.nextTask();
                Pair<Task, Boolean> nextTaskData = mLoadQueue.nextTask();
                final Task t = nextTaskData.first;
                final boolean forceLoadTask = nextTaskData.second;
                if (t != null) {
                    try {
                        Drawable loadIcon = mIconCache.get(t.key);
                        Bitmap loadThumbnail = mThumbnailCache.get(t.key);
                        Console.log(Constants.DebugFlags.App.TaskDataLoader,
                                "  [TaskResourceLoader|load]",
                                t + " icon: " + loadIcon + " thumbnail: " + loadThumbnail);
                                t + " icon: " + loadIcon + " thumbnail: " + loadThumbnail +
                                        " forceLoad: " + forceLoadTask);
                        // Load the icon
                        if (loadIcon == null) {
                        if (loadIcon == null || forceLoadTask) {
                            PackageManager pm = mContext.getPackageManager();
                            ActivityInfo info = pm.getActivityInfo(t.key.intent.getComponent(),
                                    PackageManager.GET_META_DATA);
@@ -172,7 +203,7 @@ class TaskResourceLoader implements Runnable {
                            }
                        }
                        // Load the thumbnail
                        if (loadThumbnail == null) {
                        if (loadThumbnail == null || forceLoadTask) {
                            ActivityManager am = (ActivityManager)
                                    mContext.getSystemService(Context.ACTIVITY_SERVICE);
                            Bitmap thumbnail = am.getTaskTopThumbnail(t.key.id);
@@ -197,7 +228,7 @@ class TaskResourceLoader implements Runnable {
                            mMainThreadHandler.post(new Runnable() {
                                @Override
                                public void run() {
                                    t.notifyTaskDataLoaded(newThumbnail, newIcon);
                                    t.notifyTaskDataLoaded(newThumbnail, newIcon, forceLoadTask);
                                }
                            });
                        }
@@ -329,9 +360,11 @@ public class RecentsTaskLoader {
    /** Reload the set of recent tasks */
    SpaceNode reload(Context context, int preloadCount) {
        Console.log(Constants.DebugFlags.App.TaskDataLoader, "[RecentsTaskLoader|reload]");
        ArrayList<Task> tasksToForceLoad = new ArrayList<Task>();
        TaskStack stack = new TaskStack(context);
        SpaceNode root = new SpaceNode(context);
        root.setStack(stack);

        try {
            long t1 = System.currentTimeMillis();

@@ -387,6 +420,12 @@ public class RecentsTaskLoader {
                    // Load the icon (if possible and not the foremost task, from the cache)
                    if (!isForemostTask) {
                        task.icon = mIconCache.get(task.key);

                        if (task.icon != null) {
                            // Even though we get things from the cache, we should update them if
                            // they've changed in the bg
                            tasksToForceLoad.add(task);
                        }
                    }
                    if (task.icon == null) {
                        task.icon = info.loadIcon(pm);
@@ -400,6 +439,12 @@ public class RecentsTaskLoader {
                    // Load the thumbnail (if possible and not the foremost task, from the cache)
                    if (!isForemostTask) {
                        task.thumbnail = mThumbnailCache.get(task.key);

                        if (task.thumbnail != null) {
                            // Even though we get things from the cache, we should update them if
                            // they've changed in the bg
                            tasksToForceLoad.add(task);
                        }
                    }
                    if (task.thumbnail == null) {
                        Console.log(Constants.DebugFlags.App.TaskDataLoader,
@@ -451,6 +496,11 @@ public class RecentsTaskLoader {
        // Start the task loader
        mLoader.start(context);

        // Add all the tasks that we are force/re-loading
        for (Task t : tasksToForceLoad) {
            mLoadQueue.addTask(t, true);
        }

        return root;
    }

@@ -473,9 +523,9 @@ public class RecentsTaskLoader {
            requiresLoad = true;
        }
        if (requiresLoad) {
            mLoadQueue.addTask(t);
            mLoadQueue.addTask(t, false);
        }
        t.notifyTaskDataLoaded(thumbnail, icon);
        t.notifyTaskDataLoaded(thumbnail, icon, false);
    }

    /** Releases the task resource data back into the pool. */
+3 −3
Original line number Diff line number Diff line
@@ -29,7 +29,7 @@ public class Task {
    /* Task callbacks */
    public interface TaskCallbacks {
        /* Notifies when a task has been bound */
        public void onTaskDataLoaded();
        public void onTaskDataLoaded(boolean reloadingTaskData);
        /* Notifies when a task has been unbound */
        public void onTaskDataUnloaded();
    }
@@ -84,11 +84,11 @@ public class Task {
    }

    /** Notifies the callback listeners that this task has been loaded */
    public void notifyTaskDataLoaded(Bitmap thumbnail, Drawable icon) {
    public void notifyTaskDataLoaded(Bitmap thumbnail, Drawable icon, boolean reloadingTaskData) {
        this.icon = icon;
        this.thumbnail = thumbnail;
        if (mCb != null) {
            mCb.onTaskDataLoaded();
            mCb.onTaskDataLoaded(reloadingTaskData);
        }
    }

+20 −4
Original line number Diff line number Diff line
@@ -881,6 +881,13 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
                }
                break;
            }
            case MotionEvent.ACTION_POINTER_DOWN: {
                final int index = ev.getActionIndex();
                mActivePointerId = ev.getPointerId(index);
                mLastMotionX = (int) ev.getX(index);
                mLastMotionY = (int) ev.getY(index);
                break;
            }
            case MotionEvent.ACTION_MOVE: {
                if (mActivePointerId == INACTIVE_POINTER_ID) break;

@@ -957,6 +964,19 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
                recycleVelocityTracker();
                break;
            }
            case MotionEvent.ACTION_POINTER_UP: {
                int pointerIndex = ev.getActionIndex();
                int pointerId = ev.getPointerId(pointerIndex);
                if (pointerId == mActivePointerId) {
                    // Select a new active pointer id and reset the motion state
                    final int newPointerIndex = (pointerIndex == 0) ? 1 : 0;
                    mActivePointerId = ev.getPointerId(newPointerIndex);
                    mLastMotionX = (int) ev.getX(newPointerIndex);
                    mLastMotionY = (int) ev.getY(newPointerIndex);
                    mVelocityTracker.clear();
                }
                break;
            }
            case MotionEvent.ACTION_CANCEL: {
                if (mIsScrolling) {
                    // Disable HW layers
@@ -1006,10 +1026,6 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
        Task task = tv.getTask();
        Activity activity = (Activity) mSv.getContext();

        // We have to disable the listener to ensure that we
        // don't hit this again
        tv.animate().setListener(null);

        // Remove the task from the view
        mSv.mStack.removeTask(task);

+8 −18
Original line number Diff line number Diff line
@@ -65,10 +65,7 @@ class TaskThumbnailView extends ImageView {

            setImageBitmap(t.thumbnail);
            if (animate) {
                setAlpha(0f);
                animate().alpha(1f)
                        .setDuration(Constants.Values.TaskView.Animation.TaskDataUpdatedFadeDuration)
                        .start();
                // XXX: Investigate how expensive it will be to create a second bitmap and crossfade
            }
        }
    }
@@ -143,10 +140,7 @@ class TaskIconView extends ImageView {
        if (t.icon != null) {
            setImageDrawable(t.icon);
            if (animate) {
                setAlpha(0f);
                animate().alpha(1f)
                        .setDuration(Constants.Values.TaskView.Animation.TaskDataUpdatedFadeDuration)
                        .start();
                // XXX: Investigate how expensive it will be to create a second bitmap and crossfade
            }
        }
    }
@@ -311,6 +305,7 @@ public class TaskView extends FrameLayout implements View.OnClickListener, Task.
                    .translationY(0)
                    .setStartDelay(235)
                    .setDuration(Constants.Values.TaskView.Animation.TaskIconOnEnterDuration)
                    .withLayer()
                    .start();
        }
    }
@@ -333,13 +328,8 @@ public class TaskView extends FrameLayout implements View.OnClickListener, Task.
                .setStartDelay(0)
                .setDuration(Constants.Values.TaskView.Animation.TaskIconOnLeavingDuration)
                .setInterpolator(new DecelerateInterpolator())
                .setListener(
                    new AnimatorListenerAdapter() {
                        @Override
                        public void onAnimationEnd(Animator animation) {
                            r.run();
                        }
                    })
                .withLayer()
                .withEndAction(r)
                .start();
        }
    }
@@ -379,10 +369,10 @@ public class TaskView extends FrameLayout implements View.OnClickListener, Task.
    }

    @Override
    public void onTaskDataLoaded() {
    public void onTaskDataLoaded(boolean reloadingTaskData) {
        // Bind each of the views to the new task data
        mThumbnailView.rebindToTask(mTask, false);
        mIconView.rebindToTask(mTask, false);
        mThumbnailView.rebindToTask(mTask, reloadingTaskData);
        mIconView.rebindToTask(mTask, reloadingTaskData);
    }

    @Override
+1 −0
Original line number Diff line number Diff line
@@ -757,6 +757,7 @@ public abstract class BaseStatusBar extends SystemUI implements

    protected void toggleRecentsActivity() {
        if (mRecents != null) {
            sendCloseSystemWindows(mContext, SYSTEM_DIALOG_REASON_RECENT_APPS);
            mRecents.toggleRecents(mDisplay, mLayoutDirection, getStatusBarView());
        }
    }