Merge "Don't removePluginListener() unless user is unlocked" into ub-launcher3-master
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
index 9ad0638..613386e 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
@@ -339,9 +339,20 @@
 
         final LauncherState targetState;
         if (horizontalFling && verticalFling) {
-            // Flinging left and up, left and down, or right and up all go back home.
-            // Only flinging right and down goes to quick switch.
-            targetState = velocity.x < 0 || velocity.y < 0 ? NORMAL : QUICK_SWITCH;
+            if (velocity.x < 0) {
+                // Flinging left and up or down both go back home.
+                targetState = NORMAL;
+            } else {
+                if (velocity.y > 0) {
+                    // Flinging right and down goes to quick switch.
+                    targetState = QUICK_SWITCH;
+                } else {
+                    // Flinging up and right could go either home or to quick switch.
+                    // Determine the target based on the higher velocity.
+                    targetState = Math.abs(velocity.x) > Math.abs(velocity.y)
+                        ? QUICK_SWITCH : NORMAL;
+                }
+            }
         } else if (horizontalFling) {
             targetState = velocity.x > 0 ? QUICK_SWITCH : NORMAL;
         } else if (verticalFling) {
diff --git a/src/com/android/launcher3/ExtendedEditText.java b/src/com/android/launcher3/ExtendedEditText.java
index 4e0f2e7..52a393f 100644
--- a/src/com/android/launcher3/ExtendedEditText.java
+++ b/src/com/android/launcher3/ExtendedEditText.java
@@ -21,14 +21,19 @@
 import android.view.DragEvent;
 import android.view.KeyEvent;
 import android.view.View;
+import android.view.inputmethod.CompletionInfo;
 import android.view.inputmethod.InputMethodManager;
 import android.widget.EditText;
 
+import com.android.launcher3.folder.FolderNameProvider;
 import com.android.launcher3.util.UiThreadHelper;
 
+import java.util.List;
+
 
 /**
  * The edit text that reports back when the back key has been pressed.
+ * Note: AppCompatEditText doesn't fully support #displayCompletions and #onCommitCompletion
  */
 public class ExtendedEditText extends EditText {
 
@@ -85,12 +90,9 @@
         super.onLayout(changed, left, top, right, bottom);
         if (mShowImeAfterFirstLayout) {
             // soft input only shows one frame after the layout of the EditText happens,
-            post(new Runnable() {
-                @Override
-                public void run() {
-                    showSoftInput();
-                    mShowImeAfterFirstLayout = false;
-                }
+            post(() -> {
+                showSoftInput();
+                mShowImeAfterFirstLayout = false;
             });
         }
     }
@@ -103,9 +105,27 @@
         UiThreadHelper.hideKeyboardAsync(getContext(), getWindowToken());
     }
 
+    @Override
+    public void onCommitCompletion(CompletionInfo text) {
+        setText(text.getText());
+    }
+
+    /**
+     * Currently only used for folder name suggestion.
+     */
+    public void displayCompletions(List<String> suggestList) {
+        int cnt = Math.min(suggestList.size(), FolderNameProvider.SUGGEST_MAX);
+        CompletionInfo[] cInfo = new CompletionInfo[cnt];
+        for (int i = 0; i < cnt; i++) {
+            cInfo[i] = new CompletionInfo(i, i, suggestList.get(i));
+        }
+        post(() -> getContext().getSystemService(InputMethodManager.class)
+                .displayCompletions(this, cInfo));
+    }
+
     private boolean showSoftInput() {
         return requestFocus() &&
-                ((InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE))
+                getContext().getSystemService(InputMethodManager.class)
                     .showSoftInput(this, InputMethodManager.SHOW_IMPLICIT);
     }
 
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index 0bd2c9a..33da582 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -84,6 +84,7 @@
 import com.android.launcher3.widget.PendingAddShortcutInfo;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
@@ -217,7 +218,7 @@
                 & ~InputType.TYPE_TEXT_FLAG_AUTO_CORRECT
                 & ~InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS
                 | InputType.TYPE_TEXT_FLAG_CAP_WORDS);
-        mFolderName.forceDisableSuggestions(true);
+        mFolderName.forceDisableSuggestions(!FeatureFlags.FOLDER_NAME_SUGGEST.get());
 
         mFooter = findViewById(R.id.folder_footer);
 
@@ -412,19 +413,20 @@
         });
     }
 
-
     /**
      * Show suggested folder title.
      */
