Merge "Refactor initializing LauncherAccessibilityDelegate" into ub-launcher3-edmonton
diff --git a/quickstep/res/layout/overview_clear_all_button.xml b/quickstep/res/layout/overview_clear_all_button.xml
index c8f235f..1ada914 100644
--- a/quickstep/res/layout/overview_clear_all_button.xml
+++ b/quickstep/res/layout/overview_clear_all_button.xml
@@ -6,7 +6,7 @@
     style="@android:style/Widget.DeviceDefault.Button.Borderless"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
-    android:layout_gravity="end|top"
+    android:layout_gravity="start|top"
     android:fontFamily="sans-serif-medium"
     android:text="@string/recents_clear_all"
     android:textColor="?attr/workspaceTextColor"
diff --git a/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java b/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java
index 80cc366..8b9903d 100644
--- a/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java
+++ b/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java
@@ -26,14 +26,17 @@
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.graphics.RectF;
+import android.os.RemoteException;
 
 import com.android.launcher3.BaseDraggingActivity;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.views.BaseDragLayer;
+import com.android.quickstep.RecentsModel;
 import com.android.quickstep.views.RecentsView;
 import com.android.quickstep.views.TaskThumbnailView;
+import com.android.systemui.shared.recents.ISystemUiProxy;
 import com.android.systemui.shared.recents.utilities.RectFEvaluator;
 import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
 import com.android.systemui.shared.system.TransactionCompat;
@@ -171,27 +174,7 @@
         mHomeStackBounds.offset(pos[0], pos[1]);
 
         if (rv.shouldUseMultiWindowTaskSizeStrategy()) {
-            // TODO: Fetch multi-window target bounds from system-ui
-            DeviceProfile fullDp = activity.getDeviceProfile().getFullScreenProfile();
-            // Use availableWidthPx and availableHeightPx instead of widthPx and heightPx to
-            // account for system insets
-            int taskWidth = fullDp.availableWidthPx;
-            int taskHeight = fullDp.availableHeightPx;
-            int halfDividerSize = activity.getResources()
-                    .getDimensionPixelSize(R.dimen.multi_window_task_divider_size) / 2;
-
-            Rect insets = new Rect();
-            WindowManagerWrapper.getInstance().getStableInsets(insets);
-            if (fullDp.isLandscape) {
-                taskWidth = taskWidth / 2 - halfDividerSize;
-            } else {
-                taskHeight = taskHeight / 2 - halfDividerSize;
-            }
-
-            mSourceStackBounds.set(0, 0, taskWidth, taskHeight);
-            // Align the task to bottom right (probably not true for seascape).
-            mSourceStackBounds.offset(insets.left + fullDp.availableWidthPx - taskWidth,
-                    insets.top + fullDp.availableHeightPx - taskHeight);
+            updateStackBoundsToMultiWindowTaskSize(activity);
         } else {
             mSourceStackBounds.set(mHomeStackBounds);
             mSourceInsets.set(activity.getDeviceProfile().getInsets());
@@ -209,6 +192,41 @@
         mSourceWindowClipInsets.bottom = mSourceWindowClipInsets.bottom * scale;
     }
 
