Merge "Fixing jump when swiping up in landscape and in waterfall cutout" into ub-launcher3-rvc-dev

This commit is contained in:
TreeHugger Robot
2020-06-19 07:17:02 +00:00
committed by Android (Google) Code Review
7 changed files with 297 additions and 16 deletions

View File

@@ -121,6 +121,10 @@ public abstract class BaseSwipeUpHandler<T extends StatefulActivity<?>, Q extend
});
mRecentsView.setOnScrollChangeListener((v, scrollX, scrollY, oldScrollX, oldScrollY) -> {
// Wait until the first scroll event before applying scroll to taskViewSimulator.
// Since, by default the current/running task already centered, this ensures that we
// do not move the running task, in case RecentsView has not yet laid out completely.
mRecentsViewScrollLinked = true;
if (moveWindowWithRecentsScroll()) {
updateFinalShift();
}
@@ -128,7 +132,6 @@ public abstract class BaseSwipeUpHandler<T extends StatefulActivity<?>, Q extend
runOnRecentsAnimationStart(() ->
mRecentsView.setRecentsAnimationTargets(mRecentsAnimationController,
mRecentsAnimationTargets));
mRecentsViewScrollLinked = true;
}
protected void startNewTask(Consumer<Boolean> resultCallback) {
@@ -205,26 +208,30 @@ public abstract class BaseSwipeUpHandler<T extends StatefulActivity<?>, Q extend
mRecentsAnimationController = recentsAnimationController;
mRecentsAnimationTargets = targets;
mTransformParams.setTargetSet(mRecentsAnimationTargets);
DeviceProfile dp = mTaskViewSimulator.getOrientationState().getLauncherDeviceProfile();
RemoteAnimationTargetCompat runningTaskTarget = targets.findTask(
mGestureState.getRunningTaskId());
if (targets.minimizedHomeBounds != null && runningTaskTarget != null) {
Rect overviewStackBounds = mActivityInterface
.getOverviewWindowBounds(targets.minimizedHomeBounds, runningTaskTarget);
dp = dp.getMultiWindowProfile(mContext,
new WindowBounds(overviewStackBounds, targets.homeContentInsets));
} else {
// If we are not in multi-window mode, home insets should be same as system insets.
dp = dp.copy(mContext);
}
dp.updateInsets(targets.homeContentInsets);
dp.updateIsSeascape(mContext);
if (runningTaskTarget != null) {
mTaskViewSimulator.setPreview(runningTaskTarget);
}
initTransitionEndpoints(dp);
// Only initialize the device profile, if it has not been initialized before, as in some
// configurations targets.homeContentInsets may not be correct.
if (mActivity == null) {
DeviceProfile dp = mTaskViewSimulator.getOrientationState().getLauncherDeviceProfile();
if (targets.minimizedHomeBounds != null && runningTaskTarget != null) {
Rect overviewStackBounds = mActivityInterface
.getOverviewWindowBounds(targets.minimizedHomeBounds, runningTaskTarget);
dp = dp.getMultiWindowProfile(mContext,
new WindowBounds(overviewStackBounds, targets.homeContentInsets));
} else {
// If we are not in multi-window mode, home insets should be same as system insets.
dp = dp.copy(mContext);
}
dp.updateInsets(targets.homeContentInsets);
dp.updateIsSeascape(mContext);
initTransitionEndpoints(dp);
}
// Notify when the animation starts
if (!mRecentsAnimationStartCallbacks.isEmpty()) {

View File

@@ -256,8 +256,8 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy {
float taskHeight = mTaskRect.height();
mMatrix.set(mPositionHelper.getMatrix());
mMatrix.postScale(scale, scale);
mMatrix.postTranslate(insets.left, insets.top);
mMatrix.postScale(scale, scale);
// Apply TaskView matrix: translate, scale, scroll
mMatrix.postTranslate(mTaskRect.left, mTaskRect.top);

View File

@@ -1000,6 +1000,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
mDwbToastShown = false;
mActivity.getSystemUiController().updateUiState(UI_STATE_OVERVIEW, 0);
LayoutUtils.setViewEnabled(mActionsView, true);
mOrientationState.setGestureActive(false);
}
public @Nullable TaskView getRunningTaskView() {
@@ -1037,6 +1038,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
*/
public void onGestureAnimationStart(int runningTaskId) {
// This needs to be called before the other states are set since it can create the task view
mOrientationState.setGestureActive(true);
showCurrentTask(runningTaskId);
setEnableFreeScroll(false);
setEnableDrawingLiveTile(false);
@@ -1099,6 +1101,8 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
* Called when a gesture from an app has finished.
*/
public void onGestureAnimationEnd() {
mOrientationState.setGestureActive(false);
setOnScrollChangeListener(null);
setEnableFreeScroll(true);
setEnableDrawingLiveTile(true);

View File

@@ -0,0 +1,203 @@
/*
* Copyright (C) 2020 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 android.view.Display.DEFAULT_DISPLAY;
import android.content.Context;
import android.graphics.Rect;
import android.graphics.RectF;
import android.hardware.display.DisplayManager;
import android.view.Surface;
import android.view.SurfaceControl;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.shadows.LShadowDisplay;
import com.android.launcher3.util.DefaultDisplay;
import com.android.quickstep.LauncherActivityInterface;
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
import org.hamcrest.Description;
import org.hamcrest.TypeSafeMatcher;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.LooperMode;
import org.robolectric.annotation.LooperMode.Mode;
import org.robolectric.shadow.api.Shadow;
import org.robolectric.shadows.ShadowDisplayManager;
@RunWith(RobolectricTestRunner.class)
@LooperMode(Mode.PAUSED)
public class TaskViewSimulatorTest {
@Test
public void taskProperlyScaled_portrait_noRotation_sameInsets1() {
new TaskMatrixVerifier()
.withLauncherSize(1200, 2450)
.withInsets(new Rect(0, 80, 0, 120))
.verifyNoTransforms();
}
@Test
public void taskProperlyScaled_portrait_noRotation_sameInsets2() {
new TaskMatrixVerifier()
.withLauncherSize(1200, 2450)
.withInsets(new Rect(55, 80, 55, 120))
.verifyNoTransforms();
}
@Test
public void taskProperlyScaled_landscape_noRotation_sameInsets1() {
new TaskMatrixVerifier()
.withLauncherSize(2450, 1250)
.withInsets(new Rect(0, 80, 0, 40))
.verifyNoTransforms();
}
@Test
public void taskProperlyScaled_landscape_noRotation_sameInsets2() {
new TaskMatrixVerifier()
.withLauncherSize(2450, 1250)
.withInsets(new Rect(0, 80, 120, 0))
.verifyNoTransforms();
}
@Test
public void taskProperlyScaled_landscape_noRotation_sameInsets3() {
new TaskMatrixVerifier()
.withLauncherSize(2450, 1250)
.withInsets(new Rect(55, 80, 55, 120))
.verifyNoTransforms();
}
@Test
public void taskProperlyScaled_landscape_rotated() {
new TaskMatrixVerifier()
.withLauncherSize(1200, 2450)
.withInsets(new Rect(0, 80, 0, 120))
.withAppBounds(
new Rect(0, 0, 2450, 1200),
new Rect(0, 80, 0, 120),
Surface.ROTATION_90)
.verifyNoTransforms();
}
private static class TaskMatrixVerifier extends TransformParams {
private final Context mContext = RuntimeEnvironment.application;
private Rect mAppBounds = new Rect();
private Rect mLauncherInsets = new Rect();
private Rect mAppInsets;
private int mAppRotation = -1;
private DeviceProfile mDeviceProfile;
TaskMatrixVerifier withLauncherSize(int width, int height) {
ShadowDisplayManager.changeDisplay(DEFAULT_DISPLAY,
String.format("w%sdp-h%sdp-mdpi", width, height));
if (mAppBounds.isEmpty()) {
mAppBounds.set(0, 0, width, height);
}
return this;
}
TaskMatrixVerifier withInsets(Rect insets) {
LShadowDisplay shadowDisplay = Shadow.extract(
mContext.getSystemService(DisplayManager.class).getDisplay(DEFAULT_DISPLAY));
shadowDisplay.setInsets(insets);
mLauncherInsets.set(insets);
return this;
}
TaskMatrixVerifier withAppBounds(Rect bounds, Rect insets, int appRotation) {
mAppBounds.set(bounds);
mAppInsets = insets;
mAppRotation = appRotation;
return this;
}
void verifyNoTransforms() {
mDeviceProfile = InvariantDeviceProfile.INSTANCE.get(mContext)
.getDeviceProfile(mContext);
mDeviceProfile.updateInsets(mLauncherInsets);
TaskViewSimulator tvs = new TaskViewSimulator(mContext,
LauncherActivityInterface.INSTANCE);
tvs.setDp(mDeviceProfile);
int launcherRotation = DefaultDisplay.INSTANCE.get(mContext).getInfo().rotation;
if (mAppRotation < 0) {
mAppRotation = launcherRotation;
}
tvs.setLayoutRotation(launcherRotation, mAppRotation);
if (mAppInsets == null) {
mAppInsets = new Rect(mLauncherInsets);
}
tvs.setPreviewBounds(mAppBounds, mAppInsets);
tvs.fullScreenProgress.value = 1;
tvs.recentsViewScale.value = tvs.getFullScreenScale();
tvs.apply(this);
}
@Override
public SurfaceParams[] createSurfaceParams(BuilderProxy proxy) {
SurfaceParams.Builder builder = new SurfaceParams.Builder((SurfaceControl) null);
proxy.onBuildTargetParams(builder, null, this);
return new SurfaceParams[] {builder.build()};
}
@Override
public void applySurfaceParams(SurfaceParams[] params) {
// Verify that the task position remains the same
RectF newAppBounds = new RectF(mAppBounds);
params[0].matrix.mapRect(newAppBounds);
Assert.assertThat(newAppBounds, new AlmostSame(mAppBounds));
System.err.println("Bounds mapped: " + mAppBounds + " => " + newAppBounds);
}
}
private static class AlmostSame extends TypeSafeMatcher<RectF> {
// Allow 1px error margin to account for float to int conversions
private final float mError = 1f;
private final Rect mExpected;
AlmostSame(Rect expected) {
mExpected = expected;
}
@Override
protected boolean matchesSafely(RectF item) {
return Math.abs(item.left - mExpected.left) < mError
&& Math.abs(item.top - mExpected.top) < mError
&& Math.abs(item.right - mExpected.right) < mError
&& Math.abs(item.bottom - mExpected.bottom) < mError;
}
@Override
public void describeTo(Description description) {
description.appendValue(mExpected);
}
}
}

View File

@@ -105,6 +105,9 @@ public final class RecentsOrientedState implements SharedPreferences.OnSharedPre
private static final int FLAG_ROTATION_WATCHER_ENABLED = 1 << 6;
// Enable home rotation for UI tests, ignoring home rotation value from prefs
private static final int FLAG_HOME_ROTATION_FORCE_ENABLED_FOR_TESTING = 1 << 7;
// Whether the swipe gesture is running, so the recents would stay locked in the
// current orientation
private static final int FLAG_SWIPE_UP_NOT_RUNNING = 1 << 8;
private static final int MASK_MULTIPLE_ORIENTATION_SUPPORTED_BY_DEVICE =
FLAG_MULTIPLE_ORIENTATION_SUPPORTED_BY_ACTIVITY
@@ -114,7 +117,8 @@ public final class RecentsOrientedState implements SharedPreferences.OnSharedPre
// multi-window is enabled as in that case, activity itself rotates.
private static final int VALUE_ROTATION_WATCHER_ENABLED =
MASK_MULTIPLE_ORIENTATION_SUPPORTED_BY_DEVICE | FLAG_SYSTEM_ROTATION_ALLOWED
| FLAG_ROTATION_WATCHER_SUPPORTED | FLAG_ROTATION_WATCHER_ENABLED;
| FLAG_ROTATION_WATCHER_SUPPORTED | FLAG_ROTATION_WATCHER_ENABLED
| FLAG_SWIPE_UP_NOT_RUNNING;
private final Context mContext;
private final ContentResolver mContentResolver;
@@ -156,6 +160,7 @@ public final class RecentsOrientedState implements SharedPreferences.OnSharedPre
if (originalSmallestWidth < 600) {
mFlags |= FLAG_MULTIPLE_ORIENTATION_SUPPORTED_BY_DENSITY;
}
mFlags |= FLAG_SWIPE_UP_NOT_RUNNING;
initFlags();
}
@@ -166,6 +171,13 @@ public final class RecentsOrientedState implements SharedPreferences.OnSharedPre
setFlag(FLAG_MULTIWINDOW_ROTATION_ALLOWED, isMultiWindow);
}
/**
* Sets if the swipe up gesture is currently running or not
*/
public void setGestureActive(boolean isGestureActive) {
setFlag(FLAG_SWIPE_UP_NOT_RUNNING, !isGestureActive);
}
/**
* Sets the appropriate {@link PagedOrientationHandler} for {@link #mOrientationHandler}
* @param touchRotation The rotation the nav bar region that is touched is in

View File

@@ -5,6 +5,7 @@ shadows= \
com.android.launcher3.shadows.LShadowAppWidgetManager \
com.android.launcher3.shadows.LShadowBackupManager \
com.android.launcher3.shadows.LShadowBitmap \
com.android.launcher3.shadows.LShadowDisplay \
com.android.launcher3.shadows.LShadowLauncherApps \
com.android.launcher3.shadows.LShadowTypeface \
com.android.launcher3.shadows.LShadowUserManager \

View File

@@ -0,0 +1,54 @@
/*
* Copyright (C) 2020 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.shadows;
import static org.robolectric.shadow.api.Shadow.directlyOn;
import android.graphics.Point;
import android.graphics.Rect;
import android.view.Display;
import org.robolectric.annotation.Implements;
import org.robolectric.annotation.RealObject;
import org.robolectric.shadows.ShadowDisplay;
/**
* Extension of {@link ShadowDisplay} with missing shadow methods
*/
@Implements(value = Display.class)
public class LShadowDisplay extends ShadowDisplay {
private final Rect mInsets = new Rect();
@RealObject Display realObject;
/**
* Sets the insets for the display
*/
public void setInsets(Rect insets) {
mInsets.set(insets);
}
@Override
protected void getCurrentSizeRange(Point outSmallestSize, Point outLargestSize) {
directlyOn(realObject, Display.class).getCurrentSizeRange(outSmallestSize, outLargestSize);
outSmallestSize.x -= mInsets.left + mInsets.right;
outLargestSize.x -= mInsets.left + mInsets.right;
outSmallestSize.y -= mInsets.top + mInsets.bottom;
outLargestSize.y -= mInsets.top + mInsets.bottom;
}
}