OSDN Git Service

Porting over keyboard changes from other branch.
authorWinson <winsonc@google.com>
Fri, 20 Nov 2015 20:26:23 +0000 (12:26 -0800)
committerWinson <winsonc@google.com>
Mon, 23 Nov 2015 23:56:37 +0000 (15:56 -0800)
- Allow ignoring alt-key release when interacting via touch while
  alt-tab is pressed (ag/814903)
- Cancel window animations only if the stack scrolls via alt-tab
  (ag/809873)
- Fixing issue with old task load plan being consumed if user alt-tabs
  before Recents is resumed (ag/811354)
- Canceling enter animations when the stack scrolls (ag/814461)

Change-Id: I7450f0a280571e98212f321b1e61219d149fed65

packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java

index 31810bc..6e2b349 100644 (file)
@@ -57,6 +57,7 @@ import com.android.systemui.recents.events.ui.AllTaskViewsDismissedEvent;
 import com.android.systemui.recents.events.ui.DismissTaskViewEvent;
 import com.android.systemui.recents.events.ui.ResizeTaskEvent;
 import com.android.systemui.recents.events.ui.ShowApplicationInfoEvent;
+import com.android.systemui.recents.events.ui.StackViewScrolledEvent;
 import com.android.systemui.recents.events.ui.UserInteractionEvent;
 import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent;
 import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent;
@@ -87,29 +88,30 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
 
     public final static int EVENT_BUS_PRIORITY = Recents.EVENT_BUS_PRIORITY + 1;
 
-    RecentsPackageMonitor mPackageMonitor;
-    long mLastTabKeyEventTime;
-    boolean mFinishedOnStartup;
+    private RecentsPackageMonitor mPackageMonitor;
+    private long mLastTabKeyEventTime;
+    private boolean mFinishedOnStartup;
+    private boolean mIgnoreAltTabRelease;
 
     // Top level views
-    RecentsView mRecentsView;
-    SystemBarScrimViews mScrimViews;
-    ViewStub mEmptyViewStub;
-    View mEmptyView;
+    private RecentsView mRecentsView;
+    private SystemBarScrimViews mScrimViews;
+    private ViewStub mEmptyViewStub;
+    private View mEmptyView;
 
     // Resize task debug
-    RecentsResizeTaskDialog mResizeTaskDebugDialog;
+    private RecentsResizeTaskDialog mResizeTaskDebugDialog;
 
     // Search AppWidget
-    AppWidgetProviderInfo mSearchWidgetInfo;
-    RecentsAppWidgetHost mAppWidgetHost;
-    RecentsAppWidgetHostView mSearchWidgetHostView;
+    private AppWidgetProviderInfo mSearchWidgetInfo;
+    private RecentsAppWidgetHost mAppWidgetHost;
+    private RecentsAppWidgetHostView mSearchWidgetHostView;
 
     // Runnables to finish the Recents activity
-    FinishRecentsRunnable mFinishLaunchHomeRunnable;
+    private FinishRecentsRunnable mFinishLaunchHomeRunnable;
 
     // The trigger to automatically launch the current task