-    public void showSuggestedTitle(CharSequence suggestName) {
+    public void showSuggestedTitle(String[] suggestName) {
         if (FeatureFlags.FOLDER_NAME_SUGGEST.get() && mInfo.contents.size() == 2) {
-            if (!TextUtils.isEmpty(suggestName)) {
-                mFolderName.setHint(suggestName);
-                mFolderName.setText(suggestName);
+            if (suggestName.length > 0 && !TextUtils.isEmpty(suggestName[0])) {
+                mFolderName.setHint(suggestName[0]);
+                mFolderName.setText(suggestName[0]);
+                mInfo.title = suggestName[0];
+                animateOpen();
                 mFolderName.showKeyboard();
-                mInfo.title = suggestName;
+                mFolderName.displayCompletions(
+                        Arrays.asList(suggestName).subList(1, suggestName.length));
             }
-            animateOpen();
         }
     }
 
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index fd6d1e3..7bbd45d 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -371,22 +371,31 @@
             if (!itemAdded) mPreviewItemManager.hidePreviewItem(index, true);
             final int finalIndex = index;
 
-            String[] suggestedNameOut = new String[1];
+            String[] suggestedNameOut = new String[FolderNameProvider.SUGGEST_MAX];
             if (FeatureFlags.FOLDER_NAME_SUGGEST.get()) {
-                Executors.UI_HELPER_EXECUTOR.post(() -> mLauncher.getFolderNameProvider()
-                        .getSuggestedFolderName(getContext(), mInfo.contents, suggestedNameOut));
+                Executors.UI_HELPER_EXECUTOR.post(() -> {
+                    mLauncher.getFolderNameProvider().getSuggestedFolderName(
+                            getContext(), mInfo.contents, suggestedNameOut);
+                    showFinalView(finalIndex, item, suggestedNameOut);
+                });
+            } else {
+                showFinalView(finalIndex, item, suggestedNameOut);
             }
-            postDelayed(() -> {
-                mPreviewItemManager.hidePreviewItem(finalIndex, false);
-                mFolder.showItem(item);
-                invalidate();
-                mFolder.showSuggestedTitle(suggestedNameOut[0]);
-            }, DROP_IN_ANIMATION_DURATION);
         } else {
             addItem(item);
         }
     }
 
+    private void showFinalView(int finalIndex, final WorkspaceItemInfo item,
+            String[] suggestedNameOut) {
+        postDelayed(() -> {
+            mPreviewItemManager.hidePreviewItem(finalIndex, false);
+            mFolder.showItem(item);
+            invalidate();
+            mFolder.showSuggestedTitle(suggestedNameOut);
+        }, DROP_IN_ANIMATION_DURATION);
+    }
+
     public void onDrop(DragObject d, boolean itemReturnedOnFailedDrop) {
         WorkspaceItemInfo item;
         if (d.dragInfo instanceof AppInfo) {
diff --git a/src/com/android/launcher3/folder/FolderNameProvider.java b/src/com/android/launcher3/folder/FolderNameProvider.java
index 0a1221e..37aa815 100644
--- a/src/com/android/launcher3/folder/FolderNameProvider.java
+++ b/src/com/android/launcher3/folder/FolderNameProvider.java
@@ -29,6 +29,12 @@
 public class FolderNameProvider {
 
     /**
+     * IME usually has up to 3 suggest slots. Adding one as in Launcher, there are folder
+     * name edit box that we can also provide suggestion.
+     */
+    public static final int SUGGEST_MAX = 4;
+
+    /**
      * Returns suggested folder name.
      */
     public CharSequence getSuggestedFolderName(Context context,
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 4024ff0..ccf98ae 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -560,10 +560,12 @@
                 final int finalState = mDevice.hasObject(By.pkg(getLauncherPackageName()))
                         ? NORMAL_STATE_ORDINAL : BACKGROUND_APP_STATE_ORDINAL;
 
-                swipeToState(
-                        displaySize.x / 2, displaySize.y - 1,
-                        displaySize.x / 2, 0,
-                        ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME, finalState);
+                try (LauncherInstrumentation.Closable c = addContextLayer(action)) {
+                    swipeToState(
+                            displaySize.x / 2, displaySize.y - 1,
+                            displaySize.x / 2, 0,
+                            ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME, finalState);
+                }
             }
         } else {
             log(action = "clicking home button");
@@ -873,12 +875,17 @@
         final Point start = new Point(startX, startY);
         final Point end = new Point(endX, endY);
         sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN, start);
+        final long endTime = movePointer(start, end, steps, downTime, slowDown);
+        sendPointer(downTime, endTime, MotionEvent.ACTION_UP, end);
+    }
+
+    long movePointer(Point start, Point end, int steps, long downTime, boolean slowDown) {
         long endTime = movePointer(downTime, downTime, steps * GESTURE_STEP_MS, start, end);
         if (slowDown) {
             endTime = movePointer(downTime, endTime + GESTURE_STEP_MS, 5 * GESTURE_STEP_MS, end,
                     end);
         }
-        sendPointer(downTime, endTime, MotionEvent.ACTION_UP, end);
+        return endTime;
     }
 
     void waitForIdle() {
diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java
index 3301dd8..81d343d 100644
--- a/tests/tapl/com/android/launcher3/tapl/Workspace.java
+++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java
@@ -39,7 +39,6 @@
  * Operations on the workspace screen.
  */
 public final class Workspace extends Home {
-    private static final int DRAG_DURATION = 500;
     private static final int FLING_STEPS = 10;
     private final UiObject2 mHotseat;
 
@@ -170,8 +169,7 @@
         LauncherInstrumentation.log("dragIconToWorkspace: sent down");
         launcher.waitForLauncherObject(longPressIndicator);
         LauncherInstrumentation.log("dragIconToWorkspace: indicator");
-        launcher.movePointer(
-                downTime, SystemClock.uptimeMillis(), DRAG_DURATION, launchableCenter, dest);
+        launcher.movePointer(launchableCenter, dest, 10, downTime, true);
         LauncherInstrumentation.log("dragIconToWorkspace: moved pointer");
         launcher.sendPointer(
                 downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, dest);