Merge "Call into shell for recent tasks" into sc-v2-dev
diff --git a/quickstep/res/layout/rotate_suggestion.xml b/quickstep/res/layout/rotate_suggestion.xml
new file mode 100644
index 0000000..07cf0c8
--- /dev/null
+++ b/quickstep/res/layout/rotate_suggestion.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 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
+ -->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ >
+ <com.android.systemui.shared.rotation.FloatingRotationButtonView
+ android:id="@+id/rotate_suggestion"
+ android:layout_width="@dimen/floating_rotation_button_diameter"
+ android:layout_height="@dimen/floating_rotation_button_diameter"
+ android:paddingStart="@dimen/navigation_key_padding"
+ android:paddingEnd="@dimen/navigation_key_padding"
+ android:layout_gravity="bottom|left"
+ android:scaleType="center"
+ android:visibility="invisible" />
+</FrameLayout>
diff --git a/quickstep/res/values-sw600dp/dimens.xml b/quickstep/res/values-sw600dp/dimens.xml
new file mode 100644
index 0000000..5d9e059
--- /dev/null
+++ b/quickstep/res/values-sw600dp/dimens.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ * Copyright (c) 2021, 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.
+*/
+-->
+<resources>
+ <dimen name="navigation_key_padding">25dp</dimen>
+</resources>
diff --git a/quickstep/res/values-sw900dp/dimens.xml b/quickstep/res/values-sw900dp/dimens.xml
new file mode 100644
index 0000000..3efa5e3
--- /dev/null
+++ b/quickstep/res/values-sw900dp/dimens.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ * Copyright (c) 2021, 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.
+*/
+-->
+<resources>
+ <!-- The maximum width of the navigation bar ripples. -->
+ <dimen name="key_button_ripple_max_width">76dp</dimen>
+
+ <!-- The padding around the navigation buttons -->
+ <dimen name="navigation_key_padding">0dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 4ebf5cf..98d43f1 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -197,6 +197,19 @@
<!-- Minimum distance to swipe to trigger accessibility gesture -->
<dimen name="accessibility_gesture_min_swipe_distance">80dp</dimen>
+ <!-- The maximum width of the navigation bar ripples. -->
+ <dimen name="key_button_ripple_max_width">95dp</dimen>
+
+ <dimen name="rounded_corner_content_padding">0dp</dimen>
+
+ <dimen name="navigation_key_padding">0dp</dimen>
+
+ <!-- Floating rotation button -->
+ <dimen name="floating_rotation_button_diameter">40dp</dimen>
+ <dimen name="floating_rotation_button_min_margin">20dp</dimen>
+ <dimen name="floating_rotation_button_taskbar_left_margin">20dp</dimen>
+ <dimen name="floating_rotation_button_taskbar_bottom_margin">10dp</dimen>
+
<!-- Taskbar -->
<dimen name="taskbar_size">@*android:dimen/taskbar_frame_height</dimen>
<dimen name="taskbar_icon_touch_size">48dp</dimen>
diff --git a/quickstep/src/com/android/launcher3/LauncherInitListener.java b/quickstep/src/com/android/launcher3/LauncherInitListener.java
index 5fc79f0..35151f1 100644
--- a/quickstep/src/com/android/launcher3/LauncherInitListener.java
+++ b/quickstep/src/com/android/launcher3/LauncherInitListener.java
@@ -17,11 +17,8 @@
import android.animation.AnimatorSet;
import android.annotation.TargetApi;
-import android.content.Context;
-import android.content.Intent;
import android.os.Build;
import android.os.CancellationSignal;
-import android.os.Handler;
import com.android.quickstep.util.ActivityInitListener;
import com.android.quickstep.util.RemoteAnimationProvider;
@@ -78,11 +75,4 @@
mRemoteAnimationProvider = null;
super.unregister();
}
-
- @Override
- public void registerAndStartActivity(Intent intent, RemoteAnimationProvider animProvider,
- Context context, Handler handler, long duration) {
- mRemoteAnimationProvider = animProvider;
- super.registerAndStartActivity(intent, animProvider, context, handler, duration);
- }
}
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index 7e5bda5..2ccec44 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -285,7 +285,8 @@
long statusBarTransitionDelay = duration - STATUS_BAR_TRANSITION_DURATION
- STATUS_BAR_TRANSITION_PRE_DELAY;
RemoteAnimationAdapterCompat adapterCompat =
- new RemoteAnimationAdapterCompat(runner, duration, statusBarTransitionDelay);
+ new RemoteAnimationAdapterCompat(runner, duration, statusBarTransitionDelay,
+ mLauncher.getIApplicationThread());
return new ActivityOptionsWrapper(
ActivityOptionsCompat.makeRemoteAnimation(adapterCompat), onEndCallback);
}
@@ -1081,7 +1082,8 @@
new RemoteAnimationAdapterCompat(
new LauncherAnimationRunner(mHandler, mWallpaperOpenRunner,
false /* startAtFrontOfQueue */),
- CLOSING_TRANSITION_DURATION_MS, 0 /* statusBarTransitionDelay */));
+ CLOSING_TRANSITION_DURATION_MS, 0 /* statusBarTransitionDelay */,
+ mLauncher.getIApplicationThread()));
if (KEYGUARD_ANIMATION.get()) {
mKeyguardGoingAwayRunner = createWallpaperOpenRunner(true /* fromUnlock */);
@@ -1091,7 +1093,8 @@
new LauncherAnimationRunner(
mHandler, mKeyguardGoingAwayRunner,
true /* startAtFrontOfQueue */),
- CLOSING_TRANSITION_DURATION_MS, 0 /* statusBarTransitionDelay */));
+ CLOSING_TRANSITION_DURATION_MS, 0 /* statusBarTransitionDelay */,
+ mLauncher.getIApplicationThread()));
}
new ActivityCompat(mLauncher).registerRemoteAnimations(definition);
@@ -1109,7 +1112,7 @@
mWallpaperOpenTransitionRunner = createWallpaperOpenRunner(false /* fromUnlock */);
mLauncherOpenTransition = RemoteAnimationAdapterCompat.buildRemoteTransition(
new LauncherAnimationRunner(mHandler, mWallpaperOpenTransitionRunner,
- false /* startAtFrontOfQueue */));
+ false /* startAtFrontOfQueue */), mLauncher.getIApplicationThread());
mLauncherOpenTransition.addHomeOpenCheck(mLauncher.getComponentName());
SystemUiProxy.INSTANCE.getNoCreate().registerRemoteTransition(mLauncherOpenTransition);
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
index 11349bb..4b6dacd 100644
--- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
@@ -210,7 +210,15 @@
mControllers.rotationButtonController.setRotationButton(rotationButton, null);
} else {
mFloatingRotationButton = new FloatingRotationButton(mContext,
- R.string.accessibility_rotate_button);
+ R.string.accessibility_rotate_button,
+ R.layout.rotate_suggestion,
+ R.id.rotate_suggestion,
+ R.dimen.floating_rotation_button_min_margin,
+ R.dimen.rounded_corner_content_padding,
+ R.dimen.floating_rotation_button_taskbar_left_margin,
+ R.dimen.floating_rotation_button_taskbar_bottom_margin,
+ R.dimen.floating_rotation_button_diameter,
+ R.dimen.key_button_ripple_max_width);
mControllers.rotationButtonController.setRotationButton(mFloatingRotationButton,
mRotationButtonListener);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 72d9d5b..5bc454e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -20,6 +20,7 @@
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_OPEN;
+import static com.android.launcher3.testing.TestProtocol.TASKBAR_WINDOW_CRASH;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
import static com.android.systemui.shared.system.WindowManagerWrapper.ITYPE_BOTTOM_TAPPABLE_ELEMENT;
@@ -60,6 +61,7 @@
import com.android.launcher3.logger.LauncherAtom;
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.touch.ItemClickHandler;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.SettingsCache;
@@ -200,6 +202,9 @@
updateSysuiStateFlags(sharedState.sysuiStateFlags, true /* fromInit */);
mWindowManager.addView(mDragLayer, mWindowLayoutParams);
+ if (TestProtocol.sDebugTracing) {
+ Log.e(TASKBAR_WINDOW_CRASH, "Adding taskbar window");
+ }
}
public boolean isThreeButtonNav() {
@@ -330,6 +335,9 @@
setUIController(TaskbarUIController.DEFAULT);
mControllers.onDestroy();
mWindowManager.removeViewImmediate(mDragLayer);
+ if (TestProtocol.sDebugTracing) {
+ Log.e(TASKBAR_WINDOW_CRASH, "Removing taskbar window");
+ }
}
public void updateSysuiStateFlags(int systemUiStateFlags, boolean fromInit) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index 089c265..53feaad 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -17,6 +17,8 @@
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
+
+import static com.android.launcher3.testing.TestProtocol.TASKBAR_WINDOW_CRASH;
import static com.android.launcher3.util.DisplayController.CHANGE_ACTIVE_SCREEN;
import static com.android.launcher3.util.DisplayController.CHANGE_DENSITY;
import static com.android.launcher3.util.DisplayController.CHANGE_SUPPORTED_BOUNDS;
@@ -29,6 +31,7 @@
import android.hardware.display.DisplayManager;
import android.net.Uri;
import android.provider.Settings;
+import android.util.Log;
import android.view.Display;
import androidx.annotation.NonNull;
@@ -39,6 +42,7 @@
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.statemanager.StatefulActivity;
+import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.DisplayController.Info;
import com.android.launcher3.util.SettingsCache;
@@ -203,6 +207,10 @@
}
private void recreateTaskbar() {
+ if (TestProtocol.sDebugTracing) {
+ Log.e(TASKBAR_WINDOW_CRASH, "Recreating taskbar: mTaskbarActivityContext="
+ + mTaskbarActivityContext);
+ }
destroyExistingTaskbar();
DeviceProfile dp =
@@ -225,6 +233,9 @@
mTaskbarActivityContext.setUIController(
createTaskbarUIControllerForActivity(mActivity));
}
+ if (TestProtocol.sDebugTracing) {
+ Log.e(TASKBAR_WINDOW_CRASH, "Finished recreating taskbar");
+ }
}
public void onSystemUiFlagsChanged(int systemUiStateFlags) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
index 6fbef9b..a8a0b59 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
@@ -102,9 +102,7 @@
}
private void showIMESwitcher() {
- mService.getSystemService(InputMethodManager.class)
- .showInputMethodPickerFromSystem(true /* showAuxiliarySubtypes */,
- DEFAULT_DISPLAY);
+ SystemUiProxy.INSTANCE.getNoCreate().onImeSwitcherPressed();
}
private void notifyImeClick(boolean longClick) {
diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
index ad7e4df..09a0b7d 100644
--- a/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -245,7 +245,7 @@
RemoteAnimationAdapterCompat adapterCompat = new RemoteAnimationAdapterCompat(
wrapper, RECENTS_LAUNCH_DURATION,
RECENTS_LAUNCH_DURATION - STATUS_BAR_TRANSITION_DURATION
- - STATUS_BAR_TRANSITION_PRE_DELAY);
+ - STATUS_BAR_TRANSITION_PRE_DELAY, getIApplicationThread());
final ActivityOptionsWrapper activityOptions = new ActivityOptionsWrapper(
ActivityOptionsCompat.makeRemoteAnimation(adapterCompat),
onEndCallback);
@@ -394,7 +394,8 @@
LauncherAnimationRunner runner = new LauncherAnimationRunner(
getMainThreadHandler(), mAnimationToHomeFactory, true);
RemoteAnimationAdapterCompat adapterCompat =
- new RemoteAnimationAdapterCompat(runner, HOME_APPEAR_DURATION, 0);
+ new RemoteAnimationAdapterCompat(runner, HOME_APPEAR_DURATION, 0,
+ getIApplicationThread());
startActivity(createHomeIntent(),
ActivityOptionsCompat.makeRemoteAnimation(adapterCompat).toBundle());
}
diff --git a/quickstep/src/com/android/quickstep/RemoteTargetGluer.java b/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
index 825abed..5f2b49d 100644
--- a/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
+++ b/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
@@ -17,7 +17,6 @@
package com.android.quickstep;
import android.content.Context;
-import android.util.Log;
import androidx.annotation.Nullable;
@@ -33,8 +32,6 @@
* {@link TaskViewSimulator}
*/
public class RemoteTargetGluer {
- private static final String TAG = "RemoteTargetGluer";
-
private RemoteTargetHandle[] mRemoteTargetHandles;
private SplitConfigurationOptions.StagedSplitBounds mStagedSplitBounds;
@@ -94,25 +91,18 @@
public RemoteTargetHandle[] assignTargetsForSplitScreen(RemoteAnimationTargets targets) {
int[] splitIds = LauncherSplitScreenListener.INSTANCE.getNoCreate()
.getRunningSplitTaskIds();
- Log.d(TAG, "splitIds length: " + splitIds.length
- + " targetAppsLength: " + targets.apps.length
- + " remoteHandlesLength: " + mRemoteTargetHandles.length);
- if (splitIds.length == 0 && mRemoteTargetHandles.length > 1) {
- // There's a chance that between the creation of this class and assigning targets,
- // LauncherSplitScreenListener may have received callback that removes split
- mRemoteTargetHandles = new RemoteTargetHandle[]{mRemoteTargetHandles[0]};
- Log.w(TAG, "splitTaskIds changed between creation and assignment");
- }
RemoteAnimationTargetCompat primaryTaskTarget;
RemoteAnimationTargetCompat secondaryTaskTarget;
if (mRemoteTargetHandles.length == 1) {
// If we're not in split screen, the splitIds count doesn't really matter since we
- // should always hit this case. Right now there's no use case for multiple app targets
- // without being in split screen
- primaryTaskTarget = targets.apps[0];
+ // should always hit this case.
mRemoteTargetHandles[0].mTransformParams.setTargetSet(targets);
- mRemoteTargetHandles[0].mTaskViewSimulator.setPreview(primaryTaskTarget, null);
+ if (targets.apps.length > 0) {
+ // Unclear why/when target.apps length == 0, but it sure does happen :(
+ primaryTaskTarget = targets.apps[0];
+ mRemoteTargetHandles[0].mTaskViewSimulator.setPreview(primaryTaskTarget, null);
+ }
} else {
// split screen
primaryTaskTarget = targets.findTask(splitIds[0]);
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index 9cd206a..a875b69 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -39,6 +39,7 @@
import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
+import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.SplitConfigurationOptions;
import com.android.systemui.shared.recents.ISystemUiProxy;
@@ -125,6 +126,17 @@
}
@Override
+ public void onImeSwitcherPressed() {
+ if (mSystemUiProxy != null) {
+ try {
+ mSystemUiProxy.onImeSwitcherPressed();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed call onImeSwitcherPressed", e);
+ }
+ }
+ }
+
+ @Override
public void setHomeRotationEnabled(boolean enabled) {
if (mSystemUiProxy != null) {
try {
@@ -457,6 +469,8 @@
} catch (RemoteException e) {
Log.w(TAG, "Failed call handleImageBundleAsScreenshot");
}
+ } else if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.NO_SCREENSHOT, "sysuiproxy, no proxy available");
}
}
diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
index 4b89981..258a0c2 100644
--- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java
+++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
@@ -178,7 +178,8 @@
if (ENABLE_SHELL_TRANSITIONS) {
RemoteTransitionCompat transition = new RemoteTransitionCompat(mCallbacks,
- mController != null ? mController.getController() : null);
+ mController != null ? mController.getController() : null,
+ mCtx.getIApplicationThread());
Bundle options = ActivityOptionsCompat.makeRemoteTransition(transition)
.setTransientLaunch().toBundle();
mCtx.startActivity(intent, options);
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index a0b8abd..c037ac4 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -22,6 +22,7 @@
import static com.android.launcher3.config.FeatureFlags.ASSISTANT_GIVES_LAUNCHER_FOCUS;
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
+import static com.android.launcher3.testing.TestProtocol.TASKBAR_WINDOW_CRASH;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.quickstep.GestureState.DEFAULT_STATE;
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
@@ -354,6 +355,9 @@
@Override
public void onCreate() {
super.onCreate();
+ if (TestProtocol.sDebugTracing) {
+ Log.e(TASKBAR_WINDOW_CRASH, "TIS created");
+ }
// Initialize anything here that is needed in direct boot mode.
// Everything else should be initialized in onUserUnlocked() below.
mMainChoreographer = Choreographer.getInstance();
@@ -515,6 +519,9 @@
@Override
public void onDestroy() {
Log.d(TAG, "Touch service destroyed: user=" + getUserId());
+ if (TestProtocol.sDebugTracing) {
+ Log.e(TASKBAR_WINDOW_CRASH, "TIS destroyed");
+ }
sIsInitialized = false;
if (mDeviceState.isUserUnlocked()) {
mInputConsumer.unregisterInputConsumer();
diff --git a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
index fb6cd8a..49d8203 100644
--- a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
@@ -43,6 +43,13 @@
}
@Override
+ public Integer getSuccessFeedbackSubtitle() {
+ return mTutorialFragment.isAtFinalStep()
+ ? R.string.back_gesture_feedback_complete_without_follow_up
+ : R.string.back_gesture_feedback_complete_with_overview_follow_up;
+ }
+
+ @Override
protected int getMockAppTaskLayoutResId() {
return getMockAppTaskCurrentPageLayoutResId();
}
@@ -85,10 +92,7 @@
case BACK_COMPLETED_FROM_RIGHT:
mTutorialFragment.releaseFeedbackAnimation();
updateFakeAppTaskViewLayout(getMockAppTaskPreviousPageLayoutResId());
- int subtitleResId = mTutorialFragment.isAtFinalStep()
- ? R.string.back_gesture_feedback_complete_without_follow_up
- : R.string.back_gesture_feedback_complete_with_overview_follow_up;
- showFeedback(subtitleResId, true);
+ showSuccessFeedback();
break;
case BACK_CANCELLED_FROM_LEFT:
case BACK_CANCELLED_FROM_RIGHT:
diff --git a/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java b/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java
index 7fb7d29..c2524b1 100644
--- a/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java
+++ b/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java
@@ -35,10 +35,9 @@
/** Shows the gesture interactive sandbox in full screen mode. */
public class GestureSandboxActivity extends FragmentActivity {
- private static final String LOG_TAG = "GestureSandboxActivity";
-
private static final String KEY_TUTORIAL_STEPS = "tutorial_steps";
private static final String KEY_CURRENT_STEP = "current_step";
+ private static final String KEY_GESTURE_COMPLETE = "gesture_complete";
private TutorialType[] mTutorialSteps;
private TutorialType mCurrentTutorialStep;
@@ -56,7 +55,8 @@
Bundle args = savedInstanceState == null ? getIntent().getExtras() : savedInstanceState;
mTutorialSteps = getTutorialSteps(args);
mCurrentTutorialStep = mTutorialSteps[mCurrentStep - 1];
- mFragment = TutorialFragment.newInstance(mCurrentTutorialStep);
+ mFragment = TutorialFragment.newInstance(
+ mCurrentTutorialStep, args.getBoolean(KEY_GESTURE_COMPLETE, false));
getSupportFragmentManager().beginTransaction()
.add(R.id.gesture_tutorial_fragment_container, mFragment)
.commit();
@@ -87,6 +87,7 @@
protected void onSaveInstanceState(@NonNull Bundle savedInstanceState) {
savedInstanceState.putStringArray(KEY_TUTORIAL_STEPS, getTutorialStepNames());
savedInstanceState.putInt(KEY_CURRENT_STEP, mCurrentStep);
+ savedInstanceState.putBoolean(KEY_GESTURE_COMPLETE, mFragment.isGestureComplete());
super.onSaveInstanceState(savedInstanceState);
}
@@ -121,7 +122,7 @@
return;
}
mCurrentTutorialStep = mTutorialSteps[mCurrentStep];
- mFragment = TutorialFragment.newInstance(mCurrentTutorialStep);
+ mFragment = TutorialFragment.newInstance(mCurrentTutorialStep, false);
getSupportFragmentManager().beginTransaction()
.replace(R.id.gesture_tutorial_fragment_container, mFragment)
.runOnCommit(() -> mFragment.onAttachedToWindow())
diff --git a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
index bbb22e6..0bc3691 100644
--- a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
@@ -42,6 +42,13 @@
}
@Override
+ public Integer getSuccessFeedbackSubtitle() {
+ return mTutorialFragment.isAtFinalStep()
+ ? R.string.home_gesture_feedback_complete_without_follow_up
+ : R.string.home_gesture_feedback_complete_with_follow_up;
+ }
+
+ @Override
protected int getMockAppTaskLayoutResId() {
return mTutorialFragment.isLargeScreen()
? R.layout.gesture_tutorial_foldable_mock_webpage
@@ -84,10 +91,7 @@
case HOME_GESTURE_COMPLETED: {
mTutorialFragment.releaseFeedbackAnimation();
animateFakeTaskViewHome(finalVelocity, null);
- int subtitleResId = mTutorialFragment.isAtFinalStep()
- ? R.string.home_gesture_feedback_complete_without_follow_up
- : R.string.home_gesture_feedback_complete_with_follow_up;
- showFeedback(subtitleResId, true);
+ showSuccessFeedback();
break;
}
case HOME_NOT_STARTED_TOO_FAR_FROM_EDGE:
diff --git a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
index 0fea0d7..f308f27 100644
--- a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
@@ -52,6 +52,13 @@
}
@Override
+ public Integer getSuccessFeedbackSubtitle() {
+ return mTutorialFragment.getNumSteps() > 1 && mTutorialFragment.isAtFinalStep()
+ ? R.string.overview_gesture_feedback_complete_with_follow_up
+ : R.string.overview_gesture_feedback_complete_without_follow_up;
+ }
+
+ @Override
protected int getMockAppTaskLayoutResId() {
return mTutorialFragment.isLargeScreen()
? R.layout.gesture_tutorial_foldable_mock_conversation_list
@@ -106,11 +113,7 @@
mTutorialFragment.releaseFeedbackAnimation();
animateTaskViewToOverview();
onMotionPaused(true /*arbitrary value*/);
- int subtitleResId = mTutorialFragment.getNumSteps() > 1
- && mTutorialFragment.isAtFinalStep()
- ? R.string.overview_gesture_feedback_complete_with_follow_up
- : R.string.overview_gesture_feedback_complete_without_follow_up;
- showFeedback(subtitleResId, true);
+ showSuccessFeedback();
break;
case HOME_OR_OVERVIEW_NOT_STARTED_WRONG_SWIPE_DIRECTION:
case HOME_OR_OVERVIEW_CANCELLED:
diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialController.java b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
index 81e18f6..4145393 100644
--- a/quickstep/src/com/android/quickstep/interaction/TutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
@@ -223,6 +223,11 @@
return null;
}
+ @StringRes
+ public Integer getSuccessFeedbackSubtitle() {
+ return null;
+ }
+
void showFeedback() {
if (mGestureCompleted) {
mFeedbackView.setTranslationY(0);
@@ -236,6 +241,13 @@
}
/**
+ * Show feedback reflecting a successful gesture attempt.
+ **/
+ void showSuccessFeedback() {
+ showFeedback(getSuccessFeedbackSubtitle(), true);
+ }
+
+ /**
* Show feedback reflecting a failed gesture attempt.
*
* @param subtitleResId Resource of the text to display.
diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
index 89be1a6..2fd7cde 100644
--- a/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
+++ b/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
@@ -49,8 +49,10 @@
private static final String LOG_TAG = "TutorialFragment";
static final String KEY_TUTORIAL_TYPE = "tutorial_type";
+ static final String KEY_GESTURE_COMPLETE = "gesture_complete";
TutorialType mTutorialType;
+ boolean mGestureComplete = false;
@Nullable TutorialController mTutorialController = null;
RootSandboxLayout mRootView;
View mFingerDotView;
@@ -67,7 +69,7 @@
private boolean mIsLargeScreen;
- public static TutorialFragment newInstance(TutorialType tutorialType) {
+ public static TutorialFragment newInstance(TutorialType tutorialType, boolean gestureComplete) {
TutorialFragment fragment = getFragmentForTutorialType(tutorialType);
if (fragment == null) {
fragment = new BackGestureTutorialFragment();
@@ -76,6 +78,7 @@
Bundle args = new Bundle();
args.putSerializable(KEY_TUTORIAL_TYPE, tutorialType);
+ args.putBoolean(KEY_GESTURE_COMPLETE, gestureComplete);
fragment.setArguments(args);
return fragment;
}
@@ -132,6 +135,7 @@
super.onCreate(savedInstanceState);
Bundle args = savedInstanceState != null ? savedInstanceState : getArguments();
mTutorialType = (TutorialType) args.getSerializable(KEY_TUTORIAL_TYPE);
+ mGestureComplete = args.getBoolean(KEY_GESTURE_COMPLETE, false);
mEdgeBackGestureHandler = new EdgeBackGestureHandler(getContext());
mNavBarGestureHandler = new NavBarGestureHandler(getContext());
@@ -186,11 +190,13 @@
}
void initializeFeedbackVideoView() {
- if (!updateFeedbackAnimation()) {
+ if (!updateFeedbackAnimation() || mTutorialController == null) {
return;
}
- if (!mIntroductionShown && mTutorialController != null) {
+ if (isGestureComplete()) {
+ mTutorialController.showSuccessFeedback();
+ } else if (!mIntroductionShown) {
Integer introTileStringResId = mTutorialController.getIntroductionTitle();
Integer introSubtitleResId = mTutorialController.getIntroductionSubtitle();
if (introTileStringResId != null && introSubtitleResId != null) {
@@ -372,6 +378,11 @@
return getCurrentStep() == getNumSteps();
}
+ boolean isGestureComplete() {
+ return mGestureComplete
+ || (mTutorialController != null && mTutorialController.isGestureCompleted());
+ }
+
@Nullable
private GestureSandboxActivity getGestureSandboxActivity() {
Context context = getContext();
diff --git a/quickstep/src/com/android/quickstep/util/ActivityInitListener.java b/quickstep/src/com/android/quickstep/util/ActivityInitListener.java
index b9879ab..aeec36f 100644
--- a/quickstep/src/com/android/quickstep/util/ActivityInitListener.java
+++ b/quickstep/src/com/android/quickstep/util/ActivityInitListener.java
@@ -15,11 +15,6 @@
*/
package com.android.quickstep.util;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.Handler;
-
import com.android.launcher3.BaseActivity;
import com.android.launcher3.util.ActivityTracker;
import com.android.launcher3.util.ActivityTracker.SchedulerCallback;
@@ -75,17 +70,4 @@
mIsRegistered = false;
mOnInitListener = null;
}
-
- /**
- * Starts the given intent with the provided animation. Unlike {@link #register(Intent)}, this
- * method will not call {@link #init} if the activity already exists, it will only call it when
- * we get handleIntent() for the provided intent that we're starting.
- */
- public void registerAndStartActivity(Intent intent, RemoteAnimationProvider animProvider,
- Context context, Handler handler, long duration) {
- register();
-
- Bundle options = animProvider.toActivityOptions(handler, duration, context).toBundle();
- context.startActivity(new Intent(intent), options);
- }
}
diff --git a/quickstep/src/com/android/quickstep/util/ImageActionUtils.java b/quickstep/src/com/android/quickstep/util/ImageActionUtils.java
index de7dbd6..b0c68c5 100644
--- a/quickstep/src/com/android/quickstep/util/ImageActionUtils.java
+++ b/quickstep/src/com/android/quickstep/util/ImageActionUtils.java
@@ -49,6 +49,7 @@
import com.android.internal.app.ChooserActivity;
import com.android.launcher3.BuildConfig;
+import com.android.launcher3.testing.TestProtocol;
import com.android.quickstep.SystemUiProxy;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.utilities.BitmapUtil;
@@ -77,6 +78,9 @@
public static void saveScreenshot(SystemUiProxy systemUiProxy, Bitmap screenshot,
Rect screenshotBounds,
Insets visibleInsets, Task.TaskKey task) {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.NO_SCREENSHOT, "image action utils calling into sysuiproxy");
+ }
systemUiProxy.handleImageBundleAsScreenshot(BitmapUtil.hardwareBitmapToBundle(screenshot),
screenshotBounds, visibleInsets, task);
}
diff --git a/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java b/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java
index 98dbd47..ee82ae6 100644
--- a/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java
+++ b/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java
@@ -16,32 +16,14 @@
package com.android.quickstep.util;
import android.animation.AnimatorSet;
-import android.app.ActivityOptions;
-import android.content.Context;
-import android.os.Handler;
-import com.android.launcher3.LauncherAnimationRunner;
-import com.android.launcher3.LauncherAnimationRunner.RemoteAnimationFactory;
-import com.android.systemui.shared.system.ActivityOptionsCompat;
-import com.android.systemui.shared.system.RemoteAnimationAdapterCompat;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
public abstract class RemoteAnimationProvider {
- RemoteAnimationFactory mAnimationRunner;
-
public abstract AnimatorSet createWindowAnimation(RemoteAnimationTargetCompat[] appTargets,
RemoteAnimationTargetCompat[] wallpaperTargets);
- ActivityOptions toActivityOptions(Handler handler, long duration, Context context) {
- mAnimationRunner = (transit, appTargets, wallpaperTargets, nonApps, result) ->
- result.setAnimation(createWindowAnimation(appTargets, wallpaperTargets), context);
- final LauncherAnimationRunner wrapper = new LauncherAnimationRunner(
- handler, mAnimationRunner, false /* startAtFrontOfQueue */);
- return ActivityOptionsCompat.makeRemoteAnimation(
- new RemoteAnimationAdapterCompat(wrapper, duration, 0));
- }
-
/**
* @return the target with the lowest opaque layer for a certain app animation, or null.
*/
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index 1dae2c8..4c300ec 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -94,7 +94,8 @@
new RemoteSplitLaunchTransitionRunner(task1, task2);
mSystemUiProxy.startTasks(taskIds[0], null /* mainOptions */, taskIds[1],
null /* sideOptions */, STAGE_POSITION_BOTTOM_OR_RIGHT,
- new RemoteTransitionCompat(animationRunner, MAIN_EXECUTOR));
+ new RemoteTransitionCompat(animationRunner, MAIN_EXECUTOR,
+ ActivityThread.currentActivityThread().getApplicationThread()));
} else {
RemoteSplitLaunchAnimationRunner animationRunner =
new RemoteSplitLaunchAnimationRunner(task1, task2, callback);
diff --git a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
index 734c844..977c696 100644
--- a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
+++ b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
@@ -15,6 +15,7 @@
*/
package com.android.quickstep.util;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
import static com.android.launcher3.states.RotationHelper.deltaRotation;
import static com.android.launcher3.touch.PagedOrientationHandler.MATRIX_POST_TRANSLATE;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
@@ -99,6 +100,7 @@
private boolean mLayoutValid = false;
private int mOrientationStateId;
private StagedSplitBounds mStagedSplitBounds;
+ private boolean mDrawsBelowRecents;
public TaskViewSimulator(Context context, BaseActivityInterface sizeStrategy) {
mContext = context;
@@ -198,6 +200,10 @@
recentsViewScroll.value = scroll;
}
+ public void setDrawsBelowRecents(boolean drawsBelowRecents) {
+ mDrawsBelowRecents = drawsBelowRecents;
+ }
+
/**
* Adds animation for all the components corresponding to transition from an app to overview.
*/
@@ -351,6 +357,12 @@
builder.withMatrix(mMatrix)
.withWindowCrop(mTmpCropRect)
.withCornerRadius(getCurrentCornerRadius());
+
+ if (ENABLE_QUICKSTEP_LIVE_TILE.get() && params.getRecentsSurface() != null) {
+ // When relativeLayer = 0, it reverts the surfaces back to the original order.
+ builder.withRelativeLayerTo(params.getRecentsSurface(),
+ mDrawsBelowRecents ? Integer.MIN_VALUE : 0);
+ }
}
/**
diff --git a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
index 76d3591..5a8cbc1 100644
--- a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
+++ b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
@@ -20,6 +20,7 @@
import android.content.res.Configuration;
import android.graphics.Rect;
import android.util.AttributeSet;
+import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.FrameLayout;
@@ -30,6 +31,7 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Insettable;
import com.android.launcher3.R;
+import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.util.MultiValueAlpha;
import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
import com.android.quickstep.SysUINavigationMode;
@@ -110,6 +112,11 @@
protected void onFinishInflate() {
super.onFinishInflate();
findViewById(R.id.action_screenshot).setOnClickListener(this);
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.NO_SCREENSHOT, "Inflated OverviewActionsView and added screenshot"
+ + " listener.");
+ }
+
mSplitButton = findViewById(R.id.action_split);
mSplitButton.setOnClickListener(this);
}
@@ -125,6 +132,11 @@
@Override
public void onClick(View view) {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.NO_SCREENSHOT, "OverviewActionsView - onClick"
+ + " callbacks: " + mCallbacks + " view id: " + view.getId() + " "
+ + " is screenshot? " + (view.getId() == R.id.action_screenshot));
+ }
if (mCallbacks == null) {
return;
}
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 48f8619..b5238c6 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -1914,8 +1914,10 @@
}
}
setEnableDrawingLiveTile(false);
- runActionOnRemoteHandles(remoteTargetHandle -> remoteTargetHandle.getTransformParams()
- .setTargetSet(null));
+ runActionOnRemoteHandles(remoteTargetHandle -> {
+ remoteTargetHandle.getTransformParams().setTargetSet(null);
+ remoteTargetHandle.getTaskViewSimulator().setDrawsBelowRecents(true);
+ });
// These are relatively expensive and don't need to be done this frame (RecentsView isn't
// visible anyway), so defer by a frame to get off the critical path, e.g. app to home.
@@ -4371,12 +4373,13 @@
TaskViewSimulator tvs = remoteTargetHandle.getTaskViewSimulator();
tvs.setOrientationState(mOrientationState);
tvs.setDp(mActivity.getDeviceProfile());
+ tvs.setDrawsBelowRecents(true);
tvs.recentsViewScale.value = 1;
}
}
/** Helper to avoid writing some for-loops to iterate over {@link #mRemoteTargetHandles} */
- private void runActionOnRemoteHandles(Consumer<RemoteTargetHandle> consumer) {
+ public void runActionOnRemoteHandles(Consumer<RemoteTargetHandle> consumer) {
if (mRemoteTargetHandles == null) {
return;
}
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuView.java b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
index 5c73fbb..77ac373 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
@@ -16,6 +16,7 @@
package com.android.quickstep.views;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_UNDEFINED;
import static com.android.quickstep.views.TaskThumbnailView.DIM_ALPHA;
@@ -242,7 +243,17 @@
LayoutParams lp = (LayoutParams) menuOptionView.getLayoutParams();
mTaskView.getPagedOrientationHandler().setLayoutParamsForTaskMenuOptionItem(lp,
menuOptionView, mActivity.getDeviceProfile());
- menuOptionView.setOnClickListener(menuOption::onClick);
+ menuOptionView.setOnClickListener(view -> {
+ if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
+ RecentsView recentsView = mTaskView.getRecentsView();
+ recentsView.switchToScreenshot(null,
+ () -> recentsView.finishRecentsAnimation(true /* toRecents */,
+ false /* shouldPip */,
+ () -> menuOption.onClick(view)));
+ } else {
+ menuOption.onClick(view);
+ }
+ });
mOptionLayout.addView(menuOptionView);
}
diff --git a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
index a9db400..2d58ba5 100644
--- a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
@@ -31,6 +31,8 @@
import android.graphics.Insets;
import android.graphics.Matrix;
import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
@@ -78,6 +80,7 @@
private TaskOverlay mOverlay;
private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private final Paint mBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ private final Paint mClearPaint = new Paint();
private final Paint mDimmingPaintAfterClearing = new Paint();
private final int mDimColor;
@@ -107,6 +110,7 @@
super(context, attrs, defStyleAttr);
mPaint.setFilterBitmap(true);
mBackgroundPaint.setColor(Color.WHITE);
+ mClearPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
mActivity = BaseActivity.fromContext(context);
// Initialize with placeholder value. It is overridden later by TaskView
mFullscreenParams = TEMP_PARAMS.get(context);
@@ -271,6 +275,7 @@
float cornerRadius) {
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
if (mTask != null && getTaskView().isRunningTask() && !getTaskView().showScreenshot()) {
+ canvas.drawRoundRect(x, y, width, height, cornerRadius, cornerRadius, mClearPaint);
canvas.drawRoundRect(x, y, width, height, cornerRadius, cornerRadius,
mDimmingPaintAfterClearing);
return;
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index eef5fb3..f88b243 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -94,6 +94,7 @@
import com.android.quickstep.util.LauncherSplitScreenListener;
import com.android.quickstep.util.RecentsOrientedState;
import com.android.quickstep.util.TaskCornerRadius;
+import com.android.quickstep.util.TaskViewSimulator;
import com.android.quickstep.util.TransformParams;
import com.android.quickstep.views.TaskThumbnailView.PreviewPositionHelper;
import com.android.systemui.shared.recents.model.Task;
@@ -625,7 +626,21 @@
recentsView.getDepthController());
anim.addListener(new AnimatorListenerAdapter() {
@Override
+ public void onAnimationStart(Animator animator) {
+ recentsView.runActionOnRemoteHandles(
+ (Consumer<RemoteTargetHandle>) remoteTargetHandle ->
+ remoteTargetHandle
+ .getTaskViewSimulator()
+ .setDrawsBelowRecents(false));
+ }
+
+ @Override
public void onAnimationEnd(Animator animator) {
+ recentsView.runActionOnRemoteHandles(
+ (Consumer<RemoteTargetHandle>) remoteTargetHandle ->
+ remoteTargetHandle
+ .getTaskViewSimulator()
+ .setDrawsBelowRecents(true));
mIsClickableAsLiveTile = true;
}
});
@@ -821,15 +836,7 @@
if (confirmSecondSplitSelectApp()) {
return;
}
- if (ENABLE_QUICKSTEP_LIVE_TILE.get() && isRunningTask()) {
- RecentsView recentsView = getRecentsView();
- recentsView.switchToScreenshot(
- () -> recentsView.finishRecentsAnimation(true /* toRecents */,
- false /* shouldPip */,
- () -> showTaskMenu(iconView)));
- } else {
- showTaskMenu(iconView);
- }
+ showTaskMenu(iconView);
});
iconView.setOnLongClickListener(v -> {
requestDisallowInterceptTouchEvent(true);
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index 4895b10..ea65757 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -31,6 +31,7 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
+import com.android.launcher3.tapl.AllApps;
import com.android.launcher3.tapl.Background;
import com.android.launcher3.tapl.LauncherInstrumentation.NavigationModel;
import com.android.launcher3.tapl.Overview;
@@ -43,12 +44,16 @@
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@LargeTest
@RunWith(AndroidJUnit4.class)
public class TaplTestsQuickstep extends AbstractQuickStepTest {
+
+ private static final String APP_NAME = "LauncherTestApp";
+
@Before
public void setUp() throws Exception {
super.setUp();
@@ -286,6 +291,31 @@
getAndAssertBackground();
}
+ // TODO(b/204830798): test with all navigation modes(add @NavigationModeSwitch annotation)
+ // after the bug resolved.
+ @Ignore("b/205027405")
+ @Test
+ @PortraitLandscape
+ @ScreenRecord
+ public void testPressBack() throws Exception {
+ mLauncher.getWorkspace().switchToAllApps();
+ mLauncher.pressBack();
+ mLauncher.getWorkspace();
+ waitForState("Launcher internal state didn't switch to Home", () -> LauncherState.NORMAL);
+
+ AllApps allApps = mLauncher.getWorkspace().switchToAllApps();
+ allApps.freeze();
+ try {
+ allApps.getAppIcon(APP_NAME).dragToWorkspace(false, false);
+ } finally {
+ allApps.unfreeze();
+ }
+ mLauncher.getWorkspace().getWorkspaceAppIcon(APP_NAME).launch(getAppPackageName());
+ mLauncher.pressBack();
+ mLauncher.getWorkspace();
+ waitForState("Launcher internal state didn't switch to Home", () -> LauncherState.NORMAL);
+ }
+
@Test
@PortraitLandscape
public void testOverviewForTablet() throws Exception {
diff --git a/res/layout/all_apps.xml b/res/layout/all_apps.xml
index a34baef..7f9f63e 100644
--- a/res/layout/all_apps.xml
+++ b/res/layout/all_apps.xml
@@ -43,15 +43,6 @@
<include layout="@layout/all_apps_personal_work_tabs" />
- <Button
- android:id="@+id/all_apps_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:text="@string/all_apps_label"
- android:background="@drawable/padded_rounded_action_button"
- android:visibility="gone"/>
-
</com.android.launcher3.allapps.FloatingHeaderView>
<include layout="@layout/search_container_all_apps" />
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index fc717c9..ce06c6e 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -329,6 +329,7 @@
}
updateWorkspaceScreensPadding();
+ updateWorkspaceWidgetsSizes();
}
private void updateWorkspaceScreensPadding() {
@@ -360,6 +361,25 @@
}
}
+ private void updateWorkspaceWidgetsSizes() {
+ int numberOfScreens = mScreenOrder.size();
+ for (int i = 0; i < numberOfScreens; i++) {
+ ShortcutAndWidgetContainer shortcutAndWidgetContainer =
+ mWorkspaceScreens.get(mScreenOrder.get(i)).getShortcutsAndWidgets();
+ int shortcutsAndWidgetCount = shortcutAndWidgetContainer.getChildCount();
+ for (int j = 0; j < shortcutsAndWidgetCount; j++) {
+ View view = shortcutAndWidgetContainer.getChildAt(j);
+ if (view instanceof LauncherAppWidgetHostView
+ && view.getTag() instanceof LauncherAppWidgetInfo) {
+ LauncherAppWidgetInfo launcherAppWidgetInfo =
+ (LauncherAppWidgetInfo) view.getTag();
+ WidgetSizes.updateWidgetSizeRanges((LauncherAppWidgetHostView) view,
+ mLauncher, launcherAppWidgetInfo.spanX, launcherAppWidgetInfo.spanY);
+ }
+ }
+ }
+ }
+
/**
* Estimates the size of an item using spans: hSpan, vSpan.
*
diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
index 874fe80..f089551 100644
--- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
+++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
@@ -42,6 +42,7 @@
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.R;
import com.android.launcher3.model.data.AppInfo;
+import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.util.PackageManagerHelper;
import java.util.Arrays;
@@ -95,16 +96,15 @@
// The type of this item
public int viewType;
- /** App-only properties */
- // The section name of this app. Note that there can be multiple items with different
+ // The section name of this item. Note that there can be multiple items with different
// sectionNames in the same section
public String sectionName = null;
// The row that this item shows up on
public int rowIndex;
// The index of this app in the row
public int rowAppIndex;
- // The associated AppInfo for the app
- public AppInfo appInfo = null;
+ // The associated ItemInfoWithIcon for the item
+ public ItemInfoWithIcon itemInfo = null;
// The index of this app not including sections
public int appIndex = -1;
// Search section associated to result
@@ -119,7 +119,7 @@
item.viewType = VIEW_TYPE_ICON;
item.position = pos;
item.sectionName = sectionName;
- item.appInfo = appInfo;
+ item.itemInfo = appInfo;
item.appIndex = appIndex;
return item;
}
@@ -373,7 +373,7 @@
if (adapterProvider != null) {
return adapterProvider.onCreateViewHolder(mLayoutInflater, parent, viewType);
}
- throw new RuntimeException("Unexpected view type");
+ throw new RuntimeException("Unexpected view type" + viewType);
}
}
@@ -382,10 +382,13 @@
switch (holder.getItemViewType()) {
case VIEW_TYPE_ICON:
AdapterItem adapterItem = mApps.getAdapterItems().get(position);
- AppInfo info = adapterItem.appInfo;
BubbleTextView icon = (BubbleTextView) holder.itemView;
icon.reset();
- icon.applyFromApplicationInfo(info);
+ if (adapterItem.itemInfo instanceof AppInfo) {
+ icon.applyFromApplicationInfo((AppInfo) adapterItem.itemInfo);
+ } else {
+ icon.applyFromItemInfoWithIcon(adapterItem.itemInfo);
+ }
break;
case VIEW_TYPE_EMPTY_SEARCH:
TextView emptyViewText = (TextView) holder.itemView;
diff --git a/src/com/android/launcher3/allapps/FloatingHeaderView.java b/src/com/android/launcher3/allapps/FloatingHeaderView.java
index 3ca0303..85ee636 100644
--- a/src/com/android/launcher3/allapps/FloatingHeaderView.java
+++ b/src/com/android/launcher3/allapps/FloatingHeaderView.java
@@ -47,7 +47,6 @@
ValueAnimator.AnimatorUpdateListener, PluginListener<AllAppsRow>, Insettable,
OnHeightUpdatedListener {
- private static final long ALL_APPS_CONTENT_ANIM_DURATION = 150;
private final Rect mRVClip = new Rect(0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE);
private final Rect mHeaderClip = new Rect(0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE);
private final ValueAnimator mAnimator = ValueAnimator.ofInt(0, 0);
@@ -110,13 +109,6 @@
private FloatingHeaderRow[] mAllRows = FloatingHeaderRow.NO_ROWS;
- // members for handling suggestion state
- private final ValueAnimator mAllAppsContentAnimator = ValueAnimator.ofFloat(0, 0);
- private View mAllAppsButton;
- private int mAllAppsContentFadeInOffset;
- private boolean mInSuggestionMode = false;
-
-
public FloatingHeaderView(@NonNull Context context) {
this(context, null);
}
@@ -127,20 +119,12 @@
.getDimensionPixelSize(R.dimen.all_apps_header_top_padding);
mHeaderProtectionSupported = context.getResources().getBoolean(
R.bool.config_header_protection_supported);
- mAllAppsContentFadeInOffset = context.getResources()
- .getDimensionPixelSize(R.dimen.all_apps_content_fade_in_offset);
- mAllAppsContentAnimator.setDuration(ALL_APPS_CONTENT_ANIM_DURATION);
- mAllAppsContentAnimator.addUpdateListener(this::onAllAppsContentAnimationUpdate);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mTabLayout = findViewById(R.id.tabs);
- mAllAppsButton = findViewById(R.id.all_apps_button);
- if (mAllAppsButton != null) {
- mAllAppsButton.setOnClickListener(this::onAllAppsButtonClicked);
- }
// Find all floating header rows.
ArrayList<FloatingHeaderRow> rows = new ArrayList<>();
@@ -329,7 +313,6 @@
}
mTabLayout.setTranslationY(mTranslationY);
- setSuggestionMode(false);
int clipHeight = mHeaderTopPadding - getPaddingBottom();
mRVClip.top = mTabsHidden ? clipHeight : 0;
@@ -365,7 +348,6 @@
mTranslationY = 0;
applyVerticalMove();
}
- setSuggestionMode(false);
mHeaderCollapsed = false;
mSnappedScrolledY = -mMaxTranslation;
mCurrentRV.scrollToTop();
@@ -461,38 +443,6 @@
}
return Math.max(getHeight() - getPaddingTop() + mTranslationY, 0);
}
-
- /**
- * When suggestion mode is enabled, hides AllApps content view and shows AllApps button.
- */
- public void setSuggestionMode(boolean isSuggestMode) {
- if (mInSuggestionMode == isSuggestMode || mAllAppsButton == null) return;
- if (!FeatureFlags.ENABLE_ONE_SEARCH.get()) return;
- AllAppsContainerView allApps = (AllAppsContainerView) getParent();
- mInSuggestionMode = isSuggestMode;
- if (isSuggestMode) {
- mTabLayout.setVisibility(GONE);
- mAllAppsButton.setVisibility(VISIBLE);
- allApps.getContentView().setVisibility(GONE);
- } else {
- mTabLayout.setVisibility(mTabsHidden ? GONE : VISIBLE);
- mAllAppsButton.setVisibility(GONE);
- allApps.getContentView().setVisibility(VISIBLE);
- }
- }
-
- private void onAllAppsButtonClicked(View view) {
- setSuggestionMode(false);
- mAllAppsContentAnimator.start();
- }
-
- private void onAllAppsContentAnimationUpdate(ValueAnimator valueAnimator) {
- float prog = valueAnimator.getAnimatedFraction();
- View allAppsList = ((AllAppsContainerView) getParent()).getContentView();
- allAppsList.setAlpha(255 * prog);
- allAppsList.setTranslationY((1 - prog) * mAllAppsContentFadeInOffset);
- }
-
}
diff --git a/src/com/android/launcher3/compat/AccessibilityManagerCompat.java b/src/com/android/launcher3/compat/AccessibilityManagerCompat.java
index 97052b2..dd58123 100644
--- a/src/com/android/launcher3/compat/AccessibilityManagerCompat.java
+++ b/src/com/android/launcher3/compat/AccessibilityManagerCompat.java
@@ -41,11 +41,10 @@
}
/**
- *
* @param target The view the accessibility event is initialized on.
* If null, this method has no effect.
- * @param type See TYPE_ constants defined in {@link AccessibilityEvent}.
- * @param text Optional text to add to the event, which will be announced to the user.
+ * @param type See TYPE_ constants defined in {@link AccessibilityEvent}.
+ * @param text Optional text to add to the event, which will be announced to the user.
*/
public static void sendCustomAccessibilityEvent(@Nullable View target, int type,
@Nullable String text) {
@@ -97,6 +96,16 @@
null);
}
+ /**
+ * Notify running tests of a folder opened.
+ */
+ public static void sendFolderOpenedEventToTest(Context context) {
+ final AccessibilityManager accessibilityManager = getAccessibilityManagerForTest(context);
+ if (accessibilityManager == null) return;
+
+ sendEventToTest(accessibilityManager, context, TestProtocol.FOLDER_OPENED_MESSAGE, null);
+ }
+
private static void sendEventToTest(
AccessibilityManager accessibilityManager,
Context context, String eventTag, Bundle data) {
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index 879739f..daef682 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -78,6 +78,7 @@
import com.android.launcher3.accessibility.AccessibleDragListenerAdapter;
import com.android.launcher3.accessibility.FolderAccessibilityHelper;
import com.android.launcher3.anim.KeyboardInsetAnimationCallback;
+import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dragndrop.DragController;
import com.android.launcher3.dragndrop.DragController.DragListener;
@@ -687,6 +688,7 @@
public void onAnimationEnd(Animator animation) {
mState = STATE_OPEN;
announceAccessibilityChanges();
+ AccessibilityManagerCompat.sendFolderOpenedEventToTest(getContext());
mContent.setFocusOnFirstChild();
}
@@ -1265,7 +1267,8 @@
PendingAddShortcutInfo pasi = d.dragInfo instanceof PendingAddShortcutInfo
? (PendingAddShortcutInfo) d.dragInfo : null;
- WorkspaceItemInfo pasiSi = pasi != null ? pasi.activityInfo.createWorkspaceItemInfo() : null;
+ WorkspaceItemInfo pasiSi =
+ pasi != null ? pasi.activityInfo.createWorkspaceItemInfo() : null;
if (pasi != null && pasiSi == null) {
// There is no WorkspaceItemInfo, so we have to go through a configuration activity.
pasi.container = mInfo.id;
diff --git a/src/com/android/launcher3/model/data/ItemInfo.java b/src/com/android/launcher3/model/data/ItemInfo.java
index 97398de..b72f462 100644
--- a/src/com/android/launcher3/model/data/ItemInfo.java
+++ b/src/com/android/launcher3/model/data/ItemInfo.java
@@ -373,7 +373,7 @@
protected LauncherAtom.ItemInfo.Builder getDefaultItemInfoBuilder() {
LauncherAtom.ItemInfo.Builder itemBuilder = LauncherAtom.ItemInfo.newBuilder();
- itemBuilder.setIsWork(user != Process.myUserHandle());
+ itemBuilder.setIsWork(!Process.myUserHandle().equals(user));
return itemBuilder;
}
diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java
index 5a9c074..17d925c 100644
--- a/src/com/android/launcher3/testing/TestInformationHandler.java
+++ b/src/com/android/launcher3/testing/TestInformationHandler.java
@@ -21,6 +21,7 @@
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
+import android.content.res.Resources;
import android.graphics.Insets;
import android.os.Build;
import android.os.Bundle;
@@ -148,6 +149,14 @@
TestProtocol.TEST_INFO_RESPONSE_FIELD, TestLogging.sHadEventsNotFromTest);
return response;
+ case TestProtocol.REQUEST_START_DRAG_THRESHOLD: {
+ final Resources resources = mContext.getResources();
+ response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD,
+ resources.getDimensionPixelSize(R.dimen.deep_shortcuts_start_drag_threshold)
+ + resources.getDimensionPixelSize(R.dimen.pre_drag_view_scale));
+ return response;
+ }
+
default:
return null;
}
@@ -193,6 +202,7 @@
/**
* Generic interface for setting a fiend in bundle
+ *
* @param <T> the type of value being set
*/
public interface BundleSetter<T> {
diff --git a/src/com/android/launcher3/testing/TestProtocol.java b/src/com/android/launcher3/testing/TestProtocol.java
index 5bf0342..91c7221 100644
--- a/src/com/android/launcher3/testing/TestProtocol.java
+++ b/src/com/android/launcher3/testing/TestProtocol.java
@@ -25,6 +25,7 @@
public static final String SCROLL_FINISHED_MESSAGE = "TAPL_SCROLL_FINISHED";
public static final String PAUSE_DETECTED_MESSAGE = "TAPL_PAUSE_DETECTED";
public static final String DISMISS_ANIMATION_ENDS_MESSAGE = "TAPL_DISMISS_ANIMATION_ENDS";
+ public static final String FOLDER_OPENED_MESSAGE = "TAPL_FOLDER_OPENED";
public static final int NORMAL_STATE_ORDINAL = 0;
public static final int SPRING_LOADED_STATE_ORDINAL = 1;
public static final int OVERVIEW_STATE_ORDINAL = 2;
@@ -99,6 +100,7 @@
public static final String REQUEST_CLEAR_DATA = "clear-data";
public static final String REQUEST_IS_TABLET = "is-tablet";
public static final String REQUEST_IS_TWO_PANELS = "is-two-panel";
+ public static final String REQUEST_START_DRAG_THRESHOLD = "start-drag-threshold";
public static final String REQUEST_GET_ACTIVITIES_CREATED_COUNT =
"get-activities-created-count";
public static final String REQUEST_GET_ACTIVITIES = "get-activities";
@@ -119,7 +121,9 @@
public static final String REQUEST_MOCK_SENSOR_ROTATION = "mock-sensor-rotation";
public static final String PERMANENT_DIAG_TAG = "TaplTarget";
+ public static final String TASKBAR_WINDOW_CRASH = "b/201305599";
public static final String TASK_VIEW_ID_CRASH = "b/195430732";
public static final String NO_DROP_TARGET = "b/195031154";
public static final String NULL_INT_SET = "b/200572078";
+ public static final String NO_SCREENSHOT = "b/202414125";
}
diff --git a/src/com/android/launcher3/widget/DeferredAppWidgetHostView.java b/src/com/android/launcher3/widget/DeferredAppWidgetHostView.java
index 9c32e42..57f8bc7 100644
--- a/src/com/android/launcher3/widget/DeferredAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/DeferredAppWidgetHostView.java
@@ -16,6 +16,7 @@
package com.android.launcher3.widget;
+import android.annotation.SuppressLint;
import android.appwidget.AppWidgetProviderInfo;
import android.content.Context;
import android.graphics.Canvas;
@@ -30,6 +31,9 @@
import com.android.launcher3.R;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
/**
* A widget host views created while the host has not bind to the system service.
*/
@@ -75,8 +79,22 @@
&& mSetupTextLayout.getWidth() == availableWidth) {
return;
}
- mSetupTextLayout = new StaticLayout(info.label, mPaint, availableWidth,
- Layout.Alignment.ALIGN_CENTER, 1, 0, true);
+ try {
+ mSetupTextLayout = new StaticLayout(info.label, mPaint, availableWidth,
+ Layout.Alignment.ALIGN_CENTER, 1, 0, true);
+ } catch (IllegalArgumentException e) {
+ @SuppressLint("DrawAllocation") StringWriter stringWriter = new StringWriter();
+ @SuppressLint("DrawAllocation") PrintWriter printWriter = new PrintWriter(stringWriter);
+ mActivity.getDeviceProfile().dump(/*prefix=*/"", printWriter);
+ printWriter.flush();
+ String message = "b/203530620 "
+ + "- availableWidth: " + availableWidth
+ + ", getMeasuredWidth: " + getMeasuredWidth()
+ + ", getPaddingLeft: " + getPaddingLeft()
+ + ", getPaddingRight: " + getPaddingRight()
+ + ", deviceProfile: " + stringWriter.toString();
+ throw new IllegalArgumentException(message, e);
+ }
}
@Override
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 0ffbeeb..b3457cd 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -211,7 +211,8 @@
}
protected TestRule getRulesInsideActivityMonitor() {
- final RuleChain inner = RuleChain.outerRule(new PortraitLandscapeRunner(this))
+ final RuleChain inner = RuleChain
+ .outerRule(new PortraitLandscapeRunner(this))
.around(new FailureWatcher(mDevice, mLauncher));
return TestHelpers.isInLauncherProcess()
@@ -345,13 +346,19 @@
}
// Cannot be used in TaplTests between a Tapl call injecting a gesture and a tapl call
- // expecting
- // the results of that gesture because the wait can hide flakeness.
+ // expecting the results of that gesture because the wait can hide flakeness.
protected void waitForState(String message, Supplier<LauncherState> state) {
waitForLauncherCondition(message,
launcher -> launcher.getStateManager().getCurrentStableState() == state.get());
}
+ // Cannot be used in TaplTests between a Tapl call injecting a gesture and a tapl call
+ // expecting the results of that gesture because the wait can hide flakeness.
+ protected void waitForStableState(String message, Supplier<LauncherState> state) {
+ waitForLauncherCondition(message,
+ launcher -> launcher.getStateManager().isInStableState(state.get()));
+ }
+
protected void waitForResumed(String message) {
waitForLauncherCondition(message, launcher -> launcher.hasBeenResumed());
}
diff --git a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
index 881f50c..f29ac23 100644
--- a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
+++ b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
@@ -34,6 +34,8 @@
import com.android.launcher3.tapl.AppIcon;
import com.android.launcher3.tapl.AppIconMenu;
import com.android.launcher3.tapl.AppIconMenuItem;
+import com.android.launcher3.tapl.Folder;
+import com.android.launcher3.tapl.FolderIcon;
import com.android.launcher3.tapl.Widgets;
import com.android.launcher3.tapl.Workspace;
import com.android.launcher3.views.OptionsPopupView;
@@ -369,6 +371,71 @@
}
}
+ private AppIcon createShortcutIfNotExist(String name) {
+ AppIcon appIcon = mLauncher.getWorkspace().tryGetWorkspaceAppIcon(name);
+ if (appIcon == null) {
+ AllApps allApps = mLauncher.getWorkspace().switchToAllApps();
+ allApps.freeze();
+ try {
+ appIcon = allApps.getAppIcon(name);
+ appIcon.dragToWorkspace(false, false);
+ } finally {
+ allApps.unfreeze();
+ }
+ appIcon = mLauncher.getWorkspace().getWorkspaceAppIcon(name);
+ }
+ return appIcon;
+ }
+
+ @Ignore("b/205014516")
+ @Test
+ @PortraitLandscape
+ public void testDragToFolder() throws Exception {
+ final AppIcon playStoreIcon = createShortcutIfNotExist("Play Store");
+ final AppIcon gmailIcon = createShortcutIfNotExist("Gmail");
+
+ FolderIcon folderIcon = gmailIcon.dragToIcon(playStoreIcon);
+
+ Folder folder = folderIcon.open();
+ folder.getAppIcon("Play Store");
+ folder.getAppIcon("Gmail");
+ Workspace workspace = folder.close();
+
+ assertNull("Gmail should be moved to a folder.",
+ workspace.tryGetWorkspaceAppIcon("Gmail"));
+ assertNull("Play Store should be moved to a folder.",
+ workspace.tryGetWorkspaceAppIcon("Play Store"));
+
+ final AppIcon youTubeIcon = createShortcutIfNotExist("YouTube");
+
+ folderIcon = youTubeIcon.dragToIcon(folderIcon);
+ folder = folderIcon.open();
+ folder.getAppIcon("YouTube");
+ folder.close();
+ }
+
+ @Ignore("b/205027405")
+ @Test
+ @PortraitLandscape
+ public void testPressBack() throws Exception {
+ mLauncher.getWorkspace().switchToAllApps();
+ mLauncher.pressBack();
+ mLauncher.getWorkspace();
+ waitForState("Launcher internal state didn't switch to Home", () -> LauncherState.NORMAL);
+
+ AllApps allApps = mLauncher.getWorkspace().switchToAllApps();
+ allApps.freeze();
+ try {
+ allApps.getAppIcon(APP_NAME).dragToWorkspace(false, false);
+ } finally {
+ allApps.unfreeze();
+ }
+ mLauncher.getWorkspace().getWorkspaceAppIcon(APP_NAME).launch(getAppPackageName());
+ mLauncher.pressBack();
+ mLauncher.getWorkspace();
+ waitForState("Launcher internal state didn't switch to Home", () -> LauncherState.NORMAL);
+ }
+
public static String getAppPackageName() {
return getInstrumentation().getContext().getPackageName();
}
diff --git a/tests/src/com/android/launcher3/ui/WorkProfileTest.java b/tests/src/com/android/launcher3/ui/WorkProfileTest.java
index 41cdf0f..2087bfe 100644
--- a/tests/src/com/android/launcher3/ui/WorkProfileTest.java
+++ b/tests/src/com/android/launcher3/ui/WorkProfileTest.java
@@ -32,6 +32,7 @@
import com.android.launcher3.allapps.WorkEduCard;
import com.android.launcher3.allapps.WorkProfileManager;
import com.android.launcher3.tapl.LauncherInstrumentation;
+import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
import org.junit.After;
import org.junit.Before;
@@ -86,12 +87,13 @@
}
@Test
+ @ScreenRecord // b/202735477
public void workTabExists() {
mDevice.pressHome();
waitForLauncherCondition("Launcher didn't start", Objects::nonNull);
- waitForState("Launcher internal state didn't switch to Normal", () -> NORMAL);
+ waitForStableState("Launcher internal state didn't switch to Normal", () -> NORMAL);
executeOnLauncher(launcher -> launcher.getStateManager().goToState(ALL_APPS));
- waitForState("Launcher internal state didn't switch to All Apps", () -> ALL_APPS);
+ waitForStableState("Launcher internal state didn't switch to All Apps", () -> ALL_APPS);
waitForLauncherCondition("Personal tab is missing",
launcher -> launcher.getAppsView().isPersonalTabVisible(),
LauncherInstrumentation.WAIT_TIME_MS);
diff --git a/tests/tapl/com/android/launcher3/tapl/AppIcon.java b/tests/tapl/com/android/launcher3/tapl/AppIcon.java
index 21099b4..6da59da 100644
--- a/tests/tapl/com/android/launcher3/tapl/AppIcon.java
+++ b/tests/tapl/com/android/launcher3/tapl/AppIcon.java
@@ -16,8 +16,11 @@
package com.android.launcher3.tapl;
+import android.graphics.Point;
+import android.graphics.Rect;
import android.widget.TextView;
+import androidx.annotation.NonNull;
import androidx.test.uiautomator.By;
import androidx.test.uiautomator.BySelector;
import androidx.test.uiautomator.UiObject2;
@@ -29,7 +32,7 @@
/**
* App icon, whether in all apps or in workspace/
*/
-public final class AppIcon extends Launchable {
+public final class AppIcon extends Launchable implements FolderDragTarget {
private static final Pattern LONG_CLICK_EVENT = Pattern.compile("onAllAppsItemLongClick");
@@ -61,6 +64,29 @@
}
}
+ /**
+ * Drag the AppIcon to the given position of other icon. The drag must result in a folder.
+ *
+ * @param target the destination icon.
+ */
+ @NonNull
+ public FolderIcon dragToIcon(FolderDragTarget target) {
+ try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
+ LauncherInstrumentation.Closable c = mLauncher.addContextLayer("want to drag icon")) {
+ final Rect dropBounds = target.getDropLocationBounds();
+ Workspace.dragIconToWorkspace(
+ mLauncher, this,
+ () -> {
+ final Rect bounds = target.getDropLocationBounds();
+ return new Point(bounds.centerX(), bounds.centerY());
+ },
+ getLongPressIndicator());
+ FolderIcon result = target.getTargetFolder(dropBounds);
+ mLauncher.assertTrue("Can't find the target folder.", result != null);
+ return result;
+ }
+ }
+
@Override
protected void addExpectedEventsForLongClick() {
mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, LONG_CLICK_EVENT);
@@ -80,4 +106,20 @@
protected String launchableType() {
return "app icon";
}
+
+ @Override
+ public Rect getDropLocationBounds() {
+ return mLauncher.getVisibleBounds(mObject);
+ }
+
+ @Override
+ public FolderIcon getTargetFolder(Rect bounds) {
+ for (FolderIcon folderIcon : mLauncher.getWorkspace().getFolderIcons()) {
+ final Rect folderIconBounds = folderIcon.getDropLocationBounds();
+ if (bounds.contains(folderIconBounds.centerX(), folderIconBounds.centerY())) {
+ return folderIcon;
+ }
+ }
+ return null;
+ }
}
diff --git a/tests/tapl/com/android/launcher3/tapl/Folder.java b/tests/tapl/com/android/launcher3/tapl/Folder.java
new file mode 100644
index 0000000..dba308d
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/Folder.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2021 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.launcher3.tapl;
+
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.os.SystemClock;
+import android.view.MotionEvent;
+
+import androidx.annotation.NonNull;
+import androidx.test.uiautomator.UiObject2;
+
+public class Folder {
+
+ protected static final String FOLDER_CONTENT_RES_ID = "folder_content";
+
+ private final UiObject2 mContainer;
+ private final LauncherInstrumentation mLauncher;
+
+ Folder(LauncherInstrumentation launcher) {
+ this.mLauncher = launcher;
+ this.mContainer = launcher.waitForLauncherObject(FOLDER_CONTENT_RES_ID);
+ }
+
+ /**
+ * Find an app icon with given name or raise assertion error.
+ */
+ @NonNull
+ public AppIcon getAppIcon(String appName) {
+ try (LauncherInstrumentation.Closable ignored = mLauncher.addContextLayer(
+ "Want to get app icon in folder")) {
+ return new AppIcon(mLauncher,
+ mLauncher.waitForObjectInContainer(
+ mContainer,
+ AppIcon.getAppIconSelector(appName, mLauncher)));
+ }
+ }
+
+ private void touchOutsideFolder() {
+ Rect containerBounds = mLauncher.getVisibleBounds(this.mContainer);
+ final long downTime = SystemClock.uptimeMillis();
+ Point containerLeftTopCorner = new Point(containerBounds.left - 1, containerBounds.top - 1);
+ mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN,
+ containerLeftTopCorner, LauncherInstrumentation.GestureScope.INSIDE);
+ mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_UP,
+ containerLeftTopCorner, LauncherInstrumentation.GestureScope.INSIDE);
+ }
+
+ /**
+ * CLose opened folder if possible. It throws assertion error if the folder is already closed.
+ */
+ public Workspace close() {
+ try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
+ LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+ "Want to close opened folder")) {
+ mLauncher.waitForLauncherObject(FOLDER_CONTENT_RES_ID);
+ touchOutsideFolder();
+ mLauncher.waitUntilLauncherObjectGone(FOLDER_CONTENT_RES_ID);
+ return mLauncher.getWorkspace();
+ }
+ }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/FolderDragTarget.java b/tests/tapl/com/android/launcher3/tapl/FolderDragTarget.java
new file mode 100644
index 0000000..d797418
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/FolderDragTarget.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2021 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.launcher3.tapl;
+
+import android.graphics.Rect;
+
+public interface FolderDragTarget {
+ Rect getDropLocationBounds();
+
+ FolderIcon getTargetFolder(Rect bounds);
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/FolderIcon.java b/tests/tapl/com/android/launcher3/tapl/FolderIcon.java
new file mode 100644
index 0000000..2e79d70
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/FolderIcon.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2021 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.launcher3.tapl;
+
+import android.graphics.Rect;
+
+import androidx.annotation.NonNull;
+import androidx.test.uiautomator.UiObject2;
+
+import com.android.launcher3.testing.TestProtocol;
+
+/**
+ * Folder Icon, an app folder in workspace.
+ */
+public class FolderIcon implements FolderDragTarget {
+
+ protected final UiObject2 mObject;
+ protected final LauncherInstrumentation mLauncher;
+
+ FolderIcon(LauncherInstrumentation launcher, UiObject2 icon) {
+ mObject = icon;
+ mLauncher = launcher;
+ }
+
+ /**
+ * Open and return a folder or raise assertion error.
+ */
+ @NonNull
+ public Folder open() {
+ try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
+ LauncherInstrumentation.Closable c = mLauncher.addContextLayer("open folder")) {
+ mLauncher.executeAndWaitForLauncherEvent(() -> mLauncher.clickLauncherObject(mObject),
+ event -> TestProtocol.FOLDER_OPENED_MESSAGE.equals(
+ event.getClassName().toString()),
+ () -> "Fail to open folder.",
+ "open folder");
+ }
+ return new Folder(mLauncher);
+ }
+
+ @Override
+ public Rect getDropLocationBounds() {
+ return mLauncher.getVisibleBounds(mObject.getParent());
+ }
+
+ @Override
+ public FolderIcon getTargetFolder(Rect bounds) {
+ return this;
+ }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 7ffdf4c..e2d0238 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -21,6 +21,7 @@
import static android.content.pm.PackageManager.MATCH_ALL;
import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS;
+import static com.android.launcher3.tapl.Folder.FOLDER_CONTENT_RES_ID;
import static com.android.launcher3.tapl.TestHelpers.getOverviewPackageName;
import static com.android.launcher3.testing.TestProtocol.NORMAL_STATE_ORDINAL;
@@ -75,11 +76,13 @@
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;
+import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.Consumer;
@@ -108,6 +111,9 @@
static final Pattern EVENT_TOUCH_DOWN_TIS = getTouchEventPatternTIS("ACTION_DOWN");
static final Pattern EVENT_TOUCH_UP_TIS = getTouchEventPatternTIS("ACTION_UP");
+ static final Pattern EVENT_KEY_BACK_DOWN = getKeyEventPattern("ACTION_DOWN", "KEYCODE_BACK");
+ static final Pattern EVENT_KEY_BACK_UP = getKeyEventPattern("ACTION_UP", "KEYCODE_BACK");
+
private final String mLauncherPackage;
private Boolean mIsLauncher3;
private long mTestStartTime = -1;
@@ -123,7 +129,8 @@
// Where the gesture happens: outside of Launcher, inside or from inside to outside and
// whether the gesture recognition triggers pilfer.
public enum GestureScope {
- OUTSIDE_WITHOUT_PILFER, OUTSIDE_WITH_PILFER, INSIDE, INSIDE_TO_OUTSIDE
+ OUTSIDE_WITHOUT_PILFER, OUTSIDE_WITH_PILFER, INSIDE, INSIDE_TO_OUTSIDE,
+ INSIDE_TO_OUTSIDE_WITHOUT_PILFER,
}
// Base class for launcher containers.
@@ -193,6 +200,10 @@
return getTouchEventPattern("TouchInteractionService.onInputEvent", action);
}
+ private static Pattern getKeyEventPattern(String action, String keyCode) {
+ return Pattern.compile("Key event: KeyEvent.*action=" + action + ".*keyCode=" + keyCode);
+ }
+
/**
* Constructs the root of TAPL hierarchy. You get all other objects from it.
*/
@@ -768,6 +779,47 @@
}
/**
+ * Get the resource ID of visible floating view.
+ */
+ private Optional<String> getFloatingResId() {
+ if (hasLauncherObject(CONTEXT_MENU_RES_ID)) {
+ return Optional.of(CONTEXT_MENU_RES_ID);
+ }
+ if (hasLauncherObject(FOLDER_CONTENT_RES_ID)) {
+ return Optional.of(FOLDER_CONTENT_RES_ID);
+ }
+ return Optional.empty();
+ }
+
+ /**
+ * Using swiping up gesture to dismiss closable floating views, such as Menu or Folder Content.
+ */
+ private void swipeUpToCloseFloatingView(boolean gestureStartFromLauncher) {
+ final Point displaySize = getRealDisplaySize();
+
+ final Optional<String> floatingRes = getFloatingResId();
+
+ if (!floatingRes.isPresent()) {
+ return;
+ }
+
+ GestureScope gestureScope = gestureStartFromLauncher
+ ? (isTablet() ? GestureScope.INSIDE : GestureScope.INSIDE_TO_OUTSIDE)
+ : GestureScope.OUTSIDE_WITH_PILFER;
+ linearGesture(
+ displaySize.x / 2, displaySize.y - 1,
+ displaySize.x / 2, 0,
+ ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME,
+ false, gestureScope);
+
+ try (LauncherInstrumentation.Closable c1 = addContextLayer(
+ String.format("Swiped up from floating view %s to home", floatingRes.get()))) {
+ waitUntilLauncherObjectGone(floatingRes.get());
+ waitForLauncherObject(getAnyObjectSelector());
+ }
+ }
+
+ /**
* Presses nav bar home button.
*
* @return the Workspace object.
@@ -791,21 +843,9 @@
? !isLauncher3() || hasLauncherObject(WORKSPACE_RES_ID)
: isLauncherVisible();
- if (hasLauncherObject(CONTEXT_MENU_RES_ID)) {
- GestureScope gestureScope = gestureStartFromLauncher
- ? (isTablet() ? GestureScope.INSIDE : GestureScope.INSIDE_TO_OUTSIDE)
- : GestureScope.OUTSIDE_WITH_PILFER;
- linearGesture(
- displaySize.x / 2, displaySize.y - 1,
- displaySize.x / 2, 0,
- ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME,
- false, gestureScope);
- try (LauncherInstrumentation.Closable c1 = addContextLayer(
- "Swiped up from context menu to home")) {
- waitUntilLauncherObjectGone(CONTEXT_MENU_RES_ID);
- waitForLauncherObject(getAnyObjectSelector());
- }
- }
+ // CLose floating views before going back to home.
+ swipeUpToCloseFloatingView(gestureStartFromLauncher);
+
if (hasLauncherObject(WORKSPACE_RES_ID)) {
log(action = "already at home");
} else {
@@ -848,6 +888,38 @@
}
}
+ /**
+ * Press navbar back button or swipe back if in gesture navigation mode.
+ */
+ public void pressBack() {
+ try (Closable e = eventsCheck(); Closable c = addContextLayer("want to press back")) {
+ waitForLauncherInitialized();
+ final boolean launcherVisible =
+ isTablet() ? isLauncherContainerVisible() : isLauncherVisible();
+ if (getNavigationModel() == NavigationModel.ZERO_BUTTON) {
+ final Point displaySize = getRealDisplaySize();
+ final GestureScope gestureScope =
+ launcherVisible ? GestureScope.INSIDE_TO_OUTSIDE_WITHOUT_PILFER
+ : GestureScope.OUTSIDE_WITHOUT_PILFER;
+ linearGesture(0, displaySize.y / 2, displaySize.x / 2, displaySize.y / 2,
+ 10, false, gestureScope);
+ } else {
+ waitForNavigationUiObject("back").click();
+ if (isTablet()) {
+ expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_TOUCH_DOWN);
+ expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_TOUCH_UP);
+ } else if (!isLauncher3() && getNavigationModel() == NavigationModel.TWO_BUTTON) {
+ expectEvent(TestProtocol.SEQUENCE_TIS, EVENT_TOUCH_DOWN_TIS);
+ expectEvent(TestProtocol.SEQUENCE_TIS, EVENT_TOUCH_UP_TIS);
+ }
+ }
+ if (launcherVisible) {
+ expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_KEY_BACK_DOWN);
+ expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_KEY_BACK_UP);
+ }
+ }
+ }
+
private static BySelector getAnyObjectSelector() {
return By.textStartsWith("");
}
@@ -857,6 +929,11 @@
return hasLauncherObject(getAnyObjectSelector());
}
+ boolean isLauncherContainerVisible() {
+ final String[] containerResources = {WORKSPACE_RES_ID, OVERVIEW_RES_ID, APPS_RES_ID};
+ return Arrays.stream(containerResources).anyMatch(r -> hasLauncherObject(r));
+ }
+
/**
* Gets the Workspace object if the current state is "active home", i.e. workspace. Fails if the
* launcher is not in that state.
@@ -1383,6 +1460,7 @@
break;
case MotionEvent.ACTION_UP:
if (notLauncher3 && gestureScope != GestureScope.INSIDE
+ && gestureScope != GestureScope.INSIDE_TO_OUTSIDE_WITHOUT_PILFER
&& (gestureScope == GestureScope.OUTSIDE_WITH_PILFER
|| gestureScope == GestureScope.INSIDE_TO_OUTSIDE)) {
expectEvent(TestProtocol.SEQUENCE_PILFER, EVENT_PILFER_POINTERS);
diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java
index 288c853..0145690 100644
--- a/tests/tapl/com/android/launcher3/tapl/Workspace.java
+++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java
@@ -36,7 +36,10 @@
import com.android.launcher3.testing.TestProtocol;
+import java.util.List;
+import java.util.function.Supplier;
import java.util.regex.Pattern;
+import java.util.stream.Collectors;
/**
* Operations on the workspace screen.
@@ -170,40 +173,100 @@
mHotseat, AppIcon.getAppIconSelector(appName, mLauncher)));
}
- static void dragIconToWorkspace(
- LauncherInstrumentation launcher, Launchable launchable, Point dest,
- String longPressIndicator, boolean startsActivity, boolean isWidgetShortcut,
- Runnable expectLongClickEvents) {
- LauncherInstrumentation.log("dragIconToWorkspace: begin");
- final Point launchableCenter = launchable.getObject().getVisibleCenter();
- final long downTime = SystemClock.uptimeMillis();
- launcher.runToState(
- () -> {
- launcher.sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN,
- launchableCenter, LauncherInstrumentation.GestureScope.INSIDE);
- LauncherInstrumentation.log("dragIconToWorkspace: sent down");
- expectLongClickEvents.run();
- launcher.waitForLauncherObject(longPressIndicator);
- LauncherInstrumentation.log("dragIconToWorkspace: indicator");
- launcher.movePointer(launchableCenter, dest, 10, downTime, true,
- LauncherInstrumentation.GestureScope.INSIDE);
- },
- SPRING_LOADED_STATE_ORDINAL,
- "long-pressing and moving");
- LauncherInstrumentation.log("dragIconToWorkspace: moved pointer");
+ private static int getStartDragThreshold(LauncherInstrumentation launcher) {
+ return launcher.getTestInfo(TestProtocol.REQUEST_START_DRAG_THRESHOLD).getInt(
+ TestProtocol.TEST_INFO_RESPONSE_FIELD);
+ }
+
+ /**
+ * Finds folder icons in the current workspace.
+ *
+ * @return a list of folder icons.
+ */
+ List<FolderIcon> getFolderIcons() {
+ final UiObject2 workspace = verifyActiveContainer();
+ return mLauncher.getObjectsInContainer(workspace, "folder_icon_name").stream().map(
+ o -> new FolderIcon(mLauncher, o)).collect(Collectors.toList());
+ }
+
+ /**
+ * Drag an icon up with a short distance that makes workspace go to spring loaded state.
+ *
+ * @return the position after dragging.
+ */
+ private static Point dragIconToSpringLoaded(LauncherInstrumentation launcher, long downTime,
+ UiObject2 icon,
+ String longPressIndicator, Runnable expectLongClickEvents) {
+ final Point iconCenter = icon.getVisibleCenter();
+ final Point dragStartCenter = new Point(iconCenter.x,
+ iconCenter.y - getStartDragThreshold(launcher));
+
+ launcher.runToState(() -> {
+ launcher.sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN,
+ iconCenter, LauncherInstrumentation.GestureScope.INSIDE);
+ LauncherInstrumentation.log("dragIconToSpringLoaded: sent down");
+ expectLongClickEvents.run();
+ launcher.waitForLauncherObject(longPressIndicator);
+ LauncherInstrumentation.log("dragIconToSpringLoaded: indicator");
+ launcher.movePointer(iconCenter, dragStartCenter, 10, downTime, true,
+ LauncherInstrumentation.GestureScope.INSIDE);
+ }, SPRING_LOADED_STATE_ORDINAL, "long-pressing and triggering drag start");
+ return dragStartCenter;
+ }
+
+ private static void dropDraggedIcon(LauncherInstrumentation launcher, Point dest, long downTime,
+ @Nullable Runnable expectedEvents) {
launcher.runToState(
() -> launcher.sendPointer(
downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, dest,
LauncherInstrumentation.GestureScope.INSIDE),
NORMAL_STATE_ORDINAL,
"sending UP event");
- if (startsActivity || isWidgetShortcut) {
- launcher.expectEvent(TestProtocol.SEQUENCE_MAIN, LauncherInstrumentation.EVENT_START);
+ if (expectedEvents != null) {
+ expectedEvents.run();
}
- LauncherInstrumentation.log("dragIconToWorkspace: end");
+ LauncherInstrumentation.log("dropIcon: end");
launcher.waitUntilLauncherObjectGone("drop_target_bar");
}
+ static void dragIconToWorkspace(LauncherInstrumentation launcher, Launchable launchable,
+ Point dest, String longPressIndicator, boolean startsActivity, boolean isWidgetShortcut,
+ Runnable expectLongClickEvents) {
+ Runnable expectDropEvents = null;
+ if (startsActivity || isWidgetShortcut) {
+ expectDropEvents = () -> launcher.expectEvent(TestProtocol.SEQUENCE_MAIN,
+ LauncherInstrumentation.EVENT_START);
+ }
+ dragIconToWorkspace(launcher, launchable, () -> dest, longPressIndicator,
+ expectLongClickEvents, expectDropEvents);
+ }
+
+ /**
+ * Drag icon in workspace to else where.
+ * This function expects the launchable is inside the workspace and there is no drop event.
+ */
+ static void dragIconToWorkspace(LauncherInstrumentation launcher, Launchable launchable,
+ Supplier<Point> destSupplier, String longPressIndicator) {
+ dragIconToWorkspace(launcher, launchable, destSupplier, longPressIndicator,
+ () -> launcher.expectEvent(TestProtocol.SEQUENCE_MAIN, LONG_CLICK_EVENT), null);
+ }
+
+ static void dragIconToWorkspace(
+ LauncherInstrumentation launcher, Launchable launchable, Supplier<Point> dest,
+ String longPressIndicator, Runnable expectLongClickEvents,
+ @Nullable Runnable expectDropEvents) {
+ try (LauncherInstrumentation.Closable ignored = launcher.addContextLayer(
+ "want to drag icon to workspace")) {
+ final long downTime = SystemClock.uptimeMillis();
+ final Point dragStartCenter = dragIconToSpringLoaded(launcher, downTime,
+ launchable.getObject(), longPressIndicator, expectLongClickEvents);
+ final Point targetDest = dest.get();
+ launcher.movePointer(dragStartCenter, targetDest, 10, downTime, true,
+ LauncherInstrumentation.GestureScope.INSIDE);
+ dropDraggedIcon(launcher, targetDest, downTime, expectDropEvents);
+ }
+ }
+
/**
* Flings to get to screens on the right. Waits for scrolling and a possible overscroll
* recoil to complete.