+    private void updateStackBoundsToMultiWindowTaskSize(BaseDraggingActivity activity) {
+        ISystemUiProxy sysUiProxy = RecentsModel.getInstance(activity).getSystemUiProxy();
+        if (sysUiProxy != null) {
+            try {
+                mSourceStackBounds.set(sysUiProxy.getNonMinimizedSplitScreenSecondaryBounds());
+                return;
+            } catch (RemoteException e) {
+                // Use half screen size
+            }
+        }
+
+        // Assume that the task size is half screen size (minus the insets and the divider size)
+        DeviceProfile fullDp = activity.getDeviceProfile().getFullScreenProfile();
+        // Use availableWidthPx and availableHeightPx instead of widthPx and heightPx to
+        // account for system insets
+        int taskWidth = fullDp.availableWidthPx;
+        int taskHeight = fullDp.availableHeightPx;
+        int halfDividerSize = activity.getResources()
+                .getDimensionPixelSize(R.dimen.multi_window_task_divider_size) / 2;
+
+        Rect insets = new Rect();
+        WindowManagerWrapper.getInstance().getStableInsets(insets);
+        if (fullDp.isLandscape) {
+            taskWidth = taskWidth / 2 - halfDividerSize;
+        } else {
+            taskHeight = taskHeight / 2 - halfDividerSize;
+        }
+
+        mSourceStackBounds.set(0, 0, taskWidth, taskHeight);
+        // Align the task to bottom right (probably not true for seascape).
+        mSourceStackBounds.offset(insets.left + fullDp.availableWidthPx - taskWidth,
+                insets.top + fullDp.availableHeightPx - taskHeight);
+    }
+
+
     public void drawForProgress(TaskThumbnailView ttv, Canvas canvas, float progress) {
         RectF currentRect =  mRectFEvaluator.evaluate(progress, mSourceRect, mTargetRect);
         canvas.translate(mSourceStackBounds.left - mHomeStackBounds.left,
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 5fff51c..51b787b 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -88,8 +88,6 @@
 
     private static final String TAG = RecentsView.class.getSimpleName();
 
-    public static final boolean DEBUG_SHOW_CLEAR_ALL_BUTTON = false;
-
     private final Rect mTempRect = new Rect();
 
     public static final FloatProperty<RecentsView> ADJACENT_SCALE =
@@ -104,9 +102,11 @@
             return recentsView.mAdjacentScale;
         }
     };
-    private static final boolean FLIP_RECENTS = true;
+    public static final boolean FLIP_RECENTS = true;
     private static final int DISMISS_TASK_DURATION = 300;
 
+    private static final float[] sTempFloatArray = new float[3];
+
     protected final T mActivity;
     private final QuickScrubController mQuickScrubController;
     private final float mFastFlingVelocity;
