Merge "DO NOT MERGE Fix the cutout of magnification border" into sc-v2-dev
diff --git a/Android.bp b/Android.bp
index c8d9186..d04dca0 100644
--- a/Android.bp
+++ b/Android.bp
@@ -152,9 +152,13 @@
],
srcs: [
"src/**/*.java",
+ "src/**/*.kt",
"src_shortcuts_overrides/**/*.java",
+ "src_shortcuts_overrides/**/*.kt",
"src_ui_overrides/**/*.java",
+ "src_ui_overrides/**/*.kt",
"ext_tests/src/**/*.java",
+ "ext_tests/src/**/*.kt",
],
resource_dirs: [
"ext_tests/res",
@@ -211,7 +215,10 @@
// Source code used for test helpers
filegroup {
name: "launcher-src-ext-tests",
- srcs: ["ext_tests/src/**/*.java"],
+ srcs: [
+ "ext_tests/src/**/*.java",
+ "ext_tests/src/**/*.kt",
+ ],
}
// Common source files used to build launcher
@@ -219,8 +226,11 @@
name: "launcher-src-no-build-config",
srcs: [
"src/**/*.java",
+ "src/**/*.kt",
"src_shortcuts_overrides/**/*.java",
+ "src_shortcuts_overrides/**/*.kt",
"quickstep/src/**/*.java",
+ "quickstep/src/**/*.kt",
],
}
@@ -235,9 +245,13 @@
name: "LauncherGoResLib",
srcs: [
"src/**/*.java",
+ "src/**/*.kt",
"quickstep/src/**/*.java",
+ "quickstep/src/**/*.kt",
"go/src/**/*.java",
+ "go/src/**/*.kt",
"go/quickstep/src/**/*.java",
+ "go/quickstep/src/**/*.kt",
],
resource_dirs: [
"go/res",
diff --git a/Android.mk b/Android.mk
index c1dbc53..ceaaf13 100644
--- a/Android.mk
+++ b/Android.mk
@@ -105,7 +105,7 @@
LOCAL_SDK_VERSION := system_current
LOCAL_MIN_SDK_VERSION := 26
endif
-LOCAL_STATIC_ANDROID_LIBRARIES := Launcher3CommonDepsLib
+LOCAL_STATIC_ANDROID_LIBRARIES := LauncherGoResLib
LOCAL_SRC_FILES := \
$(call all-java-files-under, src) \
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/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index 8a05533..7e5bda5 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -110,7 +110,6 @@
import com.android.quickstep.RemoteAnimationTargets;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.TaskViewUtils;
-import com.android.quickstep.util.AppCloseConfig;
import com.android.quickstep.util.MultiValueUpdateListener;
import com.android.quickstep.util.RectFSpringAnim;
import com.android.quickstep.util.RemoteAnimationProvider;
@@ -1338,12 +1337,11 @@
RectFSpringAnim.OnUpdateListener runner = new SpringAnimRunner(targets, targetRect) {
@Override
- public void onUpdate(@Nullable AppCloseConfig values, RectF currentRectF,
- float progress) {
+ public void onUpdate(RectF currentRectF, float progress) {
finalFloatingIconView.update(1f, 255 /* fgAlpha */, currentRectF, progress,
windowAlphaThreshold, getCornerRadius(progress), false);
- super.onUpdate(values, currentRectF, progress);
+ super.onUpdate(currentRectF, progress);
}
};
anim.addOnUpdateListener(runner);
@@ -1356,8 +1354,7 @@
FloatingWidgetView finalFloatingWidget = floatingWidget;
RectFSpringAnim.OnUpdateListener runner = new SpringAnimRunner(targets, targetRect) {
@Override
- public void onUpdate(@Nullable AppCloseConfig values, RectF currentRectF,
- float progress) {
+ public void onUpdate(RectF currentRectF, float progress) {
final float fallbackBackgroundAlpha =
1 - mapBoundToRange(progress, 0.8f, 1, 0, 1, EXAGGERATED_EASE);
final float foregroundAlpha =
@@ -1365,7 +1362,7 @@
finalFloatingWidget.update(currentRectF, floatingWidgetAlpha, foregroundAlpha,
fallbackBackgroundAlpha, 1 - progress);
- super.onUpdate(values, currentRectF, progress);
+ super.onUpdate(currentRectF, progress);
}
};
anim.addOnUpdateListener(runner);
@@ -1776,7 +1773,7 @@
}
@Override
- public void onUpdate(@Nullable AppCloseConfig values, RectF currentRectF, float progress) {
+ public void onUpdate(RectF currentRectF, float progress) {
SurfaceParams[] params = new SurfaceParams[mAppTargets.length];
for (int i = mAppTargets.length - 1; i >= 0; i--) {
RemoteAnimationTargetCompat target = mAppTargets[i];
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/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index e8aa2fa..30a0fdf 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -677,6 +677,9 @@
public WindowInsets onApplyWindowInsets(View view, WindowInsets windowInsets) {
WindowInsets result = view.onApplyWindowInsets(windowInsets);
buildAnimationController();
+ // Reapply the current shift to ensure it takes new insets into account, e.g. when long
+ // pressing to stash taskbar without moving the finger.
+ updateFinalShift();
return result;
}
@@ -961,8 +964,10 @@
} else {
mStateCallback.setState(STATE_RESUME_LAST_TASK);
}
- TaskViewUtils.setSplitAuxiliarySurfacesShown(
- mRecentsAnimationTargets.nonApps, true);
+ if (mRecentsAnimationTargets != null) {
+ TaskViewUtils.setSplitAuxiliarySurfacesShown(
+ mRecentsAnimationTargets.nonApps, true);
+ }
break;
}
ActiveGestureLog.INSTANCE.addLog("onSettledOnEndTarget " + endTarget);
@@ -1447,7 +1452,7 @@
}
private void setupWindowAnimation(RectFSpringAnim[] anims) {
- anims[0].addOnUpdateListener((v, r, p) -> {
+ anims[0].addOnUpdateListener((r, p) -> {
updateSysUiFlags(Math.max(p, mCurrentShift.value));
});
anims[0].addAnimatorListener(new AnimationSuccessListener() {
@@ -1734,7 +1739,10 @@
endLauncherTransitionController();
mRecentsView.onSwipeUpAnimationSuccess();
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
- mTaskAnimationManager.setLiveTileCleanUpHandler(mInputConsumerProxy::destroy);
+ mTaskAnimationManager.setLiveTileCleanUpHandler(() -> {
+ mRecentsView.cleanupRemoteTargets();
+ mInputConsumerProxy.destroy();
+ });
mTaskAnimationManager.enableLiveTileRestartListener();
}
diff --git a/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java b/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
index c1b45e0..fed5ae5 100644
--- a/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
@@ -50,7 +50,6 @@
import android.view.SurfaceControl.Transaction;
import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Utilities;
@@ -59,7 +58,6 @@
import com.android.launcher3.anim.SpringAnimationBuilder;
import com.android.quickstep.fallback.FallbackRecentsView;
import com.android.quickstep.fallback.RecentsState;
-import com.android.quickstep.util.AppCloseConfig;
import com.android.quickstep.util.RectFSpringAnim;
import com.android.quickstep.util.TransformParams;
import com.android.quickstep.util.TransformParams.BuilderProxy;
@@ -317,8 +315,7 @@
}
@Override
- public void update(@Nullable AppCloseConfig config, RectF currentRect, float progress,
- float radius) {
+ public void update(RectF currentRect, float progress, float radius) {
if (mSurfaceControl != null) {
currentRect.roundOut(mTempRect);
Transaction t = new Transaction();
diff --git a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
index 0181cd7..8a30aad 100644
--- a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
+++ b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
@@ -18,18 +18,14 @@
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
import static com.android.launcher3.LauncherState.NORMAL;
-import static com.android.launcher3.Utilities.boundToRange;
import static com.android.launcher3.Utilities.dpToPx;
import static com.android.launcher3.Utilities.mapBoundToRange;
import static com.android.launcher3.anim.Interpolators.EXAGGERATED_EASE;
import static com.android.launcher3.anim.Interpolators.LINEAR;
-import static com.android.launcher3.config.FeatureFlags.PROTOTYPE_APP_CLOSE;
import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID;
import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION;
import static com.android.launcher3.views.FloatingIconView.getFloatingIconView;
-import static java.lang.Math.round;
-
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
@@ -59,10 +55,8 @@
import com.android.launcher3.views.FloatingIconView;
import com.android.launcher3.views.FloatingView;
import com.android.launcher3.widget.LauncherAppWidgetHostView;
-import com.android.quickstep.util.AppCloseConfig;
import com.android.quickstep.util.RectFSpringAnim;
import com.android.quickstep.util.StaggeredWorkspaceAnim;
-import com.android.quickstep.util.WorkspaceRevealAnim;
import com.android.quickstep.views.FloatingWidgetView;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
@@ -167,15 +161,9 @@
}
@Override
- public void update(@Nullable AppCloseConfig config, RectF currentRect,
- float progress, float radius) {
- super.update(config, currentRect, progress, radius);
- int fgAlpha = 255;
- if (config != null && PROTOTYPE_APP_CLOSE.get()) {
- progress = config.getInterpolatedProgress();
- fgAlpha = config.getFgAlpha();
- }
- floatingIconView.update(1f, fgAlpha, currentRect, progress,
+ public void update(RectF currentRect, float progress, float radius) {
+ super.update(currentRect, progress, radius);
+ floatingIconView.update(1f /* alpha */, 255 /* fgAlpha */, currentRect, progress,
windowAlphaThreshold, radius, false);
}
};
@@ -232,9 +220,8 @@
}
@Override
- public void update(@Nullable AppCloseConfig config, RectF currentRect, float progress,
- float radius) {
- super.update(config, currentRect, progress, radius);
+ public void update(RectF currentRect, float progress, float radius) {
+ super.update(currentRect, progress, radius);
final float fallbackBackgroundAlpha =
1 - mapBoundToRange(progress, 0.8f, 1, 0, 1, EXAGGERATED_EASE);
final float foregroundAlpha =
@@ -293,27 +280,12 @@
private final float mTransY;
private final FloatingView mFloatingView;
private ValueAnimator mBounceBackAnimator;
- private final AnimatorSet mWorkspaceReveal;
FloatingViewHomeAnimationFactory(FloatingView floatingView) {
mFloatingView = floatingView;
ResourceProvider rp = DynamicResource.provider(mActivity);
mTransY = dpToPx(rp.getFloat(R.dimen.swipe_up_trans_y_dp));
-
- mWorkspaceReveal = PROTOTYPE_APP_CLOSE.get()
- ? new WorkspaceRevealAnim(mActivity, true /* animateScrim */).getAnimators()
- : null;
- }
-
- @Override
- public @NonNull RectF getWindowTargetRect() {
- if (PROTOTYPE_APP_CLOSE.get()) {
- // We want the target rect to be at this offset position, so that all
- // launcher content can spring back upwards.
- mFloatingView.setPositionOffsetY(mTransY);
- }
- return super.getWindowTargetRect();
}
@Override
@@ -321,20 +293,6 @@
return false;
}
- @Override
- public void update(@Nullable AppCloseConfig config, RectF currentRect, float progress,
- float radius) {
- if (config != null && PROTOTYPE_APP_CLOSE.get()) {
- DragLayer dl = mActivity.getDragLayer();
- float translationY = config.getWorkspaceTransY();
- dl.setTranslationY(translationY);
-
- long duration = mWorkspaceReveal.getDuration();
- long playTime = boundToRange(round(duration * progress), 0, duration);
- mWorkspaceReveal.setCurrentPlayTime(playTime);
- }
- }
-
protected void bounceBackToRestingPosition() {
final float startValue = mTransY;
final float endValue = 0;
@@ -369,31 +327,6 @@
}
@Override
- public void setAnimation(RectFSpringAnim anim) {
- if (PROTOTYPE_APP_CLOSE.get()) {
- // Use a spring to put drag layer translation back to 0.
- anim.addAnimatorListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mFloatingView.setPositionOffsetY(0);
- bounceBackToRestingPosition();
- }
- });
-
- // Will be updated manually below so that the two animations are in sync.
- mWorkspaceReveal.start();
- mWorkspaceReveal.pause();
-
- anim.addAnimatorListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mWorkspaceReveal.end();
- }
- });
- }
- }
-
- @Override
public void onCancel() {
mFloatingView.fastFinish();
if (mBounceBackAnimator != null) {
@@ -425,13 +358,9 @@
@Override
public void playAtomicAnimation(float velocity) {
- if (!PROTOTYPE_APP_CLOSE.get()) {
- new StaggeredWorkspaceAnim(mActivity, velocity, true /* animateOverviewScrim */,
- getViewIgnoredInWorkspaceRevealAnimation())
- .start();
- } else if (shouldPlayAtomicWorkspaceReveal()) {
- new WorkspaceRevealAnim(mActivity, true).start();
- }
+ new StaggeredWorkspaceAnim(mActivity, velocity, true /* animateOverviewScrim */,
+ getViewIgnoredInWorkspaceRevealAnimation())
+ .start();
}
@Override
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/SwipeUpAnimationLogic.java b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
index f64d506..b36cb0a 100644
--- a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
+++ b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
@@ -18,7 +18,6 @@
import static com.android.launcher3.anim.Interpolators.ACCEL_1_5;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.config.FeatureFlags.ENABLE_SPLIT_SELECT;
-import static com.android.launcher3.config.FeatureFlags.PROTOTYPE_APP_CLOSE;
import android.animation.Animator;
import android.content.Context;
@@ -28,7 +27,6 @@
import android.graphics.RectF;
import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
import com.android.launcher3.DeviceProfile;
@@ -39,10 +37,8 @@
import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.quickstep.RemoteTargetGluer.RemoteTargetHandle;
import com.android.quickstep.util.AnimatorControllerWithResistance;
-import com.android.quickstep.util.AppCloseConfig;
import com.android.quickstep.util.LauncherSplitScreenListener;
import com.android.quickstep.util.RectFSpringAnim;
-import com.android.quickstep.util.RectFSpringAnim2;
import com.android.quickstep.util.TaskViewSimulator;
import com.android.quickstep.util.TransformParams;
import com.android.quickstep.util.TransformParams.BuilderProxy;
@@ -189,8 +185,7 @@
public boolean keepWindowOpaque() { return false; }
- public void update(@Nullable AppCloseConfig config, RectF currentRect, float progress,
- float radius) { }
+ public void update(RectF currentRect, float progress, float radius) { }
public void onCancel() { }
@@ -290,14 +285,7 @@
homeToWindowPositionMap.invert(windowToHomePositionMap);
windowToHomePositionMap.mapRect(startRect);
- RectFSpringAnim anim;
- if (PROTOTYPE_APP_CLOSE.get()) {
- anim = new RectFSpringAnim2(startRect, targetRect, mContext,
- taskViewSimulator.getCurrentCornerRadius(),
- homeAnimationFactory.getEndRadius(cropRectF));
- } else {
- anim = new RectFSpringAnim(startRect, targetRect, mContext, mDp);
- }
+ RectFSpringAnim anim = new RectFSpringAnim(startRect, targetRect, mContext, mDp);
homeAnimationFactory.setAnimation(anim);
SpringAnimationRunner runner = new SpringAnimationRunner(
@@ -343,17 +331,13 @@
}
@Override
- public void onUpdate(@Nullable AppCloseConfig config, RectF currentRect, float progress) {
+ public void onUpdate(RectF currentRect, float progress) {
mHomeAnim.setPlayFraction(progress);
mHomeToWindowPositionMap.mapRect(mWindowCurrentRect, currentRect);
mMatrix.setRectToRect(mCropRectF, mWindowCurrentRect, ScaleToFit.FILL);
float cornerRadius = Utilities.mapRange(progress, mStartRadius, mEndRadius);
float alpha = mAnimationFactory.getWindowAlpha(progress);
- if (config != null && PROTOTYPE_APP_CLOSE.get()) {
- alpha = config.getWindowAlpha();
- cornerRadius = config.getCornerRadius();
- }
if (mAnimationFactory.keepWindowOpaque()) {
alpha = 1f;
}
@@ -362,8 +346,7 @@
.setCornerRadius(cornerRadius);
mLocalTransformParams.applySurfaceParams(mLocalTransformParams
.createSurfaceParams(this));
- mAnimationFactory.update(config, currentRect, progress,
- mMatrix.mapRadius(cornerRadius));
+ mAnimationFactory.update(currentRect, progress, mMatrix.mapRadius(cornerRadius));
}
@Override
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index d9319a9..b6f9d58 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -37,6 +37,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;
@@ -444,6 +445,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/interaction/SwipeUpGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
index 68df208..672687d 100644
--- a/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
@@ -53,7 +53,6 @@
import com.android.quickstep.RemoteTargetGluer;
import com.android.quickstep.SwipeUpAnimationLogic;
import com.android.quickstep.SwipeUpAnimationLogic.RunningWindowAnim;
-import com.android.quickstep.util.AppCloseConfig;
import com.android.quickstep.util.RectFSpringAnim;
import com.android.quickstep.util.TransformParams;
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
@@ -331,8 +330,7 @@
}
@Override
- public void update(@Nullable AppCloseConfig config, RectF rect, float progress,
- float radius) {
+ public void update(RectF rect, float progress, float radius) {
mFakeIconView.setVisibility(View.VISIBLE);
mFakeIconView.update(rect, progress,
1f - SHAPE_PROGRESS_DURATION /* shapeProgressStart */,
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/RectFSpringAnim.java b/quickstep/src/com/android/quickstep/util/RectFSpringAnim.java
index 158fba9..c4909de 100644
--- a/quickstep/src/com/android/quickstep/util/RectFSpringAnim.java
+++ b/quickstep/src/com/android/quickstep/util/RectFSpringAnim.java
@@ -328,7 +328,7 @@
break;
}
for (OnUpdateListener onUpdateListener : mOnUpdateListeners) {
- onUpdateListener.onUpdate(null, mCurrentRect, mCurrentScaleProgress);
+ onUpdateListener.onUpdate(mCurrentRect, mCurrentScaleProgress);
}
}
}
@@ -353,7 +353,12 @@
}
public interface OnUpdateListener {
- void onUpdate(@Nullable AppCloseConfig values, RectF currentRect, float progress);
+ /**
+ * Called when an update is made to the animation.
+ * @param currentRect The rect of the window.
+ * @param progress [0, 1] The progress of the rect scale animation.
+ */
+ void onUpdate(RectF currentRect, float progress);
default void onCancel() { }
}
diff --git a/quickstep/src/com/android/quickstep/util/RectFSpringAnim2.java b/quickstep/src/com/android/quickstep/util/RectFSpringAnim2.java
deleted file mode 100644
index cb35809..0000000
--- a/quickstep/src/com/android/quickstep/util/RectFSpringAnim2.java
+++ /dev/null
@@ -1,370 +0,0 @@
-/*
- * 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.quickstep.util;
-
-import static com.android.launcher3.Utilities.dpToPx;
-import static com.android.launcher3.anim.Interpolators.LINEAR;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.graphics.PointF;
-import android.graphics.RectF;
-import android.util.PathParser;
-import android.util.Property;
-import android.view.animation.Interpolator;
-
-import androidx.core.view.animation.PathInterpolatorCompat;
-import androidx.dynamicanimation.animation.FloatPropertyCompat;
-import androidx.dynamicanimation.animation.SpringAnimation;
-import androidx.dynamicanimation.animation.SpringForce;
-
-import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.util.DynamicResource;
-import com.android.systemui.plugins.ResourceProvider;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Locale;
-
-/**
- * Applies spring forces to animate from a starting rect to a target rect,
- * while providing update callbacks to the caller.
- */
-public class RectFSpringAnim2 extends RectFSpringAnim {
-
- private static final FloatPropertyCompat<RectFSpringAnim2> RECT_CENTER_X =
- new FloatPropertyCompat<RectFSpringAnim2>("rectCenterXSpring") {
- @Override
- public float getValue(RectFSpringAnim2 anim) {
- return anim.mCurrentCenterX;
- }
-
- @Override
- public void setValue(RectFSpringAnim2 anim, float currentCenterX) {
- anim.mCurrentCenterX = currentCenterX;
- anim.onUpdate();
- }
- };
-
- private static final FloatPropertyCompat<RectFSpringAnim2> RECT_Y =
- new FloatPropertyCompat<RectFSpringAnim2>("rectYSpring") {
- @Override
- public float getValue(RectFSpringAnim2 anim) {
- return anim.mCurrentCenterY;
- }
-
- @Override
- public void setValue(RectFSpringAnim2 anim, float y) {
- anim.mCurrentCenterY = y;
- anim.onUpdate();
- }
- };
-
- private static final Property<RectFSpringAnim2, Float> PROGRESS =
- new Property<RectFSpringAnim2, Float>(Float.class, "rectFProgress") {
- @Override
- public Float get(RectFSpringAnim2 rectFSpringAnim) {
- return rectFSpringAnim.mProgress;
- }
-
- @Override
- public void set(RectFSpringAnim2 rectFSpringAnim, Float progress) {
- rectFSpringAnim.mProgress = progress;
- rectFSpringAnim.onUpdate();
- }
- };
-
- private final RectF mStartRect;
- private final RectF mTargetRect;
- private final RectF mCurrentRect = new RectF();
- private final List<OnUpdateListener> mOnUpdateListeners = new ArrayList<>();
- private final List<Animator.AnimatorListener> mAnimatorListeners = new ArrayList<>();
-
- private float mCurrentCenterX;
- private float mCurrentCenterY;
-
- private float mTargetX;
- private float mTargetY;
-
- // If true, tracking the bottom of the rects, else tracking the top.
- private float mProgress;
- private SpringAnimation mRectXAnim;
- private SpringAnimation mRectYAnim;
- private ValueAnimator mRectScaleAnim;
- private boolean mAnimsStarted;
- private boolean mRectXAnimEnded;
- private boolean mRectYAnimEnded;
- private boolean mRectScaleAnimEnded;
-
- private final float mXDamping;
- private final float mXStiffness;
-
- private final float mYDamping;
- private float mYStiffness;
-
- private long mDuration;
-
- private final Interpolator mCloseInterpolator;
-
- private AppCloseConfig mValues;
- final float mStartRadius;
- final float mEndRadius;
-
- final float mHomeTransYEnd;
- final float mScaleStart;
-
- public RectFSpringAnim2(RectF startRect, RectF targetRect, Context context, float startRadius,
- float endRadius) {
- super(startRect, targetRect, context, null);
- mStartRect = startRect;
- mTargetRect = targetRect;
-
- mCurrentCenterY = mStartRect.centerY();
- mCurrentCenterX = mStartRect.centerX();
-
- mTargetY = mTargetRect.centerY();
- mTargetX = mTargetRect.centerX();
-
- ResourceProvider rp = DynamicResource.provider(context);
- mXDamping = rp.getFloat(R.dimen.swipe_up_rect_2_x_damping_ratio);
- mXStiffness = rp.getFloat(R.dimen.swipe_up_rect_2_x_stiffness);
-
- mYDamping = rp.getFloat(R.dimen.swipe_up_rect_2_y_damping_ratio);
- mYStiffness = rp.getFloat(R.dimen.swipe_up_rect_2_y_stiffness);
- mDuration = Math.round(rp.getFloat(R.dimen.swipe_up_duration));
-
- mHomeTransYEnd = dpToPx(rp.getFloat(R.dimen.swipe_up_trans_y_dp));
- mScaleStart = rp.getFloat(R.dimen.swipe_up_scale_start);
-
- mCloseInterpolator = getAppCloseInterpolator(context);
-
- // End on a "round-enough" radius so that the shape reveal doesn't have to do too much
- // rounding at the end of the animation.
- mStartRadius = startRadius;
- mEndRadius = endRadius;
-
- setCanRelease(true);
- }
-
- public void onTargetPositionChanged() {
- if (mRectXAnim != null && mTargetX != mTargetRect.centerX()) {
- mTargetX = mTargetRect.centerX();
- mRectXAnim.animateToFinalPosition(mTargetX);
- }
-
- if (mRectYAnim != null) {
- if (mTargetY != mTargetRect.centerY()) {
- mTargetY = mTargetRect.centerY();
- mRectYAnim.animateToFinalPosition(mTargetY);
- }
- }
- }
-
- public void addOnUpdateListener(OnUpdateListener onUpdateListener) {
- mOnUpdateListeners.add(onUpdateListener);
- }
-
- public void addAnimatorListener(Animator.AnimatorListener animatorListener) {
- mAnimatorListeners.add(animatorListener);
- }
-
- /**
- * Starts the fling/spring animation.
- * @param context The activity context.
- * @param velocityPxPerMs Velocity of swipe in px/ms.
- */
- public void start(Context context, PointF velocityPxPerMs) {
- mRectXAnim = new SpringAnimation(this, RECT_CENTER_X)
- .setStartValue(mCurrentCenterX)
- .setStartVelocity(velocityPxPerMs.x * 1000)
- .setSpring(new SpringForce(mTargetX)
- .setStiffness(mXStiffness)
- .setDampingRatio(mXDamping));
- mRectXAnim.addEndListener(((animation, canceled, centerX, velocityX) -> {
- mRectXAnimEnded = true;
- maybeOnEnd();
- }));
-
- mRectYAnim = new SpringAnimation(this, RECT_Y)
- .setStartValue(mCurrentCenterY)
- .setStartVelocity(velocityPxPerMs.y * 1000)
- .setSpring(new SpringForce(mTargetY)
- .setStiffness(mYStiffness)
- .setDampingRatio(mYDamping));
- mRectYAnim.addEndListener(((animation, canceled, centerY, velocityY) -> {
- mRectYAnimEnded = true;
- maybeOnEnd();
- }));
-
- mRectScaleAnim = ObjectAnimator.ofFloat(this, PROGRESS, 0, 1f)
- .setDuration(mDuration);
- mRectScaleAnim.setInterpolator(mCloseInterpolator);
- mRectScaleAnim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mRectScaleAnimEnded = true;
- maybeOnEnd();
- }
- });
-
- mValues = buildConfig();
- mRectScaleAnim.addUpdateListener(mValues);
-
- setCanRelease(false);
- mAnimsStarted = true;
-
- mRectXAnim.start();
- mRectYAnim.start();
- mRectScaleAnim.start();
- for (Animator.AnimatorListener animatorListener : mAnimatorListeners) {
- animatorListener.onAnimationStart(null);
- }
- }
-
- private AppCloseConfig buildConfig() {
- return new AppCloseConfig() {
- FloatProp mHomeTransY = new FloatProp(0, mHomeTransYEnd, 0, mDuration, LINEAR);
- FloatProp mHomeScale = new FloatProp(mScaleStart, 1f, 0, mDuration, LINEAR);
- FloatProp mWindowFadeOut = new FloatProp(1f, 0f, 0, 116, LINEAR);
- // There should be a slight overlap b/w window fading out and fg fading in.
- // (fg startDelay < window fade out duration)
- FloatProp mFgFadeIn = new FloatProp(0, 255f, 100, mDuration - 100, LINEAR);
- FloatProp mRadius = new FloatProp(mStartRadius, mEndRadius, 0, mDuration, LINEAR);
- FloatProp mThreePointInterpolation = new FloatProp(0, 1, 0, mDuration, LINEAR);
-
- @Override
- public float getWorkspaceTransY() {
- return mHomeTransY.value;
- }
-
- @Override
- public float getWorkspaceScale() {
- return mHomeScale.value;
- }
-
- @Override
- public float getWindowAlpha() {
- return mWindowFadeOut.value;
- }
-
- @Override
- public int getFgAlpha() {
- return (int) mFgFadeIn.value;
- }
-
- @Override
- public float getCornerRadius() {
- return mRadius.value;
- }
-
- @Override
- public float getInterpolatedProgress() {
- return mThreePointInterpolation.value;
- }
-
- @Override
- public void onUpdate(float percent, boolean initOnly) {}
- };
- }
-
- public void end() {
- if (mAnimsStarted) {
- if (mRectXAnim.canSkipToEnd()) {
- mRectXAnim.skipToEnd();
- }
- if (mRectYAnim.canSkipToEnd()) {
- mRectYAnim.skipToEnd();
- }
- mRectScaleAnim.end();
- }
- mRectXAnimEnded = true;
- mRectYAnimEnded = true;
- mRectScaleAnimEnded = true;
- maybeOnEnd();
- }
-
- private boolean isEnded() {
- return mRectXAnimEnded && mRectYAnimEnded && mRectScaleAnimEnded;
- }
-
- private void onUpdate() {
- if (isEnded()) {
- // Prevent further updates from being called. This can happen between callbacks for
- // ending the x/y/scale animations.
- return;
- }
-
- if (!mOnUpdateListeners.isEmpty()) {
- float rectProgress = mProgress;
- float currentWidth = Utilities.mapRange(rectProgress, mStartRect.width(),
- mTargetRect.width());
- float currentHeight = Utilities.mapRange(rectProgress, mStartRect.height(),
- mTargetRect.height());
-
- mCurrentRect.set(mCurrentCenterX - currentWidth / 2,
- mCurrentCenterY - currentHeight / 2,
- mCurrentCenterX + currentWidth / 2,
- mCurrentCenterY + currentHeight / 2);
-
- float currentPlayTime = mRectScaleAnimEnded ? mRectScaleAnim.getDuration()
- : mRectScaleAnim.getCurrentPlayTime();
- float linearProgress = Math.min(1f, currentPlayTime / mRectScaleAnim.getDuration());
- for (OnUpdateListener onUpdateListener : mOnUpdateListeners) {
- onUpdateListener.onUpdate(mValues, mCurrentRect, linearProgress);
- }
- }
- }
-
- private void maybeOnEnd() {
- if (mAnimsStarted && isEnded()) {
- mAnimsStarted = false;
- setCanRelease(true);
- for (Animator.AnimatorListener animatorListener : mAnimatorListeners) {
- animatorListener.onAnimationEnd(null);
- }
- }
- }
-
- public void cancel() {
- if (mAnimsStarted) {
- for (OnUpdateListener onUpdateListener : mOnUpdateListeners) {
- onUpdateListener.onCancel();
- }
- }
- end();
- }
-
- private Interpolator getAppCloseInterpolator(Context context) {
- ResourceProvider rp = DynamicResource.provider(context);
- String path = String.format(Locale.ENGLISH,
- "M 0,0 C %f, %f, %f, %f, %f, %f C %f, %f, %f, %f, 1, 1",
- rp.getFloat(R.dimen.c1_a),
- rp.getFloat(R.dimen.c1_b),
- rp.getFloat(R.dimen.c1_c),
- rp.getFloat(R.dimen.c1_d),
- rp.getFloat(R.dimen.mp_x),
- rp.getFloat(R.dimen.mp_y),
- rp.getFloat(R.dimen.c2_a),
- rp.getFloat(R.dimen.c2_b),
- rp.getFloat(R.dimen.c2_c),
- rp.getFloat(R.dimen.c2_d));
- return PathInterpolatorCompat.create(PathParser.createPathFromPathData(path));
- }
-}
diff --git a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
index a30216c..a534450 100644
--- a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
+++ b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
@@ -158,7 +158,7 @@
t.reparent(mContentOverlay, mLeash);
t.apply();
- addOnUpdateListener((values, currentRect, progress) -> {
+ addOnUpdateListener((currentRect, progress) -> {
float alpha = progress < 0.5f
? 0
: Utilities.mapToRange(Math.min(progress, 1f), 0.5f, 1f,
@@ -201,8 +201,7 @@
addOnUpdateListener(this::onAnimationUpdate);
}
- private void onAnimationUpdate(@Nullable AppCloseConfig values, RectF currentRect,
- float progress) {
+ private void onAnimationUpdate(RectF currentRect, float progress) {
if (mHasAnimationEnded) return;
final SurfaceControl.Transaction tx =
PipSurfaceTransactionHelper.newSurfaceControlTransaction();
diff --git a/quickstep/src/com/android/quickstep/util/TaskKeyLruCache.java b/quickstep/src/com/android/quickstep/util/TaskKeyLruCache.java
index d87feec..08a65fa 100644
--- a/quickstep/src/com/android/quickstep/util/TaskKeyLruCache.java
+++ b/quickstep/src/com/android/quickstep/util/TaskKeyLruCache.java
@@ -20,6 +20,7 @@
import com.android.systemui.shared.recents.model.Task.TaskKey;
import java.util.LinkedHashMap;
+import java.util.Map;
import java.util.function.Predicate;
/**
@@ -117,7 +118,7 @@
}
@Override
- protected boolean removeEldestEntry(Entry<Integer, TaskKeyLruCache.Entry<V>> eldest) {
+ protected boolean removeEldestEntry(Map.Entry<Integer, TaskKeyLruCache.Entry<V>> eldest) {
return size() > mMaxSize;
}
}
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 687a13a..1a3bfa9 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -4390,7 +4390,7 @@
public void finishRecentsAnimation(boolean toRecents, boolean shouldPip,
Runnable onFinishComplete) {
// TODO(b/197232424#comment#10) Move this back into onRecentsAnimationComplete(). Maybe?
- mRemoteTargetHandles = null;
+ cleanupRemoteTargets();
if (!toRecents && ENABLE_QUICKSTEP_LIVE_TILE.get()) {
// Reset the minimized state since we force-toggled the minimized state when entering
// overview, but never actually finished the recents animation. This is a catch all for
@@ -4849,6 +4849,10 @@
&& mCurrentGestureEndTarget != GestureState.GestureEndTarget.RECENTS;
}
+ public void cleanupRemoteTargets() {
+ mRemoteTargetHandles = null;
+ }
+
/**
* Used to register callbacks for when our empty message state changes.
*
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt b/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
new file mode 100644
index 0000000..9b86c73
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
@@ -0,0 +1,14 @@
+package com.android.quickstep.views
+
+import android.util.Log
+
+// TODO(http://b/193432925)
+class TaskMenuViewWithArrow {
+ companion object {
+ const val TAG = "TaskMenuViewWithArrow"
+
+ fun logSomething() {
+ Log.d(TAG, "It worked!")
+ }
+ }
+}
\ No newline at end of file
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index 8d77e44..eef5fb3 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -115,6 +115,7 @@
public class TaskView extends FrameLayout implements Reusable {
private static final String TAG = TaskView.class.getSimpleName();
+ private static final boolean DEBUG = false;
public static final int FLAG_UPDATE_ICON = 1;
public static final int FLAG_UPDATE_THUMBNAIL = FLAG_UPDATE_ICON << 1;
@@ -808,6 +809,8 @@
}
protected boolean showTaskMenuWithContainer(IconView iconView) {
+ // TODO(http://b/193432925)
+ if (DEBUG) TaskMenuViewWithArrow.Companion.logSomething();
return TaskMenuView.showForTask(mTaskIdAttributeContainer[0]);
}
diff --git a/res/values/config.xml b/res/values/config.xml
index 6fdb4de..25911e6 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -136,7 +136,6 @@
<item name="swipe_up_rect_xy_fling_friction" type="dimen" format="float">1.5</item>
<item name="swipe_up_scale_start" type="dimen" format="float">0.88</item>
- <item name="swipe_up_duration" type="dimen" format="float">400</item>
<item name="swipe_up_trans_y_dp" type="dimen" format="float">4.5</item>
<item name="swipe_up_trans_y_dp_per_s" type="dimen" format="float">3</item>
@@ -147,33 +146,10 @@
<item name="swipe_up_rect_xy_damping_ratio" type="dimen" format="float">0.8</item>
<item name="swipe_up_rect_xy_stiffness" type="dimen" format="float">200</item>
-
- <item name="swipe_up_rect_2_x_damping_ratio" type="dimen" format="float">1</item>
- <item name="swipe_up_rect_2_x_stiffness" type="dimen" format="float">250</item>
-
- <item name="swipe_up_rect_2_y_damping_ratio" type="dimen" format="float">1</item>
- <item name="swipe_up_rect_2_y_stiffness" type="dimen" format="float">600</item>
-
- <item name="swipe_up_rect_2_y_stiffness_low_swipe_multiplier" type="dimen" format="float">0.8</item>
<item name="swipe_up_low_swipe_duration_multiplier" type="dimen" format="float">1</item>
<item name="swipe_up_launcher_alpha_max_progress" type="dimen" format="float">0.85</item>
-
- <item name="c1_a" type="dimen" format="float">0.05</item>
- <item name="c1_b" type="dimen" format="float">0</item>
- <item name="c1_c" type="dimen" format="float">0.133333</item>
- <item name="c1_d" type="dimen" format="float">0.06</item>
-
- <item name="mp_x" type="dimen" format="float">0.166666</item>
- <item name="mp_y" type="dimen" format="float">.4</item>
-
- <item name="c2_a" type="dimen" format="float">0.208333</item>
- <item name="c2_b" type="dimen" format="float">.82</item>
- <item name="c2_c" type="dimen" format="float">.25</item>
- <item name="c2_d" type="dimen" format="float">1</item>
-
-
<item name="staggered_damping_ratio" type="dimen" format="float">0.7</item>
<item name="staggered_stiffness" type="dimen" format="float">150</item>
<dimen name="unlock_staggered_velocity_dp_per_s">2dp</dimen>
@@ -188,33 +164,14 @@
<dimen name="swipe_up_max_velocity">7.619dp</dimen>
<array name="dynamic_resources">
- <item>@dimen/swipe_up_duration</item>
<item>@dimen/swipe_up_scale_start</item>
<item>@dimen/swipe_up_trans_y_dp</item>
<item>@dimen/swipe_up_trans_y_dp_per_s</item>
<item>@dimen/swipe_up_trans_y_damping</item>
<item>@dimen/swipe_up_trans_y_stiffness</item>
- <item>@dimen/swipe_up_rect_2_x_damping_ratio</item>
- <item>@dimen/swipe_up_rect_2_x_stiffness</item>
- <item>@dimen/swipe_up_rect_2_y_damping_ratio</item>
- <item>@dimen/swipe_up_rect_2_y_stiffness</item>
<item>@dimen/swipe_up_launcher_alpha_max_progress</item>
- <item>@dimen/swipe_up_rect_2_y_stiffness_low_swipe_multiplier</item>
<item>@dimen/swipe_up_low_swipe_duration_multiplier</item>
<item>@dimen/swipe_up_max_velocity</item>
-
- <item>@dimen/c1_a</item>
- <item>@dimen/c1_b</item>
- <item>@dimen/c1_c</item>
- <item>@dimen/c1_d</item>
-
- <item>@dimen/mp_x</item>
- <item>@dimen/mp_y</item>
-
- <item>@dimen/c2_a</item>
- <item>@dimen/c2_b</item>
- <item>@dimen/c2_c</item>
- <item>@dimen/c2_d</item>
</array>
<string-array name="filtered_components" ></string-array>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index d7a1506..e215c20 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -251,7 +251,7 @@
<string name="wallpaper_button_text">Wallpapers</string>
<!-- Text for wallpaper change button [CHAR LIMIT=30]-->
<string name="styles_wallpaper_button_text">Wallpaper & style</string>
- <!-- Text for settings button [CHAR LIMIT=30]-->
+ <!-- Text for settings button [CHAR LIMIT=20]-->
<string name="settings_button_text">Home settings</string>
<!-- Message shown when a feature is disabled by the administrator -->
<string name="msg_disabled_by_admin">Disabled by your admin</string>
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/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 796c912..1358387 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -233,9 +233,6 @@
public static final BooleanFlag NOTIFY_CRASHES = getDebugFlag("NOTIFY_CRASHES", false,
"Sends a notification whenever launcher encounters an uncaught exception.");
- public static final BooleanFlag PROTOTYPE_APP_CLOSE = getDebugFlag(
- "PROTOTYPE_APP_CLOSE", false, "Enables new app close");
-
public static final BooleanFlag ENABLE_WALLPAPER_SCRIM = getDebugFlag(
"ENABLE_WALLPAPER_SCRIM", false,
"Enables scrim over wallpaper for text protection.");
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..db28902 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";
@@ -122,4 +124,5 @@
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/TaplTestsLauncher3.java b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
index 881f50c..2fa84b2 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,48 @@
}
}
+ 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;
+ }
+
+ @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();
+ }
+
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..27a2375 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,6 +87,7 @@
}
@Test
+ @ScreenRecord // b/202735477
public void workTabExists() {
mDevice.pressHome();
waitForLauncherCondition("Launcher didn't start", Objects::nonNull);
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..3ac5fa5 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;
@@ -80,6 +81,7 @@
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;
@@ -768,6 +770,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 +834,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 {
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.