-    DozeTrigger mIterateTrigger = new DozeTrigger(500, new Runnable() {
+    private DozeTrigger mIterateTrigger = new DozeTrigger(500, new Runnable() {
         @Override
         public void run() {
             dismissRecentsToFocusedTask();
@@ -434,6 +436,9 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
     protected void onStop() {
         super.onStop();
 
+        // Reset some states
+        mIgnoreAltTabRelease = false;
+
         // Notify that recents is now hidden
         SystemServicesProxy ssp = Recents.getSystemServices();
         EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, ssp, false));
@@ -504,10 +509,6 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
                 boolean hasRepKeyTimeElapsed = (SystemClock.elapsedRealtime() -
                         mLastTabKeyEventTime) > altTabKeyDelay;
                 if (event.getRepeatCount() <= 0 || hasRepKeyTimeElapsed) {
-                    // As we iterate to the next/previous task, cancel any current/lagging window
-                    // transition animations
-                    EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(null));
-
                     // Focus the next task in the stack
                     final boolean backward = event.isShiftPressed();
                     if (backward) {
@@ -516,6 +517,11 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
                         EventBus.getDefault().send(new FocusNextTaskViewEvent());
                     }
                     mLastTabKeyEventTime = SystemClock.elapsedRealtime();
+
+                    // In the case of another ALT event, don't ignore the next release
+                    if (event.isAltPressed()) {
+                        mIgnoreAltTabRelease = false;
+                    }
                 }
                 return true;
             }
@@ -590,7 +596,9 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
     public final void onBusEvent(HideRecentsEvent event) {
         if (event.triggeredFromAltTab) {
             // If we are hiding from releasing Alt-Tab, dismiss Recents to the focused app
-            dismissRecentsToFocusedTaskOrHome();
+            if (!mIgnoreAltTabRelease) {
+                dismissRecentsToFocusedTaskOrHome();
+            }
         } else if (event.triggeredFromHomeKey) {
             // Otherwise, dismiss Recents to Home
             dismissRecentsToHome(true /* animated */);
@@ -713,6 +721,12 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
         finish();
     }
 
+    public final void onBusEvent(StackViewScrolledEvent event) {
+        // Once the user has scrolled while holding alt-tab, then we should ignore the release of
+        // the key
+        mIgnoreAltTabRelease = true;
+    }
+
     private void refreshSearchWidgetView() {
         if (mSearchWidgetInfo != null) {
             SystemServicesProxy ssp = Recents.getSystemServices();
index 1e8789a..14799ad 100644 (file)
@@ -799,12 +799,13 @@ public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub implements
         // Update the header bar if necessary
         reloadHeaderBarLayout(false /* tryAndBindSearchWidget */);
 
-        if (sInstanceLoadPlan == null) {
-            // Create a new load plan if onPreloadRecents() was never triggered
+        // In the case where alt-tab is triggered, we never get a preloadRecents() call, so we
+        // should always preload the tasks now
+        if (mTriggeredFromAltTab ||sInstanceLoadPlan == null) {
+            // Create a new load plan if preloadRecents() was never triggered
             sInstanceLoadPlan = loader.createLoadPlan(mContext);
         }
-
-        if (!sInstanceLoadPlan.hasTasks()) {
+        if (mTriggeredFromAltTab || !sInstanceLoadPlan.hasTasks()) {
             loader.preloadTasks(sInstanceLoadPlan, isTopTaskHome);
         }
         TaskStack stack = sInstanceLoadPlan.getTaskStack();
index 84e6b1e..c3bfcc5 100644 (file)
@@ -40,6 +40,8 @@ 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.CancelEnterRecentsWindowAnimationEvent;
+import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationCompletedEvent;
 import com.android.systemui.recents.events.activity.IterateRecentsEvent;
 import com.android.systemui.recents.events.activity.PackagesChangedEvent;
 import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
@@ -100,6 +102,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
     boolean mStackViewsDirty = true;
     boolean mStackViewsClipDirty = true;
     boolean mAwaitingFirstLayout = true;
+    boolean mEnterAnimationComplete = false;
     boolean mStartEnterAnimationRequestedAfterLayout;
     ViewAnimation.TaskViewEnterContext mStartEnterAnimationContext;
 
@@ -288,6 +291,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
         mStackViewsDirty = true;
         mStackViewsClipDirty = true;
         mAwaitingFirstLayout = true;
+        mEnterAnimationComplete = false;
         if (mUIDozeTrigger != null) {
             mUIDozeTrigger.stopDozing();
             mUIDozeTrigger.resetTrigger();
@@ -604,15 +608,19 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
 
     /**
      * Sets the focused task to the provided (bounded taskIndex).
+     *
+     * @return whether or not the stack will scroll as a part of this focus change
      */
-    private void setFocusedTask(int taskIndex, boolean scrollToTask, final boolean animated) {
-        setFocusedTask(taskIndex, scrollToTask, animated, true);
+    private boolean setFocusedTask(int taskIndex, boolean scrollToTask, final boolean animated) {
+        return setFocusedTask(taskIndex, scrollToTask, animated, true);
     }
 
     /**
      * Sets the focused task to the provided (bounded taskIndex).
+     *
+     * @return whether or not the stack will scroll as a part of this focus change
      */
-    private void setFocusedTask(int taskIndex, boolean scrollToTask, final boolean animated,
+    private boolean setFocusedTask(int taskIndex, boolean scrollToTask, final boolean animated,
                                 final boolean requestViewFocus) {
         // Find the next task to focus
         int newFocusedTaskIndex = mStack.getTaskCount() > 0 ?
@@ -628,6 +636,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
             }
         }
 
+        boolean willScroll = false;
         mFocusedTaskIndex = newFocusedTaskIndex;
         if (mFocusedTaskIndex != -1) {
             Runnable focusTaskRunnable = new Runnable() {
@@ -648,18 +657,33 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
                     newScroll -= 0.5f;
                 }
                 newScroll = mStackScroller.getBoundedStackScroll(newScroll);
-                mStackScroller.animateScroll(mStackScroller.getStackScroll(), newScroll,
-                        focusTaskRunnable);
+                if (Float.compare(newScroll, mStackScroller.getStackScroll()) != 0) {
+                    mStackScroller.animateScroll(mStackScroller.getStackScroll(), newScroll,
+                            focusTaskRunnable);
+                    willScroll = true;
+
+                    // Cancel any running enter animations at this point when we scroll as well
+                    if (!mEnterAnimationComplete) {
+                        final List<TaskView> taskViews = getTaskViews();
+                        for (TaskView tv : taskViews) {
+                            tv.cancelEnterRecentsAnimation();
+                        }
+                    }
+                } else {
+                    focusTaskRunnable.run();
+                }
                 mLayoutAlgorithm.animateFocusState(TaskStackLayoutAlgorithm.STATE_FOCUSED);
             } else {
                 focusTaskRunnable.run();
             }
         }
+        return willScroll;
     }
 
     /**
      * Sets the focused task relative to the currently focused task.
      *
+     * @param forward whether to go to the next task in the stack (along the curve) or the previous
      * @param stackTasksOnly if set, will ensure that the traversal only goes along stack tasks, and
      *                       if the currently focused task is not a stack task, will set the focus
      *                       to the first visible stack task
@@ -667,6 +691,23 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
      *                            focus.
      */
     public void setRelativeFocusedTask(boolean forward, boolean stackTasksOnly, boolean animated) {
+        setRelativeFocusedTask(forward, stackTasksOnly, animated, false);
+    }
+
+    /**
+     * Sets the focused task relative to the currently focused task.
+     *
+     * @param forward whether to go to the next task in the stack (along the curve) or the previous
+     * @param stackTasksOnly if set, will ensure that the traversal only goes along stack tasks, and
+     *                       if the currently focused task is not a stack task, will set the focus
+     *                       to the first visible stack task
+     * @param animated determines whether to actually draw the highlight along with the change in
+     *                            focus.
+     * @param cancelWindowAnimations if set, will attempt to cancel window animations if a scroll
+     *                               happens
+     */
+    public void setRelativeFocusedTask(boolean forward, boolean stackTasksOnly, boolean animated,
+                                       boolean cancelWindowAnimations) {
         int newIndex = -1;
         if (mFocusedTaskIndex != -1) {
             if (stackTasksOnly) {
@@ -703,7 +744,12 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
             }
         }
         if (newIndex != -1) {
-            setFocusedTask(newIndex, true, animated);
+            boolean willScroll = setFocusedTask(newIndex, true, animated);
+            if (willScroll && cancelWindowAnimations) {
+                // As we iterate to the next/previous task, cancel any current/lagging window
+                // transition animations
+                EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(null));
+            }
         }
     }
 
@@ -1418,6 +1464,10 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
         mLayoutAlgorithm.animateFocusState(mLayoutAlgorithm.getDefaultFocusState());
     }
 
+    public final void onBusEvent(EnterRecentsWindowAnimationCompletedEvent event) {
+        mEnterAnimationComplete = true;
+    }
+
     /**
      * Removes the task from the stack, and updates the focus to the next task in the stack if the
      * removed TaskView was focused.
index 3a2ed0f..62b640e 100644 (file)
@@ -166,12 +166,6 @@ public class TaskStackViewScroller {
         mScrollAnimator.setDuration(mContext.getResources().getInteger(
                 R.integer.recents_animate_task_stack_scroll_duration));
         mScrollAnimator.setInterpolator(mLinearOutSlowInInterpolator);
-        mScrollAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator animation) {
-                setStackScroll((Float) animation.getAnimatedValue());
-            }
-        });
         mScrollAnimator.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationEnd(Animator animation) {
index 0d73d91..72936b0 100644 (file)
@@ -17,6 +17,7 @@
 package com.android.systemui.recents.views;
 
 import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
 import android.content.Context;
@@ -29,7 +30,6 @@ import android.graphics.Paint;
 import android.graphics.Point;
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffColorFilter;
-import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.MotionEvent;
@@ -40,12 +40,10 @@ import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 import android.widget.FrameLayout;
 import com.android.systemui.R;
-import com.android.systemui.recents.Constants;
 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.ui.DismissTaskViewEvent;
 import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent;
@@ -340,15 +338,21 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
                     animate().alpha(1f)
                             .translationY(transform.translationY)
                             .setUpdateListener(null)
-                            .setInterpolator(mFastOutSlowInInterpolator)
-                            .setDuration(taskViewEnterFromHomeDuration)
-                            .withEndAction(new Runnable() {
+                            .setListener(new AnimatorListenerAdapter() {
+                                private boolean hasEnded;
+
+                                // We use the animation listener instead of withEndAction() to
+                                // ensure that onAnimationEnd() is called when the animator is
+                                // cancelled
                                 @Override
-                                public void run() {
-                                    // Decrement the post animation trigger
+                                public void onAnimationEnd(Animator animation) {
+                                    if (hasEnded) return;
                                     ctx.postAnimationTrigger.decrement();
+                                    hasEnded = true;
                                 }
                             })
+                            .setInterpolator(mFastOutSlowInInterpolator)
+                            .setDuration(taskViewEnterFromHomeDuration)
                             .start();
                     ctx.postAnimationTrigger.increment();
                 }
@@ -368,21 +372,30 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
                     .translationY(transform.translationY)
                     .setStartDelay(delay)
                     .setUpdateListener(ctx.updateListener)
-                    .setInterpolator(mQuintOutInterpolator)
-                    .setDuration(taskViewEnterFromHomeDuration +
-                            frontIndex * taskViewEnterFromHomeStaggerDelay)
-                    .withEndAction(new Runnable() {
+                    .setListener(new AnimatorListenerAdapter() {
+                        private boolean hasEnded;
+
+                        // We use the animation listener instead of withEndAction() to ensure that
+                        // onAnimationEnd() is called when the animator is cancelled
                         @Override
-                        public void run() {
-                            // Decrement the post animation trigger
+                        public void onAnimationEnd(Animator animation) {
+                            if (hasEnded) return;
                             ctx.postAnimationTrigger.decrement();
+                            hasEnded = true;
                         }
                     })
+                    .setInterpolator(mQuintOutInterpolator)
+                    .setDuration(taskViewEnterFromHomeDuration +
+                            frontIndex * taskViewEnterFromHomeStaggerDelay)
                     .start();
             ctx.postAnimationTrigger.increment();
         }
     }
 
+    public void cancelEnterRecentsAnimation() {
+        animate().cancel();
+    }
+
     public void fadeInActionButton(int duration) {
         // Hide the action button
         mActionButtonView.setAlpha(0f);