@@ -303,41 +303,55 @@
     }
 
     private float calculateClearAllButtonAlpha() {
-        if (mClearAllButton.getVisibility() != View.VISIBLE || getChildCount() == 0) return 0;
+        final int childCount = getChildCount();
+        if (mClearAllButton.getVisibility() != View.VISIBLE || childCount == 0) return 0;
 
-        // Current visible coordinate of the right border of the rightmost task.
-        final int carouselCurrentRight = getChildAt(getChildCount() - 1).getRight() - getScrollX();
+        // Current visible coordinate of the end of the oldest task.
+        final View lastChild = getChildAt(childCount - 1);
+        final int carouselCurrentEnd =
+                (mIsRtl ? lastChild.getLeft() : lastChild.getRight()) - getScrollX();
 
-        // As the right border (let's call it E aka carouselCurrentRight) of the carousel moves
-        // over Clear all button, the button changes trasparency.
-        // leftOfAlphaChange < rightOfAlphaChange; these are the points of the 100% and 0% alpha
-        // correspondingly. Alpha changes linearly between 100% and 0% as E moves through this
-        // range. It doesn't change outside of the range.
+        // As the end (let's call it E aka carouselCurrentEnd) of the carousel moves over Clear
+        // all button, the button changes trasparency.
+        // fullAlphaX and zeroAlphaX are the points of the 100% and 0% alpha correspondingly.
+        // Alpha changes linearly between 100% and 0% as E moves through this range. It doesn't
+        // change outside of the range.
 
-        // Once E hits the left border of the Clear-All button, the whole button is uncovered,
-        // and it should have alpha 100%.
-        final float leftOfAlphaChange = mClearAllButton.getX();
+        // Once E hits the border of the Clear-All button that looks towards the most recent
+        // task, the whole button is uncovered, and it should have alpha 100%.
+        final float fullAlphaX = mIsRtl ?
+                mClearAllButton.getX() + mClearAllButton.getWidth() :
+                mClearAllButton.getX();
 
-        // The rightmost possible right coordinate of the carousel.
-        final int carouselMotionLimit = getScrollForPage(getChildCount() - 1) + getWidth()
-                - getPaddingRight() - mInsets.right;
+        // X coordinate of the carousel scrolled as far as possible in the direction towards the
+        // button. Logically, the button is "behind" the least recent task. This is the
+        // coordinate of the end of the least recent task in the carousel just after opening,
+        // with the most recent task in the center, and the rest of tasks go from that point
+        // towards and potentially behind the button.
+        final int carouselMotionLimit = getScrollForPage(childCount - 1) - getScrollForPage(0) +
+                (mIsRtl ?
+                        getPaddingLeft() + mInsets.left :
+                        getWidth() - getPaddingRight() - mInsets.right);
 
         // The carousel might not be able to ever cover a part of the Clear-all button. Then
         // always show the button as 100%. Technically, this check also prevents dividing by zero
-        // or a negative number when calculating the transparency ratio below.
-        if (carouselMotionLimit <= leftOfAlphaChange) return 1;
+        // or getting a negative transparency ratio.
+        if (mIsRtl ? carouselMotionLimit >= fullAlphaX : carouselMotionLimit <= fullAlphaX) {
+            return 1;
+        }
 
         // If the carousel is able to cover the button completely, we make the button completely
-        // transparent when E hits the right border of the button.
-        // Or, the carousel may not be able to move that far to the right so it completely covers
-        // the button. Then we set the rightmost possible position of the carousel as the point
+        // transparent when E hits the border of the button farthest from the most recent task.
+        // Or, the carousel may not be able to move that far towards the button so it completely
+        // covers the it. Then we set the motion limit position of the carousel as the point
         // where the button reaches 0 alpha.
-        final float rightOfAlphaChange = Math.min(
-                mClearAllButton.getX() + mClearAllButton.getWidth(), carouselMotionLimit);
+        final float zeroAlphaX = mIsRtl ?
+                Math.max(mClearAllButton.getX(), carouselMotionLimit) :
+                Math.min(mClearAllButton.getX() + mClearAllButton.getWidth(), carouselMotionLimit);
 
         return Utilities.boundToRange(
-                (rightOfAlphaChange - carouselCurrentRight) /
-                        (rightOfAlphaChange - leftOfAlphaChange), 0, 1);
+                (zeroAlphaX - carouselCurrentEnd) /
+                        (zeroAlphaX - fullAlphaX), 0, 1);
     }
 
     private void updateClearAllButtonAlpha() {
@@ -354,9 +368,8 @@
 
     @Override
     public boolean onTouchEvent(MotionEvent ev) {
-        if (DEBUG_SHOW_CLEAR_ALL_BUTTON && ev.getAction() == MotionEvent.ACTION_DOWN
-                && mTouchState == TOUCH_STATE_REST && mScroller.isFinished()
-                && mClearAllButton.getVisibility() == View.VISIBLE) {
+        if (ev.getAction() == MotionEvent.ACTION_DOWN && mTouchState == TOUCH_STATE_REST
+                && mScroller.isFinished() && mClearAllButton.getVisibility() == View.VISIBLE) {
             mClearAllButton.getHitRect(mTempRect);
             mTempRect.offset(-getLeft(), -getTop());
             if (mTempRect.contains((int) ev.getX(), (int) ev.getY())) {
@@ -985,11 +998,10 @@
     private float[] getAdjacentScaleAndTranslation(TaskView currTask, TaskView adjacentTask,
             float currTaskToScale, float currTaskToTranslationY) {
         float displacement = currTask.getWidth() * (currTaskToScale - currTask.getCurveScale());
-        return new float[] {
-                currTaskToScale * adjacentTask.getCurveScale(),
-                mIsRtl ? -displacement : displacement,
-                currTaskToTranslationY
-        };
+        sTempFloatArray[0] = currTaskToScale * adjacentTask.getCurveScale();
+        sTempFloatArray[1] = mIsRtl ? -displacement : displacement;
+        sTempFloatArray[2] = currTaskToTranslationY;
+        return sTempFloatArray;
     }
 
     @Override
@@ -1206,21 +1218,29 @@
         return "";
     }
 
+    private int additionalScrollForClearAllButton() {
+        return (int) getResources().getDimension(
+                R.dimen.clear_all_container_width) - getPaddingEnd();
+    }
+
     @Override
     protected int computeMaxScrollX() {
-        if (!DEBUG_SHOW_CLEAR_ALL_BUTTON || getChildCount() == 0) {
+        if (getChildCount() == 0) {
             return super.computeMaxScrollX();
         }
 
         // Allow a clear_all_container_width-sized gap after the last task.
-        return super.computeMaxScrollX() + (int) getResources().getDimension(
-                R.dimen.clear_all_container_width) - getPaddingEnd();
+        return super.computeMaxScrollX() + (mIsRtl ? 0 : additionalScrollForClearAllButton());
+    }
+
+    @Override
+    protected int offsetForPageScrolls() {
+        return mIsRtl ? additionalScrollForClearAllButton() : 0;
     }
 
     private void updateClearAllButtonVisibility() {
         if (mClearAllButton == null) return;
-        mClearAllButton.setVisibility(
-                !DEBUG_SHOW_CLEAR_ALL_BUTTON || mShowEmptyMessage ? GONE : VISIBLE);
+        mClearAllButton.setVisibility(mShowEmptyMessage ? GONE : VISIBLE);
         updateClearAllButtonAlpha();
     }
 
diff --git a/quickstep/src/com/android/quickstep/views/RecentsViewContainer.java b/quickstep/src/com/android/quickstep/views/RecentsViewContainer.java
index 988b3ad..6b89b66 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsViewContainer.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsViewContainer.java
@@ -4,6 +4,7 @@
 import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.util.FloatProperty;
+import android.view.Gravity;
 import android.view.MotionEvent;
 import android.view.View;
 
@@ -43,6 +44,10 @@
         });
 
         mRecentsView = (RecentsView) findViewById(R.id.overview_panel);
+        final InsettableFrameLayout.LayoutParams params =
+                (InsettableFrameLayout.LayoutParams) mClearAllButton.getLayoutParams();
+        params.gravity = Gravity.TOP | (RecentsView.FLIP_RECENTS ? Gravity.START : Gravity.END);
+        mClearAllButton.setLayoutParams(params);
         mRecentsView.setClearAllButton(mClearAllButton);
     }
 
@@ -53,8 +58,9 @@
         mRecentsView.getTaskSize(mTempRect);
 
         mClearAllButton.setTranslationX(
-                (mClearAllButton.getMeasuredWidth() - getResources().getDimension(
-                        R.dimen.clear_all_container_width)) / 2);
+                (mRecentsView.isRtl() ? 1 : -1) *
+                        (getResources().getDimension(R.dimen.clear_all_container_width)
+                                - mClearAllButton.getMeasuredWidth()) / 2);
         mClearAllButton.setTranslationY(
                 mTempRect.top + (mTempRect.height() - mClearAllButton.getMeasuredHeight()) / 2
                         - mClearAllButton.getTop());
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index c2416d4..adca327 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -607,18 +607,19 @@
         final int endIndex = mIsRtl ? -1 : childCount;
         final int delta = mIsRtl ? -1 : 1;
 
-        int verticalPadding = getPaddingTop() + getPaddingBottom();
+        final int verticalPadding = getPaddingTop() + getPaddingBottom();
 
-        int scrollOffsetLeft = mInsets.left + getPaddingLeft();
-        int childLeft = scrollOffsetLeft;
+        final int scrollOffsetLeft = mInsets.left + getPaddingLeft();
         boolean pageScrollChanged = false;
 
-        for (int i = startIndex; i != endIndex; i += delta) {
+        for (int i = startIndex, childLeft = scrollOffsetLeft + offsetForPageScrolls();
+                i != endIndex;
+                i += delta) {
             final View child = getPageAt(i);
             if (scrollLogic.shouldIncludeView(child)) {
-                int childTop = getPaddingTop() + mInsets.top;
-                childTop += (getMeasuredHeight() - mInsets.top - mInsets.bottom - verticalPadding
-                        - child.getMeasuredHeight()) / 2;
+                final int childTop = getPaddingTop() +
+                        (getMeasuredHeight() - mInsets.bottom - verticalPadding
+                                - child.getMeasuredHeight()) / 2;
                 final int childWidth = child.getMeasuredWidth();
 
                 if (layoutChildren) {
@@ -657,6 +658,10 @@
         }
     }
 
+    protected int offsetForPageScrolls() {
+        return 0;
+    }
+
     public void setPageSpacing(int pageSpacing) {
         mPageSpacing = pageSpacing;
         requestLayout();