Merging from ub-launcher3-master @ build 6369897
Test: manual, presubmit on the source branch
Bug:150504032
x20/teams/android-launcher/merge/ub-launcher3-master_6369897.html
Change-Id: Id94544cf790a7dcf0841f66648ac864bf2f530d4
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java
index ffc1e29..cb46c40 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java
@@ -209,6 +209,7 @@
WorkspaceItemInfo info = predictions.get(i);
PredictedAppIcon icon = PredictedAppIcon.createIcon(mSampleHotseat, info);
icon.setEnabled(false);
+ icon.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
icon.verifyHighRes();
CellLayout.LayoutParams lp = new CellLayout.LayoutParams(i, 0, 1, 1);
mSampleHotseat.addViewToCellLayout(icon, i, info.getViewId(), lp, true);
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
index d3bb4f9..9bc0975 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
@@ -349,7 +349,10 @@
mHotSeatItemsCount);
}
- private void pinPrediction(ItemInfo info) {
+ /**
+ * Pins a predicted app icon into place.
+ */
+ public void pinPrediction(ItemInfo info) {
PredictedAppIcon icon = (PredictedAppIcon) mHotseat.getChildAt(
mHotseat.getCellXFromOrder(info.rank),
mHotseat.getCellYFromOrder(info.rank));
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/PredictedAppIcon.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
index 4bbb48c..304c77f 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
@@ -15,6 +15,7 @@
*/
package com.android.launcher3.uioverrides;
+import static com.android.launcher3.accessibility.LauncherAccessibilityDelegate.PIN_PREDICTION;
import static com.android.launcher3.graphics.IconShape.getShape;
import android.content.Context;
@@ -26,15 +27,19 @@
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityNodeInfo;
import androidx.core.graphics.ColorUtils;
import com.android.launcher3.CellLayout;
import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.ItemInfo;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.WorkspaceItemInfo;
+import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
import com.android.launcher3.graphics.IconPalette;
+import com.android.launcher3.hybridhotseat.HotseatPredictionController;
import com.android.launcher3.icons.IconNormalizer;
import com.android.launcher3.touch.ItemClickHandler;
import com.android.launcher3.touch.ItemLongClickListener;
@@ -43,7 +48,8 @@
/**
* A BubbleTextView with a ring around it's drawable
*/
-public class PredictedAppIcon extends DoubleShadowBubbleTextView {
+public class PredictedAppIcon extends DoubleShadowBubbleTextView implements
+ LauncherAccessibilityDelegate.AccessibilityActionHandler {
private static final float RING_EFFECT_RATIO = 0.11f;
@@ -97,6 +103,13 @@
super.applyFromWorkspaceItem(info);
int color = IconPalette.getMutedColor(info.bitmap.color, 0.54f);
mIconRingPaint.setColor(ColorUtils.setAlphaComponent(color, 200));
+ if (mIsPinned) {
+ setContentDescription(info.contentDescription);
+ } else {
+ setContentDescription(
+ getContext().getString(R.string.hotseat_prediction_content_description,
+ info.contentDescription));
+ }
}
/**
@@ -104,9 +117,9 @@
*/
public void pin(WorkspaceItemInfo info) {
if (mIsPinned) return;
+ mIsPinned = true;
applyFromWorkspaceItem(info);
setOnLongClickListener(ItemLongClickListener.INSTANCE_WORKSPACE);
- mIsPinned = true;
((CellLayout.LayoutParams) getLayoutParams()).canReorder = true;
invalidate();
}
@@ -122,6 +135,27 @@
}
@Override
+ public void addSupportedAccessibilityActions(AccessibilityNodeInfo accessibilityNodeInfo) {
+ accessibilityNodeInfo.addAction(
+ new AccessibilityNodeInfo.AccessibilityAction(PIN_PREDICTION,
+ getContext().getText(R.string.pin_prediction)));
+ }
+
+ @Override
+ public boolean performAccessibilityAction(int action, ItemInfo info) {
+ QuickstepLauncher launcher = Launcher.cast(Launcher.getLauncher(getContext()));
+ if (action == PIN_PREDICTION) {
+ if (launcher == null || launcher.getHotseatPredictionController() == null) {
+ return false;
+ }
+ HotseatPredictionController controller = launcher.getHotseatPredictionController();
+ controller.pinPrediction(info);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
public void getIconBounds(Rect outBounds) {
super.getIconBounds(outBounds);
if (!mIsPinned && !mIsDrawingDot) {
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 9352ace..a02d9c3 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -19,12 +19,9 @@
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
-import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
-import android.graphics.Rect;
import android.os.Bundle;
-import android.view.Gravity;
import android.view.View;
import androidx.annotation.Nullable;
@@ -38,7 +35,6 @@
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.folder.Folder;
-import com.android.launcher3.graphics.RotationMode;
import com.android.launcher3.hybridhotseat.HotseatPredictionController;
import com.android.launcher3.popup.SystemShortcut;
import com.android.launcher3.uioverrides.touchcontrollers.FlingAndHoldTouchController;
@@ -72,77 +68,6 @@
*/
public static final AsyncCommand SET_SHELF_HEIGHT = (context, arg1, arg2) ->
SystemUiProxy.INSTANCE.get(context).setShelfHeight(arg1 != 0, arg2);
- public static final RotationMode ROTATION_LANDSCAPE = new RotationMode(-90) {
- @Override
- public void mapRect(int left, int top, int right, int bottom, Rect out) {
- out.left = top;
- out.top = right;
- out.right = bottom;
- out.bottom = left;
- }
-
- @Override
- public void mapInsets(Context context, Rect insets, Rect out) {
- // If there is a display cutout, the top insets in portrait would also include the
- // cutout, which we will get as the left inset in landscape. Using the max of left and
- // top allows us to cover both cases (with or without cutout).
- if (SysUINavigationMode.getMode(context) == NO_BUTTON) {
- out.top = Math.max(insets.top, insets.left);
- out.bottom = Math.max(insets.right, insets.bottom);
- out.left = out.right = 0;
- } else {
- out.top = Math.max(insets.top, insets.left);
- out.bottom = insets.right;
- out.left = insets.bottom;
- out.right = 0;
- }
- }
- };
- public static final RotationMode ROTATION_SEASCAPE = new RotationMode(90) {
- @Override
- public void mapRect(int left, int top, int right, int bottom, Rect out) {
- out.left = bottom;
- out.top = left;
- out.right = top;
- out.bottom = right;
- }
-
- @Override
- public void mapInsets(Context context, Rect insets, Rect out) {
- if (SysUINavigationMode.getMode(context) == NO_BUTTON) {
- out.top = Math.max(insets.top, insets.right);
- out.bottom = Math.max(insets.left, insets.bottom);
- out.left = out.right = 0;
- } else {
- out.top = Math.max(insets.top, insets.right);
- out.bottom = insets.left;
- out.right = insets.bottom;
- out.left = 0;
- }
- }
-
- @Override
- public int toNaturalGravity(int absoluteGravity) {
- int horizontalGravity = absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK;
- int verticalGravity = absoluteGravity & Gravity.VERTICAL_GRAVITY_MASK;
-
- if (horizontalGravity == Gravity.RIGHT) {
- horizontalGravity = Gravity.LEFT;
- } else if (horizontalGravity == Gravity.LEFT) {
- horizontalGravity = Gravity.RIGHT;
- }
-
- if (verticalGravity == Gravity.TOP) {
- verticalGravity = Gravity.BOTTOM;
- } else if (verticalGravity == Gravity.BOTTOM) {
- verticalGravity = Gravity.TOP;
- }
-
- return ((absoluteGravity & ~Gravity.HORIZONTAL_GRAVITY_MASK)
- & ~Gravity.VERTICAL_GRAVITY_MASK)
- | horizontalGravity | verticalGravity;
- }
- };
private HotseatPredictionController mHotseatPredictionController;
@Override
@@ -154,12 +79,6 @@
}
@Override
- protected RotationMode getFakeRotationMode(DeviceProfile dp) {
- return !dp.isVerticalBarLayout() ? RotationMode.NORMAL
- : (dp.isSeascape() ? ROTATION_SEASCAPE : ROTATION_LANDSCAPE);
- }
-
- @Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
onStateOrResumeChanged();
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
index 131b71f..3d6e519 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
@@ -15,6 +15,7 @@
*/
package com.android.launcher3.uioverrides;
+import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
import static com.android.launcher3.LauncherState.OVERVIEW_BUTTONS;
import static com.android.launcher3.anim.Interpolators.AGGRESSIVE_EASE_IN_OUT;
import static com.android.launcher3.anim.Interpolators.LINEAR;
@@ -91,7 +92,7 @@
View actionsView = mLauncher.getActionsView();
if (actionsView != null) {
- propertySetter.setViewAlpha(actionsView, buttonAlpha, actionInterpolator);
+ propertySetter.setFloat(actionsView, VIEW_ALPHA, buttonAlpha, actionInterpolator);
}
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java
index 113cdec..5abeae4 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java
@@ -46,7 +46,6 @@
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
-import com.android.launcher3.graphics.RotationMode;
import com.android.launcher3.model.PagedViewOrientedState;
import com.android.launcher3.states.RotationHelper;
import com.android.launcher3.testing.TestProtocol;
@@ -149,8 +148,8 @@
VibratorWrapper.INSTANCE.get(mContext).vibrate(OVERVIEW_HAPTIC);
}
- public Consumer<MotionEvent> getRecentsViewDispatcher(RotationMode navBarRotationMode) {
- return mRecentsView != null ? mRecentsView.getEventDispatcher(navBarRotationMode) : null;
+ public Consumer<MotionEvent> getRecentsViewDispatcher(float navbarRotation) {
+ return mRecentsView != null ? mRecentsView.getEventDispatcher(navbarRotation) : null;
}
@UiThread
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
index 2d0f978..c889632 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
@@ -444,9 +444,12 @@
GestureState newGestureState;
if (mDeviceState.isInSwipeUpTouchRegion(event)) {
+ // Clone the previous gesture state since onConsumerAboutToBeSwitched might trigger
+ // onConsumerInactive and wipe the previous gesture state
+ GestureState prevGestureState = new GestureState(mGestureState);
newGestureState = createGestureState();
mConsumer.onConsumerAboutToBeSwitched();
- mConsumer = newConsumer(mGestureState, newGestureState, event);
+ mConsumer = newConsumer(prevGestureState, newGestureState, event);
ActiveGestureLog.INSTANCE.addLog("setInputConsumer", mConsumer.getType());
mUncheckedConsumer = mConsumer;
@@ -678,7 +681,7 @@
* To be called by the consumer when it's no longer active.
*/
private void onConsumerInactive(InputConsumer caller) {
- if (mConsumer == caller) {
+ if (mConsumer != null && mConsumer.isInConsumerHierarchy(caller)) {
mConsumer = mUncheckedConsumer = mResetGestureInputConsumer;
mGestureState = new GestureState();
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DelegateInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DelegateInputConsumer.java
index 71465eb..bcc9707 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DelegateInputConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DelegateInputConsumer.java
@@ -30,6 +30,11 @@
}
@Override
+ public boolean isInConsumerHierarchy(InputConsumer candidate) {
+ return this == candidate || mDelegate.isInConsumerHierarchy(candidate);
+ }
+
+ @Override
public boolean allowInterceptByParent() {
return mDelegate.allowInterceptByParent() && mState != STATE_ACTIVE;
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
index a462949..fe9ef2b 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
@@ -182,7 +182,7 @@
if (mPassedWindowMoveSlop && mInteractionHandler != null
&& !mRecentsViewDispatcher.hasConsumer()) {
mRecentsViewDispatcher.setConsumer(mInteractionHandler
- .getRecentsViewDispatcher(mNavBarPosition.getRotationMode()));
+ .getRecentsViewDispatcher(mNavBarPosition.getRotation()));
}
int edgeFlags = ev.getEdgeFlags();
ev.setEdgeFlags(edgeFlags | EDGE_NAV_BAR);
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java
index e62de18..98eb29a 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -42,7 +42,6 @@
import com.android.launcher3.Hotseat;
import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherStateManager.StateListener;
-import com.android.launcher3.R;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.appprediction.PredictionUiStateManager;
import com.android.launcher3.appprediction.PredictionUiStateManager.Client;
@@ -172,7 +171,7 @@
mActivity.getAllAppsController(), ALL_APPS_PROGRESS, allAppsProgressOffscreen));
ObjectAnimator dragHandleAnim = ObjectAnimator.ofInt(
- mActivity.findViewById(R.id.scrim_view), ScrimView.DRAG_HANDLE_ALPHA, 0);
+ mActivity.getScrimView(), ScrimView.DRAG_HANDLE_ALPHA, 0);
dragHandleAnim.setInterpolator(Interpolators.ACCEL_2);
anim.play(dragHandleAnim);
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
index 1c95a9e..e3b3102 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
@@ -71,6 +71,7 @@
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
+import android.view.OrientationEventListener;
import android.view.View;
import android.view.ViewDebug;
import android.view.ViewGroup;
@@ -90,6 +91,7 @@
import com.android.launcher3.PagedView;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
+import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.anim.PendingAnimation.EndState;
@@ -97,9 +99,9 @@
import com.android.launcher3.anim.SpringProperty;
import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.graphics.RotationMode;
import com.android.launcher3.statehandlers.DepthController;
import com.android.launcher3.states.RotationHelper;
+import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.touch.PagedOrientationHandler.CurveProperties;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
@@ -169,6 +171,7 @@
}
};
+ private OrientationEventListener mOrientationListener;
private int mPreviousRotation;
protected RecentsAnimationController mRecentsAnimationController;
protected RecentsAnimationTargets mRecentsAnimationTargets;
@@ -376,6 +379,22 @@
// Initialize quickstep specific cache params here, as this is constructed only once
mActivity.getViewCache().setCacheSize(R.layout.digital_wellbeing_toast, 5);
+
+ mOrientationListener = new OrientationEventListener(getContext()) {
+ @Override
+ public void onOrientationChanged(int i) {
+ int rotation = RotationHelper.getRotationFromDegrees(i);
+ if (mPreviousRotation != rotation) {
+ animateRecentsRotationInPlace(rotation);
+ if (rotation == 0) {
+ showActionsView();
+ } else {
+ hideActionsView();
+ }
+ mPreviousRotation = rotation;
+ }
+ }
+ };
}
public OverScroller getScroller() {
@@ -504,6 +523,15 @@
}
public void setOverviewStateEnabled(boolean enabled) {
+ if (supportsVerticalLandscape()
+ && !TestProtocol.sDisableSensorRotation // Ignore hardware dependency for tests
+ && mOrientationListener.canDetectOrientation()) {
+ if (enabled) {
+ mOrientationListener.enable();
+ } else {
+ mOrientationListener.disable();
+ }
+ }
mOverviewStateEnabled = enabled;
updateTaskStackListenerState();
if (!enabled) {
@@ -784,23 +812,14 @@
if (getPageCount() == 0 || getPageAt(0).getMeasuredWidth() == 0) {
return;
}
- CurveProperties curveProperties = mOrientationHandler
- .getCurveProperties(this, mInsets);
- int scroll = curveProperties.scroll;
- final int halfPageSize = curveProperties.halfPageSize;
- final int screenCenter = curveProperties.screenCenter;
- final int halfScreenSize = curveProperties.halfScreenSize;
- final int pageSpacing = mPageSpacing;
- mScrollState.scrollFromEdge = mIsRtl ? scroll : (mMaxScroll - scroll);
+ mOrientationHandler.getCurveProperties(this, mInsets, mScrollState);
+ mScrollState.scrollFromEdge =
+ mIsRtl ? mScrollState.scroll : (mMaxScroll - mScrollState.scroll);
final int pageCount = getPageCount();
for (int i = 0; i < pageCount; i++) {
View page = getPageAt(i);
- float pageCenter = mOrientationHandler.getViewCenterPosition(page) + halfPageSize;
- float distanceFromScreenCenter = screenCenter - pageCenter;
- float distanceToReachEdge = halfScreenSize + halfPageSize + pageSpacing;
- mScrollState.linearInterpolation = Math.min(1,
- Math.abs(distanceFromScreenCenter) / distanceToReachEdge);
+ mScrollState.updateInterpolation(mOrientationHandler.getChildStart(page), mPageSpacing);
((PageCallbacks) page).onPageScroll(mScrollState);
}
}
@@ -947,6 +966,35 @@
setSwipeDownShouldLaunchApp(true);
}
+ private void animateRecentsRotationInPlace(int newRotation) {
+ if (!supportsVerticalLandscape()) {
+ return;
+ }
+
+ AnimatorSet pa = setRecentsChangedOrientation(true);
+ pa.addListener(AnimationSuccessListener.forRunnable(() -> {
+ updateLayoutRotation(newRotation);
+ mActivity.getDragLayer().recreateControllers();
+ rotateAllChildTasks();
+ setRecentsChangedOrientation(false).start();
+ }));
+ pa.start();
+ }
+
+ public AnimatorSet setRecentsChangedOrientation(boolean fadeInChildren) {
+ getRunningTaskIndex();
+ int runningIndex = getCurrentPage();
+ AnimatorSet as = new AnimatorSet();
+ for (int i = 0; i < getTaskViewCount(); i++) {
+ if (runningIndex == i) {
+ continue;
+ }
+ View taskView = getTaskViewAt(i);
+ as.play(ObjectAnimator.ofFloat(taskView, View.ALPHA, fadeInChildren ? 0 : 1));
+ }
+ return as;
+ }
+
abstract protected boolean supportsVerticalLandscape();
private void rotateAllChildTasks() {
@@ -1143,7 +1191,7 @@
default void onPageScroll(ScrollState scrollState) {}
}
- public static class ScrollState {
+ public static class ScrollState extends CurveProperties {
/**
* The progress from 0 to 1, where 0 is the center
@@ -1155,6 +1203,17 @@
* The amount by which all the content is scrolled relative to the end of the list.
*/
public float scrollFromEdge;
+
+ /**
+ * Updates linearInterpolation for the provided child position
+ */
+ public void updateInterpolation(int childStart, int pageSpacing) {
+ float pageCenter = childStart + halfPageSize;
+ float distanceFromScreenCenter = screenCenter - pageCenter;
+ float distanceToReachEdge = halfScreenSize + halfPageSize + pageSpacing;
+ linearInterpolation = Math.min(1,
+ Math.abs(distanceFromScreenCenter) / distanceToReachEdge);
+ }
}
public void setIgnoreResetTask(int taskId) {
@@ -1924,13 +1983,13 @@
return offsetX;
}
- public Consumer<MotionEvent> getEventDispatcher(RotationMode navBarRotationMode) {
+ public Consumer<MotionEvent> getEventDispatcher(float navbarRotation) {
float degreesRotated;
- if (navBarRotationMode == RotationMode.NORMAL) {
+ if (navbarRotation == 0) {
degreesRotated = mOrientationState.areMultipleLayoutOrientationsDisabled() ? 0 :
RotationHelper.getDegreesFromRotation(mLayoutRotation);
} else {
- degreesRotated = -navBarRotationMode.surfaceRotation;
+ degreesRotated = -navbarRotation;
}
if (degreesRotated == 0) {
return super::onTouchEvent;
@@ -1940,7 +1999,7 @@
// undo that transformation since PagedView also accommodates for the transformation via
// PagedOrientationHandler
return e -> {
- if (navBarRotationMode != RotationMode.NORMAL
+ if (navbarRotation != 0
&& !mOrientationState.areMultipleLayoutOrientationsDisabled()) {
RotationHelper.transformEventForNavBar(e, true);
super.onTouchEvent(e);
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 8d42c4a..dcc85d5 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -66,9 +66,6 @@
docked_stack_divider_thickness - 2 * docked_stack_divider_insets -->
<dimen name="multi_window_task_divider_size">10dp</dimen>
- <!-- same as vertical_drag_handle_size -->
- <dimen name="shelf_surface_offset">24dp</dimen>
-
<!-- Assistant Gestures -->
<!-- Distance from the vertical edges of the screen in which assist gestures are recognized -->
<dimen name="gestures_assistant_width">48dp</dimen>
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index 548a51f..f5552f0 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -90,6 +90,9 @@
<!-- tip shown if user declines migration and has some open spots for prediction -->
<string name="hotseat_tip_gaps_filled">App suggestions added to empty space</string>
+ <!-- content description for hotseat items -->
+ <string name="hotseat_prediction_content_description">Predicted app: <xliff:g id="title" example="Chrome">%1$s</xliff:g></string>
+
<!-- Title shown during interactive part of Back gesture tutorial for right edge. [CHAR LIMIT=30] -->
<string name="back_gesture_tutorial_playground_title_swipe_inward_right_edge" translatable="false">Try the back gesture</string>
<!-- Subtitle shown during interactive parts of Back gesture tutorial for right edge. [CHAR LIMIT=60] -->
diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
index 135daef..abdff0d 100644
--- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
@@ -88,9 +88,7 @@
super.onCreate(savedInstanceState);
mSystemActions = new SystemActions(this);
- SysUINavigationMode.Mode mode = SysUINavigationMode.INSTANCE.get(this)
- .addModeChangeListener(this);
- getRotationHelper().setRotationHadDifferentUI(mode != Mode.NO_BUTTON);
+ SysUINavigationMode.INSTANCE.get(this).addModeChangeListener(this);
if (!getSharedPrefs().getBoolean(HOME_BOUNCE_SEEN, false)) {
getStateManager().addStateListener(new LauncherStateManager.StateListener() {
@@ -141,7 +139,6 @@
@Override
public void onNavigationModeChanged(Mode newMode) {
getDragLayer().recreateControllers();
- getRotationHelper().setRotationHadDifferentUI(newMode != Mode.NO_BUTTON);
}
@Override
diff --git a/quickstep/src/com/android/quickstep/GestureState.java b/quickstep/src/com/android/quickstep/GestureState.java
index 631df4c..5118906 100644
--- a/quickstep/src/com/android/quickstep/GestureState.java
+++ b/quickstep/src/com/android/quickstep/GestureState.java
@@ -130,6 +130,17 @@
mGestureId = gestureId;
}
+ public GestureState(GestureState other) {
+ mHomeIntent = other.mHomeIntent;
+ mOverviewIntent = other.mOverviewIntent;
+ mActivityInterface = other.mActivityInterface;
+ mStateCallback = other.mStateCallback;
+ mGestureId = other.mGestureId;
+ mRunningTask = other.mRunningTask;
+ mEndTarget = other.mEndTarget;
+ mFinishingRecentsAnimationTaskId = other.mFinishingRecentsAnimationTaskId;
+ }
+
public GestureState() {
// Do nothing, only used for initializing the gesture state prior to user unlock
mHomeIntent = new Intent();
diff --git a/quickstep/src/com/android/quickstep/InputConsumer.java b/quickstep/src/com/android/quickstep/InputConsumer.java
index 8efaeb9..818d836 100644
--- a/quickstep/src/com/android/quickstep/InputConsumer.java
+++ b/quickstep/src/com/android/quickstep/InputConsumer.java
@@ -70,6 +70,13 @@
}
/**
+ * Returns true if the given input consumer is in the hierarchy of this input consumer.
+ */
+ default boolean isInConsumerHierarchy(InputConsumer candidate) {
+ return this == candidate;
+ }
+
+ /**
* Called by the event queue when the consumer is about to be switched to a new consumer.
* Consumers should update the state accordingly here before the state is passed to the new
* consumer.
diff --git a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialFragment.java
index 593b695..aeb718d 100644
--- a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialFragment.java
+++ b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialFragment.java
@@ -107,11 +107,11 @@
}
void onAttachedToWindow() {
- mEdgeBackGestureHandler.setIsEnabled(true);
+ mEdgeBackGestureHandler.setViewGroupParent((ViewGroup) getRootView());
}
void onDetachedFromWindow() {
- mEdgeBackGestureHandler.setIsEnabled(false);
+ mEdgeBackGestureHandler.setViewGroupParent(null);
}
@Override
diff --git a/quickstep/src/com/android/quickstep/interaction/EdgeBackGestureHandler.java b/quickstep/src/com/android/quickstep/interaction/EdgeBackGestureHandler.java
index 04cd2f4..f34530e 100644
--- a/quickstep/src/com/android/quickstep/interaction/EdgeBackGestureHandler.java
+++ b/quickstep/src/com/android/quickstep/interaction/EdgeBackGestureHandler.java
@@ -17,21 +17,18 @@
import android.content.Context;
import android.content.res.Resources;
-import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.PointF;
-import android.hardware.display.DisplayManager;
-import android.hardware.display.DisplayManager.DisplayListener;
-import android.os.Handler;
-import android.os.Looper;
import android.os.SystemProperties;
import android.view.Display;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewConfiguration;
-import android.view.WindowManager;
-import android.view.WindowManager.LayoutParams;
+import android.view.ViewGroup;
+import android.view.ViewGroup.LayoutParams;
+
+import androidx.annotation.Nullable;
import com.android.launcher3.ResourceUtils;
@@ -40,7 +37,7 @@
*
* Forked from platform/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java.
*/
-public class EdgeBackGestureHandler implements DisplayListener, OnTouchListener {
+public class EdgeBackGestureHandler implements OnTouchListener {
private static final String TAG = "EdgeBackGestureHandler";
private static final int MAX_LONG_PRESS_TIMEOUT = SystemProperties.getInt(
@@ -106,29 +103,22 @@
mEdgeWidth = ResourceUtils.getNavbarSize("config_backGestureInset", res);
}
- void setIsEnabled(boolean isEnabled) {
- if (isEnabled == mIsEnabled) {
- return;
- }
- mIsEnabled = isEnabled;
+ void setViewGroupParent(@Nullable ViewGroup parent) {
+ mIsEnabled = parent != null;
if (mEdgeBackPanel != null) {
mEdgeBackPanel.onDestroy();
mEdgeBackPanel = null;
}
- if (!mIsEnabled) {
- mContext.getSystemService(DisplayManager.class).unregisterDisplayListener(this);
- } else {
- updateDisplaySize();
- mContext.getSystemService(DisplayManager.class).registerDisplayListener(this,
- new Handler(Looper.getMainLooper()));
-
+ if (mIsEnabled) {
// Add a nav bar panel window.
- mEdgeBackPanel = new EdgeBackGesturePanel(mContext);
+ mEdgeBackPanel = new EdgeBackGesturePanel(mContext, parent, createLayoutParams());
mEdgeBackPanel.setBackCallback(mBackCallback);
- mEdgeBackPanel.setLayoutParams(createLayoutParams());
- updateDisplaySize();
+ if (mContext.getDisplay() != null) {
+ mContext.getDisplay().getRealSize(mDisplaySize);
+ mEdgeBackPanel.setDisplaySize(mDisplaySize);
+ }
}
}
@@ -136,21 +126,11 @@
mGestureCallback = callback;
}
- private WindowManager.LayoutParams createLayoutParams() {
+ private LayoutParams createLayoutParams() {
Resources resources = mContext.getResources();
- WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(
+ return new LayoutParams(
ResourceUtils.getNavbarSize("navigation_edge_panel_width", resources),
- ResourceUtils.getNavbarSize("navigation_edge_panel_height", resources),
- LayoutParams.TYPE_APPLICATION_PANEL,
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
- | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
- | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
- PixelFormat.TRANSLUCENT);
- layoutParams.setTitle(TAG + mDisplayId);
- layoutParams.windowAnimations = 0;
- layoutParams.setFitInsetsTypes(0 /* types */);
- return layoutParams;
+ ResourceUtils.getNavbarSize("navigation_edge_panel_height", resources));
}
@Override
@@ -232,26 +212,6 @@
}
}
- @Override
- public void onDisplayAdded(int displayId) { }
-
- @Override
- public void onDisplayRemoved(int displayId) { }
-
- @Override
- public void onDisplayChanged(int displayId) {
- if (displayId == mDisplayId) {
- updateDisplaySize();
- }
- }
-
- private void updateDisplaySize() {
- mContext.getDisplay().getRealSize(mDisplaySize);
- if (mEdgeBackPanel != null) {
- mEdgeBackPanel.setDisplaySize(mDisplaySize);
- }
- }
-
void setInsets(int leftInset, int rightInset) {
mLeftInset = leftInset;
mRightInset = rightInset;
diff --git a/quickstep/src/com/android/quickstep/interaction/EdgeBackGesturePanel.java b/quickstep/src/com/android/quickstep/interaction/EdgeBackGesturePanel.java
index 34eeafc..5bf5026 100644
--- a/quickstep/src/com/android/quickstep/interaction/EdgeBackGesturePanel.java
+++ b/quickstep/src/com/android/quickstep/interaction/EdgeBackGesturePanel.java
@@ -26,11 +26,11 @@
import android.graphics.Path;
import android.graphics.Point;
import android.os.SystemClock;
-import android.view.Gravity;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
-import android.view.WindowManager;
+import android.view.ViewGroup;
+import android.view.ViewGroup.LayoutParams;
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
@@ -110,7 +110,6 @@
private static final Interpolator RUBBER_BAND_INTERPOLATOR_APPEAR =
new PathInterpolator(1.0f / RUBBER_BAND_AMOUNT_APPEAR, 1.0f, 1.0f, 1.0f);
- private final WindowManager mWindowManager;
private BackCallback mBackCallback;
/**
@@ -147,7 +146,6 @@
private VelocityTracker mVelocityTracker;
private int mArrowPaddingEnd;
- private WindowManager.LayoutParams mLayoutParams;
/**
* True if the panel is currently on the left of the screen
@@ -232,11 +230,9 @@
}
};
- public EdgeBackGesturePanel(Context context) {
+ public EdgeBackGesturePanel(Context context, ViewGroup parent, LayoutParams layoutParams) {
super(context);
- mWindowManager = context.getSystemService(WindowManager.class);
-
mDensity = context.getResources().getDisplayMetrics().density;
mBaseTranslation = dp(BASE_TRANSLATION_DP);
@@ -290,11 +286,15 @@
mSwipeThreshold = ResourceUtils.getDimenByName(
"navigation_edge_action_drag_threshold", context.getResources(), 16 /* defaultValue */);
+ parent.addView(this, layoutParams);
setVisibility(GONE);
}
void onDestroy() {
- mWindowManager.removeView(this);
+ ViewGroup parent = (ViewGroup) getParent();
+ if (parent != null) {
+ parent.removeView(this);
+ }
}
@Override
@@ -305,9 +305,6 @@
@SuppressLint("RtlHardcoded")
void setIsLeftPanel(boolean isLeftPanel) {
mIsLeftPanel = isLeftPanel;
- mLayoutParams.gravity = mIsLeftPanel
- ? (Gravity.LEFT | Gravity.TOP)
- : (Gravity.RIGHT | Gravity.TOP);
}
boolean getIsLeftPanel() {
@@ -323,11 +320,6 @@
mBackCallback = callback;
}
- void setLayoutParams(WindowManager.LayoutParams layoutParams) {
- mLayoutParams = layoutParams;
- mWindowManager.addView(this, mLayoutParams);
- }
-
private float getCurrentAngle() {
return mCurrentAngle;
}
@@ -349,7 +341,6 @@
mStartY = event.getY();
setVisibility(VISIBLE);
updatePosition(event.getY());
- mWindowManager.updateViewLayout(this, mLayoutParams);
break;
case MotionEvent.ACTION_MOVE:
handleMoveEvent(event);
@@ -614,10 +605,11 @@
}
private void updatePosition(float touchY) {
- float position = touchY - mFingerOffset;
- position = Math.max(position, mMinArrowPosition);
- position -= mLayoutParams.height / 2.0f;
- mLayoutParams.y = MathUtils.clamp((int) position, 0, mDisplaySize.y);
+ float positionY = touchY - mFingerOffset;
+ positionY = Math.max(positionY, mMinArrowPosition);
+ positionY -= getLayoutParams().height / 2.0f;
+ setX(mIsLeftPanel ? 0 : mDisplaySize.x - getLayoutParams().width);
+ setY(MathUtils.clamp((int) positionY, 0, mDisplaySize.y));
}
private void setDesiredVerticalTransition(float verticalTranslation, boolean animated) {
diff --git a/quickstep/src/com/android/quickstep/util/LayoutUtils.java b/quickstep/src/com/android/quickstep/util/LayoutUtils.java
index ba99016..1f1a999 100644
--- a/quickstep/src/com/android/quickstep/util/LayoutUtils.java
+++ b/quickstep/src/com/android/quickstep/util/LayoutUtils.java
@@ -33,9 +33,6 @@
import java.lang.annotation.Retention;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS;
-import static java.lang.annotation.RetentionPolicy.SOURCE;
-
public class LayoutUtils {
private static final int MULTI_WINDOW_STRATEGY_HALF_SCREEN = 1;
@@ -68,7 +65,7 @@
// UI when shown.
extraSpace = 0;
} else {
- extraSpace = getDefaultSwipeHeight(context, dp) + dp.verticalDragHandleSizePx
+ extraSpace = getDefaultSwipeHeight(context, dp) + dp.workspacePageIndicatorHeight
+ res.getDimensionPixelSize(
R.dimen.dynamic_grid_hotseat_extra_vertical_size)
+ res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_bottom_padding);
diff --git a/quickstep/src/com/android/quickstep/util/NavBarPosition.java b/quickstep/src/com/android/quickstep/util/NavBarPosition.java
index 8dc19dc..74e6b29 100644
--- a/quickstep/src/com/android/quickstep/util/NavBarPosition.java
+++ b/quickstep/src/com/android/quickstep/util/NavBarPosition.java
@@ -17,12 +17,8 @@
import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
-import android.content.Context;
-import android.graphics.Rect;
-import android.view.Gravity;
import android.view.Surface;
-import com.android.launcher3.graphics.RotationMode;
import com.android.launcher3.util.DefaultDisplay;
import com.android.quickstep.SysUINavigationMode;
@@ -31,79 +27,6 @@
*/
public class NavBarPosition {
- public static final RotationMode ROTATION_LANDSCAPE = new RotationMode(-90) {
- @Override
- public void mapRect(int left, int top, int right, int bottom, Rect out) {
- out.left = top;
- out.top = right;
- out.right = bottom;
- out.bottom = left;
- }
-
- @Override
- public void mapInsets(Context context, Rect insets, Rect out) {
- // If there is a display cutout, the top insets in portrait would also include the
- // cutout, which we will get as the left inset in landscape. Using the max of left and
- // top allows us to cover both cases (with or without cutout).
- if (SysUINavigationMode.getMode(context) == NO_BUTTON) {
- out.top = Math.max(insets.top, insets.left);
- out.bottom = Math.max(insets.right, insets.bottom);
- out.left = out.right = 0;
- } else {
- out.top = Math.max(insets.top, insets.left);
- out.bottom = insets.right;
- out.left = insets.bottom;
- out.right = 0;
- }
- }
- };
-
- public static final RotationMode ROTATION_SEASCAPE = new RotationMode(90) {
- @Override
- public void mapRect(int left, int top, int right, int bottom, Rect out) {
- out.left = bottom;
- out.top = left;
- out.right = top;
- out.bottom = right;
- }
-
- @Override
- public void mapInsets(Context context, Rect insets, Rect out) {
- if (SysUINavigationMode.getMode(context) == NO_BUTTON) {
- out.top = Math.max(insets.top, insets.right);
- out.bottom = Math.max(insets.left, insets.bottom);
- out.left = out.right = 0;
- } else {
- out.top = Math.max(insets.top, insets.right);
- out.bottom = insets.left;
- out.right = insets.bottom;
- out.left = 0;
- }
- }
-
- @Override
- public int toNaturalGravity(int absoluteGravity) {
- int horizontalGravity = absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK;
- int verticalGravity = absoluteGravity & Gravity.VERTICAL_GRAVITY_MASK;
-
- if (horizontalGravity == Gravity.RIGHT) {
- horizontalGravity = Gravity.LEFT;
- } else if (horizontalGravity == Gravity.LEFT) {
- horizontalGravity = Gravity.RIGHT;
- }
-
- if (verticalGravity == Gravity.TOP) {
- verticalGravity = Gravity.BOTTOM;
- } else if (verticalGravity == Gravity.BOTTOM) {
- verticalGravity = Gravity.TOP;
- }
-
- return ((absoluteGravity & ~Gravity.HORIZONTAL_GRAVITY_MASK)
- & ~Gravity.VERTICAL_GRAVITY_MASK)
- | horizontalGravity | verticalGravity;
- }
- };
-
private final SysUINavigationMode.Mode mMode;
private final int mDisplayRotation;
@@ -120,8 +43,7 @@
return mMode != NO_BUTTON && mDisplayRotation == Surface.ROTATION_270;
}
- public RotationMode getRotationMode() {
- return isLeftEdge() ? ROTATION_SEASCAPE
- : (isRightEdge() ? ROTATION_LANDSCAPE : RotationMode.NORMAL);
+ public float getRotation() {
+ return isLeftEdge() ? 90 : (isRightEdge() ? -90 : 0);
}
}
diff --git a/quickstep/src/com/android/quickstep/views/ShelfScrimView.java b/quickstep/src/com/android/quickstep/views/ShelfScrimView.java
index 14c458e..c2ccd90 100644
--- a/quickstep/src/com/android/quickstep/views/ShelfScrimView.java
+++ b/quickstep/src/com/android/quickstep/views/ShelfScrimView.java
@@ -88,7 +88,6 @@
private float mShiftRange;
- private final float mShelfOffset;
private float mTopOffset;
private float mShelfTop;
private float mShelfTopAtThreshold;
@@ -110,7 +109,6 @@
mRadius = BOTTOM_CORNER_RADIUS_RATIO * Themes.getDialogCornerRadius(context);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- mShelfOffset = context.getResources().getDimension(R.dimen.shelf_surface_offset);
// Just assume the easiest UI for now, until we have the proper layout information.
mDrawingFlatColor = true;
}
@@ -179,7 +177,7 @@
Math.min(hotseatSize, LayoutUtils.getDefaultSwipeHeight(context, dp));
mDragHandleProgress = 1 - (dragHandleTop / mShiftRange);
}
- mTopOffset = dp.getInsets().top - mShelfOffset;
+ mTopOffset = dp.getInsets().top - mDragHandleSize.y;
mShelfTopAtThreshold = mShiftRange * SCRIM_CATCHUP_THRESHOLD + mTopOffset;
}
updateColors();
@@ -190,12 +188,15 @@
@Override
public void updateColors() {
super.updateColors();
+ mDragHandleOffset = 0;
if (mDrawingFlatColor) {
- mDragHandleOffset = 0;
return;
}
- mDragHandleOffset = mShelfOffset - mDragHandleSize;
+ if (mProgress < mDragHandleProgress) {
+ mDragHandleOffset = mShiftRange * (mDragHandleProgress - mProgress);
+ }
+
if (mProgress >= SCRIM_CATCHUP_THRESHOLD) {
mShelfTop = mShiftRange * mProgress + mTopOffset;
} else {
@@ -231,10 +232,6 @@
(float) 0, LINEAR));
mRemainingScreenColor = setColorAlphaBound(mScrimColor, remainingScrimAlpha);
}
-
- if (mProgress < mDragHandleProgress) {
- mDragHandleOffset += mShiftRange * (mDragHandleProgress - mProgress);
- }
}
@Override
@@ -290,4 +287,9 @@
mPaint.setColor(mShelfColor);
canvas.drawRoundRect(0, mShelfTop, width, height + mRadius, mRadius, mRadius, mPaint);
}
+
+ @Override
+ public float getVisualTop() {
+ return mShelfTop;
+ }
}
diff --git a/res/drawable-v24/drag_handle_indicator_shadow.xml b/res/drawable-v24/drag_handle_indicator_shadow.xml
new file mode 100644
index 0000000..774bc38
--- /dev/null
+++ b/res/drawable-v24/drag_handle_indicator_shadow.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<com.android.launcher3.graphics.ShadowDrawable
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:src="@drawable/drag_handle_indicator_no_shadow"
+ android:elevation="@dimen/vertical_drag_handle_elevation" />
diff --git a/res/drawable/drag_handle_indicator.xml b/res/drawable/drag_handle_indicator.xml
deleted file mode 100644
index b01b84a..0000000
--- a/res/drawable/drag_handle_indicator.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 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.
--->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="@dimen/vertical_drag_handle_size"
- android:height="@dimen/vertical_drag_handle_size"
- android:viewportWidth="36.0"
- android:viewportHeight="36.0" >
-
- <group
- android:translateX="11.5"
- android:translateY="11.5">
- <path
- android:pathData="M2 8.5L6.5 4L11 8.5"
- android:strokeColor="?attr/workspaceAmbientShadowColor"
- android:strokeWidth="3.6"
- android:strokeLineCap="round"
- android:strokeLineJoin="round" />
-
- <path
- android:pathData="M2 8.5L6.5 4L11 8.5"
- android:strokeColor="?attr/workspaceTextColor"
- android:strokeWidth="1.8"
- android:strokeLineCap="round"
- android:strokeLineJoin="round" />
- </group>
-</vector>
diff --git a/res/drawable/drag_handle_indicator_no_shadow.xml b/res/drawable/drag_handle_indicator_no_shadow.xml
new file mode 100644
index 0000000..341e60c
--- /dev/null
+++ b/res/drawable/drag_handle_indicator_no_shadow.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="@dimen/vertical_drag_handle_width"
+ android:height="@dimen/vertical_drag_handle_height"
+ android:viewportWidth="18.0"
+ android:viewportHeight="6.0"
+ android:tint="?attr/workspaceTextColor" >
+
+ <path
+ android:pathData="M17,6c-0.15,0-0.3-0.03-0.45-0.11L9,2.12L1.45,5.89c-0.5,0.25-1.09,
+ 0.05-1.34-0.45S0.06,4.35,0.55,4.11l8-4c0.28-0.14,0.61-0.14,0.89,0l8,4c0.49,0.25,0.69,
+ 0.85,0.45,1.34C17.72,5.8,17.37,6,17,6z"
+ android:fillColor="@android:color/white" />
+</vector>
diff --git a/res/layout/launcher.xml b/res/layout/launcher.xml
index ab6c960..de13277 100644
--- a/res/layout/launcher.xml
+++ b/res/layout/launcher.xml
@@ -57,7 +57,7 @@
<com.android.launcher3.pageindicators.WorkspacePageIndicator
android:id="@+id/page_indicator"
android:layout_width="match_parent"
- android:layout_height="@dimen/vertical_drag_handle_size"
+ android:layout_height="@dimen/workspace_page_indicator_height"
android:layout_gravity="bottom|center_horizontal"
android:theme="@style/HomeScreenElementTheme" />
diff --git a/res/values/config.xml b/res/values/config.xml
index 1675a98..ef67613 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -109,6 +109,7 @@
<item type="id" name="action_dismiss_notification" />
<item type="id" name="action_remote_action_shortcut" />
<item type="id" name="action_dismiss_prediction" />
+ <item type="id" name="action_pin_prediction"/>
<!-- QSB IDs. DO not change -->
<item type="id" name="search_container_workspace" />
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 271511e..0b589a2 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -20,7 +20,6 @@
<!-- Dynamic Grid -->
<dimen name="dynamic_grid_edge_margin">8dp</dimen>
- <dimen name="dynamic_grid_page_indicator_line_height">1dp</dimen>
<dimen name="dynamic_grid_icon_drawable_padding">8dp</dimen>
<!-- Minimum space between workspace and hotseat in spring loaded mode -->
<dimen name="dynamic_grid_min_spring_loaded_space">8dp</dimen>
@@ -36,10 +35,18 @@
<dimen name="dynamic_grid_hotseat_extra_vertical_size">34dp</dimen>
<dimen name="dynamic_grid_hotseat_side_padding">0dp</dimen>
+ <!-- Workspace page indicator -->
+ <dimen name="workspace_page_indicator_height">24dp</dimen>
+ <dimen name="workspace_page_indicator_line_height">1dp</dimen>
+ <dimen name="workspace_page_indicator_overlap_workspace">0dp</dimen>
+
<!-- Hotseat/all-apps scrim -->
<dimen name="all_apps_scrim_blur">4dp</dimen>
- <dimen name="vertical_drag_handle_size">24dp</dimen>
- <dimen name="vertical_drag_handle_overlap_workspace">0dp</dimen>
+ <dimen name="vertical_drag_handle_width">18dp</dimen>
+ <dimen name="vertical_drag_handle_height">6dp</dimen>
+ <dimen name="vertical_drag_handle_elevation">1dp</dimen>
+ <dimen name="vertical_drag_handle_touch_size">48dp</dimen>
+ <dimen name="vertical_drag_handle_padding_in_vertical_bar_layout">16dp</dimen>
<!-- Drop target bar -->
<dimen name="dynamic_grid_drop_target_size">48dp</dimen>
diff --git a/res/values/drawables.xml b/res/values/drawables.xml
index 9c57ec1..7d63142 100644
--- a/res/values/drawables.xml
+++ b/res/values/drawables.xml
@@ -18,4 +18,5 @@
<drawable name="ic_remove_shadow">@drawable/ic_remove_no_shadow</drawable>
<drawable name="ic_uninstall_shadow">@drawable/ic_uninstall_no_shadow</drawable>
<drawable name="ic_block_shadow">@drawable/ic_block_no_shadow</drawable>
+ <drawable name="all_apps_arrow_shadow">@drawable/drag_handle_indicator_no_shadow</drawable>
</resources>
\ No newline at end of file
diff --git a/robolectric_tests/src/com/android/launcher3/model/DefaultLayoutProviderTest.java b/robolectric_tests/src/com/android/launcher3/model/DefaultLayoutProviderTest.java
index f8ac010..7bc34cf 100644
--- a/robolectric_tests/src/com/android/launcher3/model/DefaultLayoutProviderTest.java
+++ b/robolectric_tests/src/com/android/launcher3/model/DefaultLayoutProviderTest.java
@@ -30,11 +30,8 @@
import com.android.launcher3.FolderInfo;
import com.android.launcher3.ItemInfo;
-import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.icons.BitmapInfo;
-import com.android.launcher3.model.BgDataModel.Callbacks;
-import com.android.launcher3.util.Executors;
import com.android.launcher3.util.LauncherLayoutBuilder;
import com.android.launcher3.util.LauncherModelHelper;
import com.android.launcher3.util.LauncherRoboTestRunner;
@@ -46,8 +43,6 @@
import org.robolectric.annotation.LooperMode;
import org.robolectric.annotation.LooperMode.Mode;
-import java.util.ArrayList;
-
/**
* Tests for layout parser for remote layout
*/
@@ -120,18 +115,6 @@
}
private void writeLayoutAndLoad(LauncherLayoutBuilder builder) throws Exception {
- mModelHelper.setupDefaultLayoutProvider(builder);
-
- LoaderResults results = new LoaderResults(
- LauncherAppState.getInstance(mTargetContext),
- mModelHelper.getBgDataModel(),
- mModelHelper.getAllAppsList(),
- new Callbacks[0]);
- LoaderTask task = new LoaderTask(
- LauncherAppState.getInstance(mTargetContext),
- mModelHelper.getAllAppsList(),
- mModelHelper.getBgDataModel(),
- results);
- Executors.MODEL_EXECUTOR.submit(() -> task.loadWorkspace(new ArrayList<>())).get();
+ mModelHelper.setupDefaultLayoutProvider(builder).loadModelSync();
}
}
diff --git a/robolectric_tests/src/com/android/launcher3/shadows/LShadowLauncherApps.java b/robolectric_tests/src/com/android/launcher3/shadows/LShadowLauncherApps.java
index f16ed33..76cb747 100644
--- a/robolectric_tests/src/com/android/launcher3/shadows/LShadowLauncherApps.java
+++ b/robolectric_tests/src/com/android/launcher3/shadows/LShadowLauncherApps.java
@@ -127,6 +127,10 @@
@Override
protected List<LauncherActivityInfo> getShortcutConfigActivityList(String packageName,
UserHandle user) {
- return Collections.emptyList();
+ Intent intent = new Intent(Intent.ACTION_CREATE_SHORTCUT).setPackage(packageName);
+ return RuntimeEnvironment.application.getPackageManager().queryIntentActivities(intent, 0)
+ .stream()
+ .map(ri -> getLauncherActivityInfo(ri.activityInfo))
+ .collect(Collectors.toList());
}
}
diff --git a/robolectric_tests/src/com/android/launcher3/shadows/LShadowTypeface.java b/robolectric_tests/src/com/android/launcher3/shadows/LShadowTypeface.java
new file mode 100644
index 0000000..0e7c1de
--- /dev/null
+++ b/robolectric_tests/src/com/android/launcher3/shadows/LShadowTypeface.java
@@ -0,0 +1,38 @@
+/*
+ * 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 android.graphics.Typeface;
+
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.shadows.ShadowTypeface;
+
+/**
+ * Extension of {@link ShadowTypeface} with missing shadow methods
+ */
+@Implements(Typeface.class)
+public class LShadowTypeface extends ShadowTypeface {
+
+ @Implementation
+ public static Typeface create(Typeface family, int weight, boolean italic) {
+ int style = italic ? Typeface.ITALIC : Typeface.NORMAL;
+ if (weight >= 400) {
+ style |= Typeface.BOLD;
+ }
+ return create(family, style);
+ }
+}
diff --git a/robolectric_tests/src/com/android/launcher3/shadows/LShadowWallpaperManager.java b/robolectric_tests/src/com/android/launcher3/shadows/LShadowWallpaperManager.java
new file mode 100644
index 0000000..d60251c
--- /dev/null
+++ b/robolectric_tests/src/com/android/launcher3/shadows/LShadowWallpaperManager.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2019 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.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
+import android.app.WallpaperManager;
+import android.content.Context;
+
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.Shadows;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.shadows.ShadowApplication;
+import org.robolectric.shadows.ShadowUserManager;
+import org.robolectric.shadows.ShadowWallpaperManager;
+
+/**
+ * Extension of {@link ShadowUserManager} with missing shadow methods
+ */
+@Implements(WallpaperManager.class)
+public class LShadowWallpaperManager extends ShadowWallpaperManager {
+
+ @Implementation
+ protected static WallpaperManager getInstance(Context context) {
+ return context.getSystemService(WallpaperManager.class);
+ }
+
+ /**
+ * Remove this once the fix for
+ * https://github.com/robolectric/robolectric/issues/5285
+ * is available
+ */
+ public static void initializeMock() {
+ WallpaperManager wm = mock(WallpaperManager.class);
+ ShadowApplication shadowApplication = Shadows.shadowOf(RuntimeEnvironment.application);
+ shadowApplication.setSystemService(Context.WALLPAPER_SERVICE, wm);
+ doReturn(0).when(wm).getDesiredMinimumWidth();
+ doReturn(0).when(wm).getDesiredMinimumHeight();
+ }
+}
diff --git a/robolectric_tests/src/com/android/launcher3/shadows/ShadowOverrides.java b/robolectric_tests/src/com/android/launcher3/shadows/ShadowOverrides.java
new file mode 100644
index 0000000..131f691
--- /dev/null
+++ b/robolectric_tests/src/com/android/launcher3/shadows/ShadowOverrides.java
@@ -0,0 +1,61 @@
+/*
+ * 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 android.content.Context;
+
+import com.android.launcher3.util.MainThreadInitializedObject.ObjectProvider;
+import com.android.launcher3.util.ResourceBasedOverride;
+import com.android.launcher3.util.ResourceBasedOverride.Overrides;
+
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.shadow.api.Shadow;
+import org.robolectric.util.ReflectionHelpers.ClassParameter;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Shadow for {@link Overrides} to provide custom overrides for test
+ */
+@Implements(value = Overrides.class, isInAndroidSdk = false)
+public class ShadowOverrides {
+
+ private static Map<Class, ObjectProvider> sProviderMap = new HashMap<>();
+
+ @Implementation
+ public static <T extends ResourceBasedOverride> T getObject(
+ Class<T> clazz, Context context, int resId) {
+ ObjectProvider<T> provider = sProviderMap.get(clazz);
+ if (provider != null) {
+ return provider.get(context);
+ }
+ return Shadow.directlyOn(Overrides.class, "getObject",
+ ClassParameter.from(Class.class, clazz),
+ ClassParameter.from(Context.class, context),
+ ClassParameter.from(int.class, resId));
+ }
+
+ public static <T> void setProvider(Class<T> clazz, ObjectProvider<T> provider) {
+ sProviderMap.put(clazz, provider);
+ }
+
+ public static void clearProvider() {
+ sProviderMap.clear();
+ }
+}
diff --git a/robolectric_tests/src/com/android/launcher3/ui/LauncherUIScrollTest.java b/robolectric_tests/src/com/android/launcher3/ui/LauncherUIScrollTest.java
new file mode 100644
index 0000000..209bae0
--- /dev/null
+++ b/robolectric_tests/src/com/android/launcher3/ui/LauncherUIScrollTest.java
@@ -0,0 +1,207 @@
+/*
+ * 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.ui;
+
+import static android.view.View.MeasureSpec.EXACTLY;
+import static android.view.View.MeasureSpec.makeMeasureSpec;
+
+import static com.android.launcher3.util.LauncherModelHelper.TEST_PACKAGE;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.mockito.Mockito.mock;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.SystemClock;
+import android.provider.Settings;
+import android.view.InputDevice;
+import android.view.MotionEvent;
+import android.view.MotionEvent.PointerProperties;
+import android.view.View;
+
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.InvariantDeviceProfile;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherState;
+import com.android.launcher3.folder.Folder;
+import com.android.launcher3.folder.FolderIcon;
+import com.android.launcher3.folder.FolderPagedView;
+import com.android.launcher3.logging.UserEventDispatcher;
+import com.android.launcher3.shadows.ShadowOverrides;
+import com.android.launcher3.util.LauncherLayoutBuilder;
+import com.android.launcher3.util.LauncherLayoutBuilder.FolderBuilder;
+import com.android.launcher3.util.LauncherModelHelper;
+import com.android.launcher3.util.LauncherRoboTestRunner;
+import com.android.launcher3.util.ViewOnDrawExecutor;
+import com.android.launcher3.widget.WidgetsFullSheet;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.Robolectric;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.LooperMode;
+import org.robolectric.annotation.LooperMode.Mode;
+import org.robolectric.shadows.ShadowLooper;
+import org.robolectric.util.ReflectionHelpers;
+
+/**
+ * Tests scroll behavior at various Launcher UI components
+ */
+@RunWith(LauncherRoboTestRunner.class)
+@LooperMode(Mode.PAUSED)
+public class LauncherUIScrollTest {
+
+ private Context mTargetContext;
+ private InvariantDeviceProfile mIdp;
+ private LauncherModelHelper mModelHelper;
+
+ private LauncherLayoutBuilder mLayoutBuilder;
+
+ @Before
+ public void setup() throws Exception {
+ mModelHelper = new LauncherModelHelper();
+ mTargetContext = RuntimeEnvironment.application;
+ mIdp = InvariantDeviceProfile.INSTANCE.get(mTargetContext);
+ ShadowOverrides.setProvider(UserEventDispatcher.class,
+ c -> mock(UserEventDispatcher.class));
+
+ Settings.Global.putFloat(mTargetContext.getContentResolver(),
+ Settings.Global.WINDOW_ANIMATION_SCALE, 0);
+
+ mModelHelper.installApp(TEST_PACKAGE);
+ // LayoutBuilder with 3 workspace pages
+ mLayoutBuilder = new LauncherLayoutBuilder()
+ .atWorkspace(0, mIdp.numRows - 1, 0).putApp(TEST_PACKAGE, TEST_PACKAGE)
+ .atWorkspace(0, mIdp.numRows - 1, 1).putApp(TEST_PACKAGE, TEST_PACKAGE)
+ .atWorkspace(0, mIdp.numRows - 1, 2).putApp(TEST_PACKAGE, TEST_PACKAGE);
+ }
+
+ @Test
+ public void testWorkspacePagesBound() throws Exception {
+ // Verify that the workspace if bound synchronously
+ Launcher launcher = loadLauncher();
+ assertEquals(3, launcher.getWorkspace().getPageCount());
+ assertEquals(0, launcher.getWorkspace().getCurrentPage());
+
+ launcher.dispatchGenericMotionEvent(createScrollEvent(-1));
+ assertNotEquals("Workspace was not scrolled",
+ 0, launcher.getWorkspace().getNextPage());
+ }
+
+ @Test
+ public void testAllAppsScroll() throws Exception {
+ // Install 100 apps
+ for (int i = 0; i < 100; i++) {
+ mModelHelper.installApp(TEST_PACKAGE + i);
+ }
+
+ // Bind and open all-apps
+ Launcher launcher = loadLauncher();
+ launcher.getStateManager().goToState(LauncherState.ALL_APPS, false);
+ doLayout(launcher);
+
+ int currentScroll = launcher.getAppsView().getActiveRecyclerView().getCurrentScrollY();
+ launcher.dispatchGenericMotionEvent(createScrollEvent(-1));
+ int newScroll = launcher.getAppsView().getActiveRecyclerView().getCurrentScrollY();
+
+ assertNotEquals("All Apps was not scrolled", currentScroll, newScroll);
+ assertEquals("Workspace was scrolled", 0, launcher.getWorkspace().getNextPage());
+ }
+
+ @Test
+ public void testWidgetsListScroll() throws Exception {
+ // Install 100 widgets
+ for (int i = 0; i < 100; i++) {
+ mModelHelper.installCustomShortcut(TEST_PACKAGE + i, "shortcutProvider");
+ }
+
+ // Bind and open widgets
+ Launcher launcher = loadLauncher();
+ WidgetsFullSheet widgets = WidgetsFullSheet.show(launcher, false);
+ doLayout(launcher);
+
+ int currentScroll = widgets.getRecyclerView().getCurrentScrollY();
+ launcher.dispatchGenericMotionEvent(createScrollEvent(-1));
+ int newScroll = widgets.getRecyclerView().getCurrentScrollY();
+ assertNotEquals("Widgets was not scrolled", currentScroll, newScroll);
+ assertEquals("Workspace was scrolled", 0, launcher.getWorkspace().getNextPage());
+ }
+
+ @Test
+ public void testFolderPageScroll() throws Exception {
+ // Add a folder with multiple icons
+ FolderBuilder fb = mLayoutBuilder.atWorkspace(mIdp.numColumns / 2, mIdp.numRows / 2, 0)
+ .putFolder(0);
+ for (int i = 0; i < 100; i++) {
+ fb.addApp(TEST_PACKAGE, TEST_PACKAGE);
+ }
+
+ // Bind and open folder
+ Launcher launcher = loadLauncher();
+ doLayout(launcher);
+ launcher.getWorkspace().getFirstMatch((i, v) -> v instanceof FolderIcon).performClick();
+ ShadowLooper.idleMainLooper();
+ doLayout(launcher);
+ FolderPagedView folderPages = Folder.getOpen(launcher).getContent();
+
+ assertEquals(0, folderPages.getNextPage());
+ launcher.dispatchGenericMotionEvent(createScrollEvent(-1));
+ assertNotEquals("Folder page was not scrolled", 0, folderPages.getNextPage());
+ assertEquals("Workspace was scrolled", 0, launcher.getWorkspace().getNextPage());
+ }
+
+ private Launcher loadLauncher() throws Exception {
+ mModelHelper.setupDefaultLayoutProvider(mLayoutBuilder).loadModelSync();
+
+ Launcher launcher = Robolectric.buildActivity(Launcher.class).setup().get();
+ doLayout(launcher);
+ ViewOnDrawExecutor executor = ReflectionHelpers.getField(launcher, "mPendingExecutor");
+ if (executor != null) {
+ executor.runAllTasks();
+ }
+ return launcher;
+ }
+
+ private static void doLayout(Activity activity) {
+ DeviceProfile dp = InvariantDeviceProfile.INSTANCE
+ .get(RuntimeEnvironment.application).portraitProfile;
+ View view = activity.getWindow().getDecorView();
+ view.measure(makeMeasureSpec(dp.widthPx, EXACTLY), makeMeasureSpec(dp.heightPx, EXACTLY));
+ view.layout(0, 0, dp.widthPx, dp.heightPx);
+ ShadowLooper.idleMainLooper();
+ }
+
+ private static MotionEvent createScrollEvent(int scroll) {
+ DeviceProfile dp = InvariantDeviceProfile.INSTANCE
+ .get(RuntimeEnvironment.application).portraitProfile;
+
+ final PointerProperties[] pointerProperties = new PointerProperties[1];
+ pointerProperties[0] = new PointerProperties();
+ pointerProperties[0].id = 0;
+ final MotionEvent.PointerCoords[] coords = new MotionEvent.PointerCoords[1];
+ coords[0] = new MotionEvent.PointerCoords();
+ coords[0].setAxisValue(MotionEvent.AXIS_VSCROLL, scroll);
+ coords[0].x = dp.widthPx / 2;
+ coords[0].y = dp.heightPx / 2;
+
+ final long time = SystemClock.uptimeMillis();
+ return MotionEvent.obtain(time, time, MotionEvent.ACTION_SCROLL, 1,
+ pointerProperties, coords, 0, 0, 1.0f, 1.0f, 0, 0,
+ InputDevice.SOURCE_CLASS_POINTER, 0);
+ }
+
+}
diff --git a/robolectric_tests/src/com/android/launcher3/util/LauncherModelHelper.java b/robolectric_tests/src/com/android/launcher3/util/LauncherModelHelper.java
index 20b1453..d593d84 100644
--- a/robolectric_tests/src/com/android/launcher3/util/LauncherModelHelper.java
+++ b/robolectric_tests/src/com/android/launcher3/util/LauncherModelHelper.java
@@ -15,6 +15,8 @@
*/
package com.android.launcher3.util;
+import static android.content.Intent.ACTION_CREATE_SHORTCUT;
+
import static com.android.launcher3.LauncherSettings.Favorites.CONTENT_URI;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
@@ -44,6 +46,7 @@
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.model.AllAppsList;
import com.android.launcher3.model.BgDataModel;
+import com.android.launcher3.model.BgDataModel.Callbacks;
import com.android.launcher3.pm.UserCache;
import org.mockito.ArgumentCaptor;
@@ -61,6 +64,7 @@
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
+import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.function.Function;
@@ -345,7 +349,8 @@
/**
* Sets up a dummy provider to load the provided layout by default, next time the layout loads
*/
- public void setupDefaultLayoutProvider(LauncherLayoutBuilder builder) throws Exception {
+ public LauncherModelHelper setupDefaultLayoutProvider(LauncherLayoutBuilder builder)
+ throws Exception {
Context context = RuntimeEnvironment.application;
InvariantDeviceProfile idp = InvariantDeviceProfile.INSTANCE.get(context);
idp.numRows = idp.numColumns = idp.numHotseatIcons = DEFAULT_GRID_SIZE;
@@ -363,23 +368,53 @@
Uri layoutUri = LauncherProvider.getLayoutUri(TEST_PROVIDER_AUTHORITY, context);
shadowOf(context.getContentResolver()).registerInputStream(layoutUri,
new ByteArrayInputStream(bos.toByteArray()));
+ return this;
}
/**
* Simulates an apk install with a default main activity with same class and package name
*/
public void installApp(String component) throws NameNotFoundException {
- ShadowPackageManager spm = shadowOf(RuntimeEnvironment.application.getPackageManager());
- ComponentName cn = new ComponentName(component, component);
- spm.addActivityIfNotPresent(cn);
-
IntentFilter filter = new IntentFilter(Intent.ACTION_MAIN);
filter.addCategory(Intent.CATEGORY_LAUNCHER);
+ installApp(component, component, filter);
+ }
+
+ /**
+ * Simulates a custom shortcut install
+ */
+ public void installCustomShortcut(String pkg, String clazz) throws NameNotFoundException {
+ installApp(pkg, clazz, new IntentFilter(ACTION_CREATE_SHORTCUT));
+ }
+
+ private void installApp(String pkg, String clazz, IntentFilter filter)
+ throws NameNotFoundException {
+ ShadowPackageManager spm = shadowOf(RuntimeEnvironment.application.getPackageManager());
+ ComponentName cn = new ComponentName(pkg, clazz);
+ spm.addActivityIfNotPresent(cn);
+
filter.addCategory(Intent.CATEGORY_DEFAULT);
spm.addIntentFilterForActivity(cn, filter);
}
/**
+ * Loads the model in memory synchronously
+ */
+ public void loadModelSync() throws ExecutionException, InterruptedException {
+ // Since robolectric tests run on main thread, we run the loader-UI calls on a temp thread,
+ // so that we can wait appropriately for the loader to complete.
+ ReflectionHelpers.setField(getModel(), "mMainExecutor", Executors.UI_HELPER_EXECUTOR);
+
+ Callbacks mockCb = mock(Callbacks.class);
+ getModel().addCallbacksAndLoad(mockCb);
+
+ Executors.MODEL_EXECUTOR.submit(() -> { }).get();
+ Executors.UI_HELPER_EXECUTOR.submit(() -> { }).get();
+ ReflectionHelpers.setField(getModel(), "mMainExecutor", Executors.MAIN_EXECUTOR);
+ getModel().removeCallbacks(mockCb);
+ }
+
+ /**
* An extension of LauncherProvider backed up by in-memory database.
*/
public static class TestLauncherProvider extends LauncherProvider {
diff --git a/robolectric_tests/src/com/android/launcher3/util/LauncherRoboTestRunner.java b/robolectric_tests/src/com/android/launcher3/util/LauncherRoboTestRunner.java
index 6277c66..744b478b 100644
--- a/robolectric_tests/src/com/android/launcher3/util/LauncherRoboTestRunner.java
+++ b/robolectric_tests/src/com/android/launcher3/util/LauncherRoboTestRunner.java
@@ -21,10 +21,13 @@
import com.android.launcher3.shadows.LShadowBackupManager;
import com.android.launcher3.shadows.LShadowBitmap;
import com.android.launcher3.shadows.LShadowLauncherApps;
+import com.android.launcher3.shadows.LShadowTypeface;
import com.android.launcher3.shadows.LShadowUserManager;
+import com.android.launcher3.shadows.LShadowWallpaperManager;
import com.android.launcher3.shadows.ShadowDeviceFlag;
import com.android.launcher3.shadows.ShadowLooperExecutor;
import com.android.launcher3.shadows.ShadowMainThreadInitializedObject;
+import com.android.launcher3.shadows.ShadowOverrides;
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
import org.junit.runners.model.InitializationError;
@@ -49,9 +52,12 @@
LShadowLauncherApps.class,
LShadowBitmap.class,
LShadowBackupManager.class,
+ LShadowTypeface.class,
+ LShadowWallpaperManager.class,
ShadowLooperExecutor.class,
ShadowMainThreadInitializedObject.class,
ShadowDeviceFlag.class,
+ ShadowOverrides.class
};
public LauncherRoboTestRunner(Class<?> testClass) throws InitializationError {
@@ -78,6 +84,9 @@
// Disable plugins
PluginManagerWrapper.INSTANCE.initializeForTesting(mock(PluginManagerWrapper.class));
+
+ // Initialize mock wallpaper manager
+ LShadowWallpaperManager.initializeMock();
}
@Override
@@ -86,6 +95,7 @@
ShadowLog.stream = null;
ShadowMainThreadInitializedObject.resetInitializedObjects();
+ ShadowOverrides.clearProvider();
}
}
}
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index c8e73ba..921e8ac 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -151,27 +151,25 @@
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.BubbleTextView, defStyle, 0);
mLayoutHorizontal = a.getBoolean(R.styleable.BubbleTextView_layoutHorizontal, false);
+ DeviceProfile grid = mActivity.getDeviceProfile();
mDisplay = a.getInteger(R.styleable.BubbleTextView_iconDisplay, DISPLAY_WORKSPACE);
final int defaultIconSize;
if (mDisplay == DISPLAY_WORKSPACE) {
- DeviceProfile grid = mActivity.getWallpaperDeviceProfile();
setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.iconTextSizePx);
setCompoundDrawablePadding(grid.iconDrawablePaddingPx);
defaultIconSize = grid.iconSizePx;
} else if (mDisplay == DISPLAY_ALL_APPS) {
- DeviceProfile grid = mActivity.getDeviceProfile();
setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.allAppsIconTextSizePx);
setCompoundDrawablePadding(grid.allAppsIconDrawablePaddingPx);
defaultIconSize = grid.allAppsIconSizePx;
} else if (mDisplay == DISPLAY_FOLDER) {
- DeviceProfile grid = mActivity.getDeviceProfile();
setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.folderChildTextSizePx);
setCompoundDrawablePadding(grid.folderChildDrawablePaddingPx);
defaultIconSize = grid.folderChildIconSizePx;
} else {
// widget_selection or shortcut_popup
- defaultIconSize = mActivity.getDeviceProfile().iconSizePx;
+ defaultIconSize = grid.iconSizePx;
}
mCenterVertically = a.getBoolean(R.styleable.BubbleTextView_centerVertically, false);
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index 9682d09..4259196 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -59,14 +59,12 @@
import com.android.launcher3.dragndrop.DraggableView;
import com.android.launcher3.folder.PreviewBackground;
import com.android.launcher3.graphics.DragPreviewProvider;
-import com.android.launcher3.graphics.RotationMode;
import com.android.launcher3.util.CellAndSpan;
import com.android.launcher3.util.GridOccupancy;
import com.android.launcher3.util.ParcelableSparseArray;
import com.android.launcher3.util.Themes;
import com.android.launcher3.util.Thunk;
import com.android.launcher3.views.ActivityContext;
-import com.android.launcher3.views.Transposable;
import com.android.launcher3.widget.LauncherAppWidgetHostView;
import java.lang.annotation.Retention;
@@ -77,7 +75,7 @@
import java.util.Comparator;
import java.util.Stack;
-public class CellLayout extends ViewGroup implements Transposable {
+public class CellLayout extends ViewGroup {
private static final String TAG = "CellLayout";
private static final boolean LOGD = false;
@@ -184,7 +182,6 @@
// Related to accessible drag and drop
private boolean mUseTouchHelper = false;
- private RotationMode mRotationMode = RotationMode.NORMAL;
public CellLayout(Context context) {
this(context, null);
@@ -206,7 +203,7 @@
setClipToPadding(false);
mActivity = ActivityContext.lookupContext(context);
- DeviceProfile grid = mActivity.getWallpaperDeviceProfile();
+ DeviceProfile grid = mActivity.getDeviceProfile();
mCellWidth = mCellHeight = -1;
mFixedCellWidth = mFixedCellHeight = -1;
@@ -314,24 +311,6 @@
}
}
- public void setRotationMode(RotationMode mode) {
- if (mRotationMode != mode) {
- mRotationMode = mode;
- requestLayout();
- }
- }
-
- @Override
- public RotationMode getRotationMode() {
- return mRotationMode;
- }
-
- @Override
- public void setPadding(int left, int top, int right, int bottom) {
- mRotationMode.mapRect(left, top, right, bottom, mTempRect);
- super.setPadding(mTempRect.left, mTempRect.top, mTempRect.right, mTempRect.bottom);
- }
-
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (mUseTouchHelper ||
@@ -789,13 +768,6 @@
int childWidthSize = widthSize - (getPaddingLeft() + getPaddingRight());
int childHeightSize = heightSize - (getPaddingTop() + getPaddingBottom());
- mShortcutsAndWidgets.setRotation(mRotationMode.surfaceRotation);
- if (mRotationMode.isTransposed) {
- int tmp = childWidthSize;
- childWidthSize = childHeightSize;
- childHeightSize = tmp;
- }
-
if (mFixedCellWidth < 0 || mFixedCellHeight < 0) {
int cw = DeviceProfile.calculateCellWidth(childWidthSize, mCountX);
int ch = DeviceProfile.calculateCellHeight(childHeightSize, mCountY);
@@ -846,15 +818,7 @@
right + mTempRect.right + getPaddingRight(),
bottom + mTempRect.bottom + getPaddingBottom());
- if (mRotationMode.isTransposed) {
- int halfW = mShortcutsAndWidgets.getMeasuredWidth() / 2;
- int halfH = mShortcutsAndWidgets.getMeasuredHeight() / 2;
- int cX = (left + right) / 2;
- int cY = (top + bottom) / 2;
- mShortcutsAndWidgets.layout(cX - halfW, cY - halfH, cX + halfW, cY + halfH);
- } else {
- mShortcutsAndWidgets.layout(left, top, right, bottom);
- }
+ mShortcutsAndWidgets.layout(left, top, right, bottom);
}
/**
@@ -863,8 +827,7 @@
* width in {@link DeviceProfile#calculateCellWidth(int, int)}.
*/
public int getUnusedHorizontalSpace() {
- return (mRotationMode.isTransposed ? getMeasuredHeight() : getMeasuredWidth())
- - getPaddingLeft() - getPaddingRight() - (mCountX * mCellWidth);
+ return getMeasuredWidth() - getPaddingLeft() - getPaddingRight() - (mCountX * mCellWidth);
}
public Drawable getScrimBackground() {
diff --git a/src/com/android/launcher3/DeleteDropTarget.java b/src/com/android/launcher3/DeleteDropTarget.java
index 423f2bb..6f0ebd2 100644
--- a/src/com/android/launcher3/DeleteDropTarget.java
+++ b/src/com/android/launcher3/DeleteDropTarget.java
@@ -67,7 +67,7 @@
public boolean supportsAccessibilityDrop(ItemInfo info, View view) {
if (info instanceof WorkspaceItemInfo) {
// Support the action unless the item is in a context menu.
- return info.screenId >= 0;
+ return canRemove(info);
}
return (info instanceof LauncherAppWidgetInfo)
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index c049069..4e1e586 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -76,9 +76,9 @@
public float workspaceSpringLoadShrinkFactor;
public final int workspaceSpringLoadedBottomSpace;
- // Drag handle
- public final int verticalDragHandleSizePx;
- private final int verticalDragHandleOverlapWorkspace;
+ // Workspace page indicator
+ public final int workspacePageIndicatorHeight;
+ private final int mWorkspacePageIndicatorOverlapWorkspace;
// Workspace icons
public int iconSizePx;
@@ -190,10 +190,10 @@
cellLayoutBottomPaddingPx = 0;
}
- verticalDragHandleSizePx = res.getDimensionPixelSize(
- R.dimen.vertical_drag_handle_size);
- verticalDragHandleOverlapWorkspace =
- res.getDimensionPixelSize(R.dimen.vertical_drag_handle_overlap_workspace);
+ workspacePageIndicatorHeight = res.getDimensionPixelSize(
+ R.dimen.workspace_page_indicator_height);
+ mWorkspacePageIndicatorOverlapWorkspace =
+ res.getDimensionPixelSize(R.dimen.workspace_page_indicator_overlap_workspace);
iconDrawablePaddingOriginalPx =
res.getDimensionPixelSize(R.dimen.dynamic_grid_icon_drawable_padding);
@@ -211,7 +211,7 @@
hotseatBarSidePaddingEndPx =
res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_side_padding);
// Add a bit of space between nav bar and hotseat in vertical bar layout.
- hotseatBarSidePaddingStartPx = isVerticalBarLayout() ? verticalDragHandleSizePx : 0;
+ hotseatBarSidePaddingStartPx = isVerticalBarLayout() ? workspacePageIndicatorHeight : 0;
hotseatBarSizePx = ResourceUtils.pxFromDp(inv.iconSize, dm) + (isVerticalBarLayout()
? (hotseatBarSidePaddingStartPx + hotseatBarSidePaddingEndPx)
: (res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_extra_vertical_size)
@@ -227,7 +227,7 @@
// in portrait mode closer together by adding more height to the hotseat.
// Note: This calculation was created after noticing a pattern in the design spec.
int extraSpace = getCellSize().y - iconSizePx - iconDrawablePaddingPx * 2
- - verticalDragHandleSizePx;
+ - workspacePageIndicatorHeight;
hotseatBarSizePx += extraSpace;
hotseatBarBottomPaddingPx += extraSpace;
@@ -376,7 +376,7 @@
if (!isVerticalLayout) {
int expectedWorkspaceHeight = availableHeightPx - hotseatBarSizePx
- - verticalDragHandleSizePx - edgeMarginPx;
+ - workspacePageIndicatorHeight - edgeMarginPx;
float minRequiredHeight = dropTargetBarSizePx + workspaceSpringLoadedBottomSpace;
workspaceSpringLoadShrinkFactor = Math.min(
res.getInteger(R.integer.config_workspaceSpringLoadShrinkPercentage) / 100.0f,
@@ -480,14 +480,14 @@
padding.bottom = edgeMarginPx;
if (isSeascape()) {
padding.left = hotseatBarSizePx;
- padding.right = verticalDragHandleSizePx;
+ padding.right = hotseatBarSidePaddingStartPx;
} else {
- padding.left = verticalDragHandleSizePx;
+ padding.left = hotseatBarSidePaddingStartPx;
padding.right = hotseatBarSizePx;
}
} else {
- int paddingBottom = hotseatBarSizePx + verticalDragHandleSizePx
- - verticalDragHandleOverlapWorkspace;
+ int paddingBottom = hotseatBarSizePx + workspacePageIndicatorHeight
+ - mWorkspacePageIndicatorOverlapWorkspace;
if (isTablet) {
// Pad the left and right of the workspace to ensure consistent spacing
// between all icons
@@ -554,7 +554,7 @@
mInsets.top + dropTargetBarSizePx + edgeMarginPx,
mInsets.left + availableWidthPx - edgeMarginPx,
mInsets.top + availableHeightPx - hotseatBarSizePx
- - verticalDragHandleSizePx - edgeMarginPx);
+ - workspacePageIndicatorHeight - edgeMarginPx);
}
}
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index 76cfe1c..78bd2ff 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -27,15 +27,13 @@
import android.view.ViewGroup;
import android.widget.FrameLayout;
-import com.android.launcher3.graphics.RotationMode;
import com.android.launcher3.logging.StatsLogUtils.LogContainerProvider;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
-import com.android.launcher3.views.Transposable;
import java.util.ArrayList;
-public class Hotseat extends CellLayout implements LogContainerProvider, Insettable, Transposable {
+public class Hotseat extends CellLayout implements LogContainerProvider, Insettable {
@ViewDebug.ExportedProperty(category = "launcher")
private boolean mHasVerticalHotseat;
@@ -89,7 +87,7 @@
@Override
public void setInsets(Rect insets) {
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
- DeviceProfile grid = mActivity.getWallpaperDeviceProfile();
+ DeviceProfile grid = mActivity.getDeviceProfile();
insets = grid.getInsets();
if (grid.isVerticalBarLayout()) {
@@ -117,9 +115,4 @@
public boolean onTouchEvent(MotionEvent event) {
return event.getY() > getCellHeight();
}
-
- @Override
- public RotationMode getRotationMode() {
- return Launcher.getLauncher(getContext()).getRotationMode();
- }
}
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 5b9f676..043ea2f 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -56,7 +56,6 @@
import android.content.res.Configuration;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Point;
-import android.graphics.Rect;
import android.os.Build;
import android.os.Bundle;
import android.os.CancellationSignal;
@@ -102,7 +101,6 @@
import com.android.launcher3.folder.Folder;
import com.android.launcher3.folder.FolderGridOrganizer;
import com.android.launcher3.folder.FolderIcon;
-import com.android.launcher3.graphics.RotationMode;
import com.android.launcher3.icons.IconCache;
import com.android.launcher3.keyboard.CustomActionsPopup;
import com.android.launcher3.keyboard.ViewGroupFocusHelper;
@@ -317,9 +315,6 @@
private float mCurrentAssistantVisibility = 0f;
- private DeviceProfile mStableDeviceProfile;
- private RotationMode mRotationMode = RotationMode.NORMAL;
-
protected LauncherOverlayManager mOverlayManager;
// If true, overlay callbacks are deferred
private boolean mDeferOverlayCallbacks;
@@ -503,24 +498,12 @@
super.onConfigurationChanged(newConfig);
}
- public void reload() {
- onIdpChanged(mDeviceProfile.inv);
- }
-
- private boolean supportsFakeLandscapeUI() {
- return FeatureFlags.FAKE_LANDSCAPE_UI.get() && !mRotationHelper.homeScreenCanRotate();
- }
-
@Override
public void reapplyUi() {
reapplyUi(true /* cancelCurrentAnimation */);
}
public void reapplyUi(boolean cancelCurrentAnimation) {
- if (supportsFakeLandscapeUI()) {
- mRotationMode = mStableDeviceProfile == null
- ? RotationMode.NORMAL : getFakeRotationMode(mDeviceProfile);
- }
getRootView().dispatchInsets();
getStateManager().reapplyState(cancelCurrentAnimation);
}
@@ -533,7 +516,6 @@
private void onIdpChanged(InvariantDeviceProfile idp) {
mUserEventDispatcher = null;
- DeviceProfile oldWallpaperProfile = getWallpaperDeviceProfile();
initDeviceProfile(idp);
dispatchDeviceProfileChanged();
reapplyUi();
@@ -542,9 +524,7 @@
// Calling onSaveInstanceState ensures that static cache used by listWidgets is
// initialized properly.
onSaveInstanceState(new Bundle());
- if (oldWallpaperProfile != getWallpaperDeviceProfile()) {
- mModel.rebindCallbacks();
- }
+ mModel.rebindCallbacks();
}
public void onAssistantVisibilityChanged(float visibility) {
@@ -571,41 +551,8 @@
mDeviceProfile = mDeviceProfile.getMultiWindowProfile(this, mwSize);
}
- if (supportsFakeLandscapeUI() && mDeviceProfile.isVerticalBarLayout()) {
- mStableDeviceProfile = mDeviceProfile.inv.portraitProfile;
- mRotationMode = getFakeRotationMode(mDeviceProfile);
- } else {
- mStableDeviceProfile = null;
- mRotationMode = RotationMode.NORMAL;
- }
-
- mRotationHelper.updateRotationAnimation();
onDeviceProfileInitiated();
- mModelWriter = mModel.getWriter(getWallpaperDeviceProfile().isVerticalBarLayout(), true);
- }
-
- public void updateInsets(Rect insets) {
- mDeviceProfile.updateInsets(insets);
- if (mStableDeviceProfile != null) {
- Rect r = mStableDeviceProfile.getInsets();
- mRotationMode.mapInsets(this, insets, r);
- mStableDeviceProfile.updateInsets(r);
- }
- }
-
- @Override
- public RotationMode getRotationMode() {
- return mRotationMode;
- }
-
- /**
- * Device profile to be used by UI elements which are shown directly on top of the wallpaper
- * and whose presentation is tied to the wallpaper (and physical device) and not the activity
- * configuration.
- */
- @Override
- public DeviceProfile getWallpaperDeviceProfile() {
- return mStableDeviceProfile == null ? mDeviceProfile : mStableDeviceProfile;
+ mModelWriter = mModel.getWriter(getDeviceProfile().isVerticalBarLayout(), true);
}
public RotationHelper getRotationHelper() {
@@ -1193,7 +1140,7 @@
// Setup the drag controller (drop targets have to be added in reverse order in priority)
mDropTargetBar.setup(mDragController);
- mAllAppsController.setupViews(mAppsView);
+ mAllAppsController.setupViews(mAppsView, mScrimView);
}
/**
@@ -1415,6 +1362,10 @@
return mDropTargetBar;
}
+ public ScrimView getScrimView() {
+ return mScrimView;
+ }
+
public LauncherAppWidgetHost getAppWidgetHost() {
return mAppWidgetHost;
}
@@ -1753,7 +1704,6 @@
public FolderIcon addFolder(CellLayout layout, int container, final int screenId, int cellX,
int cellY) {
final FolderInfo folderInfo = new FolderInfo();
- folderInfo.title = "";
// Update the model
getModelWriter().addItemToDatabase(folderInfo, container, screenId, cellX, cellY);
@@ -2049,7 +1999,7 @@
mAppWidgetHost.clearViews();
if (mHotseat != null) {
- mHotseat.resetLayout(getWallpaperDeviceProfile().isVerticalBarLayout());
+ mHotseat.resetLayout(getDeviceProfile().isVerticalBarLayout());
}
TraceHelper.INSTANCE.endSection(traceToken);
}
@@ -2724,10 +2674,6 @@
return new TouchController[] {getDragController(), new AllAppsSwipeController(this)};
}
- protected RotationMode getFakeRotationMode(DeviceProfile deviceProfile) {
- return RotationMode.NORMAL;
- }
-
protected ScaleAndTranslation getOverviewScaleAndTranslationForNormalState() {
return new ScaleAndTranslation(1.1f, 0f, 0f);
}
diff --git a/src/com/android/launcher3/LauncherRootView.java b/src/com/android/launcher3/LauncherRootView.java
index 2b2224a..b4fbbc3 100644
--- a/src/com/android/launcher3/LauncherRootView.java
+++ b/src/com/android/launcher3/LauncherRootView.java
@@ -83,7 +83,7 @@
UI_STATE_ROOT_VIEW, drawInsetBar ? FLAG_DARK_NAV : 0);
// Update device profile before notifying th children.
- mLauncher.updateInsets(insets);
+ mLauncher.getDeviceProfile().updateInsets(insets);
boolean resetState = !insets.equals(mInsets);
setInsets(insets);
@@ -127,7 +127,7 @@
}
public void dispatchInsets() {
- mLauncher.updateInsets(mInsets);
+ mLauncher.getDeviceProfile().updateInsets(mInsets);
super.setInsets(mInsets);
}
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 7d7739e..5e47e2f 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -16,6 +16,14 @@
package com.android.launcher3;
+import static com.android.launcher3.compat.AccessibilityManagerCompat.isAccessibilityEnabled;
+import static com.android.launcher3.compat.AccessibilityManagerCompat.isObservedEventType;
+import static com.android.launcher3.config.FeatureFlags.QUICKSTEP_SPRINGS;
+import static com.android.launcher3.touch.OverScroll.OVERSCROLL_DAMP_FACTOR;
+import static com.android.launcher3.touch.PagedOrientationHandler.CANVAS_TRANSLATE;
+import static com.android.launcher3.touch.PagedOrientationHandler.VIEW_SCROLL_BY;
+import static com.android.launcher3.touch.PagedOrientationHandler.VIEW_SCROLL_TO;
+
import android.animation.LayoutTransition;
import android.animation.TimeInterpolator;
import android.annotation.SuppressLint;
@@ -42,14 +50,6 @@
import android.view.animation.Interpolator;
import android.widget.ScrollView;
-import static com.android.launcher3.compat.AccessibilityManagerCompat.isAccessibilityEnabled;
-import static com.android.launcher3.compat.AccessibilityManagerCompat.isObservedEventType;
-import static com.android.launcher3.config.FeatureFlags.QUICKSTEP_SPRINGS;
-import static com.android.launcher3.touch.OverScroll.OVERSCROLL_DAMP_FACTOR;
-import static com.android.launcher3.touch.PagedOrientationHandler.CANVAS_TRANSLATE;
-import static com.android.launcher3.touch.PagedOrientationHandler.VIEW_SCROLL_BY;
-import static com.android.launcher3.touch.PagedOrientationHandler.VIEW_SCROLL_TO;
-
import androidx.annotation.Nullable;
import com.android.launcher3.anim.Interpolators;
@@ -63,6 +63,7 @@
import com.android.launcher3.touch.PortraitPagedViewHandler;
import com.android.launcher3.util.OverScroller;
import com.android.launcher3.util.Thunk;
+import com.android.launcher3.views.ActivityContext;
import java.util.ArrayList;
@@ -1369,10 +1370,6 @@
if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
switch (event.getAction()) {
case MotionEvent.ACTION_SCROLL: {
- Launcher launcher = Launcher.getLauncher(getContext());
- if (launcher != null) {
- AbstractFloatingView.closeAllOpenViews(launcher);
- }
// Handle mouse (or ext. device) by shifting the page depending on the scroll
final float vscroll;
final float hscroll;
@@ -1383,8 +1380,8 @@
vscroll = -event.getAxisValue(MotionEvent.AXIS_VSCROLL);
hscroll = event.getAxisValue(MotionEvent.AXIS_HSCROLL);
}
- if (Math.abs(vscroll) > Math.abs(hscroll) && !isVerticalScrollable()) {
- return true;
+ if (!canScroll(Math.abs(vscroll), Math.abs(hscroll))) {
+ return false;
}
if (hscroll != 0 || vscroll != 0) {
boolean isForwardScroll = mIsRtl ? (hscroll < 0 || vscroll < 0)
@@ -1402,8 +1399,13 @@
return super.onGenericMotionEvent(event);
}
- protected boolean isVerticalScrollable() {
- return true;
+ /**
+ * Returns true if the paged view can scroll for the provided vertical and horizontal
+ * scroll values
+ */
+ protected boolean canScroll(float absVScroll, float absHScroll) {
+ ActivityContext ac = ActivityContext.lookupContext(getContext());
+ return (ac == null || AbstractFloatingView.getTopOpenView(ac) == null);
}
private void acquireVelocityTrackerAndAddMovement(MotionEvent ev) {
diff --git a/src/com/android/launcher3/ShortcutAndWidgetContainer.java b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
index c07dd9d..6326b7a 100644
--- a/src/com/android/launcher3/ShortcutAndWidgetContainer.java
+++ b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
@@ -93,7 +93,7 @@
public void setupLp(View child) {
CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
if (child instanceof LauncherAppWidgetHostView) {
- DeviceProfile profile = mActivity.getWallpaperDeviceProfile();
+ DeviceProfile profile = mActivity.getDeviceProfile();
lp.setup(mCellWidth, mCellHeight, invertLayoutHorizontally(), mCountX,
profile.appWidgetScale.x, profile.appWidgetScale.y);
} else {
@@ -108,12 +108,12 @@
public int getCellContentHeight() {
return Math.min(getMeasuredHeight(),
- mActivity.getWallpaperDeviceProfile().getCellHeight(mContainerType));
+ mActivity.getDeviceProfile().getCellHeight(mContainerType));
}
public void measureChild(View child) {
CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
- final DeviceProfile profile = mActivity.getWallpaperDeviceProfile();
+ final DeviceProfile profile = mActivity.getDeviceProfile();
if (child instanceof LauncherAppWidgetHostView) {
lp.setup(mCellWidth, mCellHeight, invertLayoutHorizontally(), mCountX,
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 122b393..0cd08d4 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -62,7 +62,6 @@
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dragndrop.FolderAdaptiveIcon;
-import com.android.launcher3.graphics.RotationMode;
import com.android.launcher3.graphics.TintedDrawableSpan;
import com.android.launcher3.icons.IconProvider;
import com.android.launcher3.icons.LauncherIcons;
@@ -72,7 +71,6 @@
import com.android.launcher3.shortcuts.ShortcutRequest;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.PackageManagerHelper;
-import com.android.launcher3.views.Transposable;
import com.android.launcher3.widget.PendingAddShortcutInfo;
import java.lang.reflect.Method;
@@ -165,7 +163,7 @@
public static float getDescendantCoordRelativeToAncestor(
View descendant, View ancestor, float[] coord, boolean includeRootScroll) {
return getDescendantCoordRelativeToAncestor(descendant, ancestor, coord, includeRootScroll,
- false, null);
+ false);
}
/**
@@ -178,15 +176,12 @@
* @param includeRootScroll Whether or not to account for the scroll of the descendant:
* sometimes this is relevant as in a child's coordinates within the descendant.
* @param ignoreTransform If true, view transform is ignored
- * @param outRotation If not null, and {@param ignoreTransform} is true, this is set to the
- * overall rotation of the view in degrees.
* @return The factor by which this descendant is scaled relative to this DragLayer. Caution
* this scale factor is assumed to be equal in X and Y, and so if at any point this
* assumption fails, we will need to return a pair of scale factors.
*/
public static float getDescendantCoordRelativeToAncestor(View descendant, View ancestor,
- float[] coord, boolean includeRootScroll, boolean ignoreTransform,
- float[] outRotation) {
+ float[] coord, boolean includeRootScroll, boolean ignoreTransform) {
float scale = 1.0f;
View v = descendant;
while(v != ancestor && v != null) {
@@ -196,19 +191,7 @@
offsetPoints(coord, -v.getScrollX(), -v.getScrollY());
}
- if (ignoreTransform) {
- if (v instanceof Transposable) {
- RotationMode m = ((Transposable) v).getRotationMode();
- if (m.isTransposed) {
- sMatrix.setRotate(m.surfaceRotation, v.getPivotX(), v.getPivotY());
- sMatrix.mapPoints(coord);
-
- if (outRotation != null) {
- outRotation[0] += m.surfaceRotation;
- }
- }
- }
- } else {
+ if (!ignoreTransform) {
v.getMatrix().mapPoints(coord);
}
offsetPoints(coord, v.getLeft(), v.getTop());
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 8bc0242..3a3de26 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -75,7 +75,6 @@
import com.android.launcher3.folder.PreviewBackground;
import com.android.launcher3.graphics.DragPreviewProvider;
import com.android.launcher3.graphics.PreloadIconDrawable;
-import com.android.launcher3.graphics.RotationMode;
import com.android.launcher3.icons.BitmapRenderer;
import com.android.launcher3.logging.UserEventDispatcher;
import com.android.launcher3.pageindicators.WorkspacePageIndicator;
@@ -125,7 +124,7 @@
private static final int ADJACENT_SCREEN_DROP_DURATION = 300;
- private static final int DEFAULT_PAGE = 0;
+ public static final int DEFAULT_PAGE = 0;
private LayoutTransition mLayoutTransition;
@Thunk final WallpaperManager mWallpaperManager;
@@ -276,20 +275,13 @@
@Override
public void setInsets(Rect insets) {
DeviceProfile grid = mLauncher.getDeviceProfile();
- DeviceProfile stableGrid = mLauncher.getWallpaperDeviceProfile();
- mMaxDistanceForFolderCreation = stableGrid.isTablet
- ? 0.75f * stableGrid.iconSizePx
- : 0.55f * stableGrid.iconSizePx;
+ mMaxDistanceForFolderCreation = grid.isTablet
+ ? 0.75f * grid.iconSizePx : 0.55f * grid.iconSizePx;
mWorkspaceFadeInAdjacentScreens = grid.shouldFadeAdjacentWorkspaceScreens();
- Rect padding = stableGrid.workspacePadding;
-
- RotationMode rotationMode = mLauncher.getRotationMode();
-
- rotationMode.mapRect(padding, mTempRect);
- setPadding(mTempRect.left, mTempRect.top, mTempRect.right, mTempRect.bottom);
- rotationMode.mapRect(stableGrid.getInsets(), mInsets);
+ Rect padding = grid.workspacePadding;
+ setPadding(padding.left, padding.top, padding.right, padding.bottom);
if (mWorkspaceFadeInAdjacentScreens) {
// In landscape mode the page spacing is set to the default.
@@ -302,12 +294,11 @@
}
- int paddingLeftRight = stableGrid.cellLayoutPaddingLeftRightPx;
- int paddingBottom = stableGrid.cellLayoutBottomPaddingPx;
+ int paddingLeftRight = grid.cellLayoutPaddingLeftRightPx;
+ int paddingBottom = grid.cellLayoutBottomPaddingPx;
for (int i = mWorkspaceScreens.size() - 1; i >= 0; i--) {
- CellLayout page = mWorkspaceScreens.valueAt(i);
- page.setRotationMode(rotationMode);
- page.setPadding(paddingLeftRight, 0, paddingLeftRight, paddingBottom);
+ mWorkspaceScreens.valueAt(i)
+ .setPadding(paddingLeftRight, 0, paddingLeftRight, paddingBottom);
}
}
@@ -327,7 +318,7 @@
float scale = 1;
if (isWidget) {
- DeviceProfile profile = mLauncher.getWallpaperDeviceProfile();
+ DeviceProfile profile = mLauncher.getDeviceProfile();
scale = Utilities.shrinkRect(r, profile.appWidgetScale.x, profile.appWidgetScale.y);
}
size[0] = r.width();
@@ -555,10 +546,9 @@
// created CellLayout.
CellLayout newScreen = (CellLayout) LayoutInflater.from(getContext()).inflate(
R.layout.workspace_screen, this, false /* attachToRoot */);
- DeviceProfile grid = mLauncher.getWallpaperDeviceProfile();
+ DeviceProfile grid = mLauncher.getDeviceProfile();
int paddingLeftRight = grid.cellLayoutPaddingLeftRightPx;
int paddingBottom = grid.cellLayoutBottomPaddingPx;
- newScreen.setRotationMode(mLauncher.getRotationMode());
newScreen.setPadding(paddingLeftRight, 0, paddingLeftRight, paddingBottom);
mWorkspaceScreens.put(screenId, newScreen);
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index c521c34..c4c4377 100644
--- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -104,10 +104,8 @@
Interpolator scaleInterpolator = config.getInterpolator(ANIM_WORKSPACE_SCALE, ZOOM_OUT);
propertySetter.setFloat(mWorkspace, SCALE_PROPERTY, mNewScale, scaleInterpolator);
- if (!hotseat.getRotationMode().isTransposed) {
- setPivotToScaleWithWorkspace(hotseat);
- setPivotToScaleWithWorkspace(qsbScaleView);
- }
+ setPivotToScaleWithWorkspace(hotseat);
+ setPivotToScaleWithWorkspace(qsbScaleView);
float hotseatScale = hotseatScaleAndTranslation.scale;
Interpolator hotseatScaleInterpolator = config.getInterpolator(ANIM_HOTSEAT_SCALE,
scaleInterpolator);
diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
index 24c846c..414abab 100644
--- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
@@ -56,6 +56,7 @@
public static final int REMOVE = R.id.action_remove;
public static final int UNINSTALL = R.id.action_uninstall;
public static final int DISMISS_PREDICTION = R.id.action_dismiss_prediction;
+ public static final int PIN_PREDICTION = R.id.action_pin_prediction;
public static final int RECONFIGURE = R.id.action_reconfigure;
protected static final int ADD_TO_WORKSPACE = R.id.action_add_to_workspace;
protected static final int MOVE = R.id.action_move;
@@ -120,6 +121,10 @@
if (!(host.getTag() instanceof ItemInfo)) return;
ItemInfo item = (ItemInfo) host.getTag();
+ if (host instanceof AccessibilityActionHandler) {
+ ((AccessibilityActionHandler) host).addSupportedAccessibilityActions(info);
+ }
+
// If the request came from keyboard, do not add custom shortcuts as that is already
// exposed as a direct shortcut
if (!fromKeyboard && ShortcutUtil.supportsShortcuts(item)) {
@@ -157,14 +162,14 @@
}
private boolean itemSupportsLongClick(View host, ItemInfo info) {
- return new CustomActionsPopup(mLauncher, host).canShow()
- || ShortcutUtil.supportsShortcuts(info);
+ return PopupContainerWithArrow.canShow(host, info)
+ || new CustomActionsPopup(mLauncher, host).canShow();
}
private boolean itemSupportsAccessibleDrag(ItemInfo item) {
if (item instanceof WorkspaceItemInfo) {
// Support the action unless the item is in a context menu.
- return item.screenId >= 0;
+ return item.screenId >= 0 && item.container != Favorites.CONTAINER_HOTSEAT_PREDICTION;
}
return (item instanceof LauncherAppWidgetInfo)
|| (item instanceof FolderInfo);
@@ -181,7 +186,7 @@
public boolean performAction(final View host, final ItemInfo item, int action) {
if (action == ACTION_LONG_CLICK) {
- if (ShortcutUtil.supportsShortcuts(item)) {
+ if (PopupContainerWithArrow.canShow(host, item)) {
// Long press should be consumed for workspace items, and it should invoke the
// Shortcuts / Notifications / Actions pop-up menu, and not start a drag as the
// standard long press path does.
@@ -195,7 +200,10 @@
}
}
}
-
+ if (host instanceof AccessibilityActionHandler
+ && ((AccessibilityActionHandler) host).performAccessibilityAction(action, item)) {
+ return true;
+ }
if (action == MOVE) {
beginAccessibleDrag(host, item);
} else if (action == ADD_TO_WORKSPACE) {
@@ -466,4 +474,20 @@
}
return screenId;
}
+
+ /**
+ * An interface allowing views to handle their own action.
+ */
+ public interface AccessibilityActionHandler {
+
+ /**
+ * performs accessibility action and returns true on success
+ */
+ boolean performAccessibilityAction(int action, ItemInfo itemInfo);
+
+ /**
+ * adds all the accessibility actions that can be handled.
+ */
+ void addSupportedAccessibilityActions(AccessibilityNodeInfo accessibilityNodeInfo);
+ }
}
diff --git a/src/com/android/launcher3/allapps/AllAppsPagedView.java b/src/com/android/launcher3/allapps/AllAppsPagedView.java
index ab4cb6b..f640c3e 100644
--- a/src/com/android/launcher3/allapps/AllAppsPagedView.java
+++ b/src/com/android/launcher3/allapps/AllAppsPagedView.java
@@ -83,7 +83,7 @@
}
@Override
- protected boolean isVerticalScrollable() {
- return false;
+ protected boolean canScroll(float absVScroll, float absHScroll) {
+ return (absHScroll > absVScroll) && super.canScroll(absVScroll, absHScroll);
}
}
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 7600f52..68b0706 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -123,8 +123,8 @@
// Use a light system UI (dark icons) if all apps is behind at least half of the
// status bar.
- boolean forceChange = shiftCurrent - mScrimView.getDragHandleSize()
- <= mLauncher.getDeviceProfile().getInsets().top / 2;
+ boolean forceChange = Math.min(shiftCurrent, mScrimView.getVisualTop())
+ <= mLauncher.getDeviceProfile().getInsets().top / 2f;
if (forceChange) {
mLauncher.getSystemUiController().updateUiState(UI_STATE_ALL_APPS, !mIsDarkTheme);
} else {
@@ -212,9 +212,9 @@
return AnimationSuccessListener.forRunnable(this::onProgressAnimationEnd);
}
- public void setupViews(AllAppsContainerView appsView) {
+ public void setupViews(AllAppsContainerView appsView, ScrimView scrimView) {
mAppsView = appsView;
- mScrimView = mLauncher.findViewById(R.id.scrim_view);
+ mScrimView = scrimView;
}
/**
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 92f5112..ec34350 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -95,9 +95,6 @@
public static final BooleanFlag ENABLE_HINTS_IN_OVERVIEW = getDebugFlag(
"ENABLE_HINTS_IN_OVERVIEW", false, "Show chip hints and gleams on the overview screen");
- public static final BooleanFlag FAKE_LANDSCAPE_UI = getDebugFlag(
- "FAKE_LANDSCAPE_UI", false, "Rotate launcher UI instead of using transposed layout");
-
public static final BooleanFlag FOLDER_NAME_SUGGEST = new DeviceFlag(
"FOLDER_NAME_SUGGEST", true,
"Suggests folder names instead of blank text.");
diff --git a/src/com/android/launcher3/dragndrop/DragLayer.java b/src/com/android/launcher3/dragndrop/DragLayer.java
index 9ece3d3..970c5a0 100644
--- a/src/com/android/launcher3/dragndrop/DragLayer.java
+++ b/src/com/android/launcher3/dragndrop/DragLayer.java
@@ -17,10 +17,6 @@
package com.android.launcher3.dragndrop;
-import static android.view.View.MeasureSpec.EXACTLY;
-import static android.view.View.MeasureSpec.getMode;
-import static android.view.View.MeasureSpec.getSize;
-
import static com.android.launcher3.anim.Interpolators.DEACCEL_1_5;
import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent;
@@ -34,14 +30,12 @@
import android.graphics.Canvas;
import android.graphics.Rect;
import android.util.AttributeSet;
-import android.view.Gravity;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.animation.Interpolator;
-import android.widget.FrameLayout;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.CellLayout;
@@ -52,12 +46,10 @@
import com.android.launcher3.Workspace;
import com.android.launcher3.folder.Folder;
import com.android.launcher3.graphics.OverviewScrim;
-import com.android.launcher3.graphics.RotationMode;
import com.android.launcher3.graphics.WorkspaceAndHotseatScrim;
import com.android.launcher3.keyboard.ViewGroupFocusHelper;
import com.android.launcher3.util.Thunk;
import com.android.launcher3.views.BaseDragLayer;
-import com.android.launcher3.views.Transposable;
import java.util.ArrayList;
@@ -560,145 +552,4 @@
public OverviewScrim getOverviewScrim() {
return mOverviewScrim;
}
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- RotationMode rotation = mActivity.getRotationMode();
- int count = getChildCount();
-
- if (!rotation.isTransposed
- || getMode(widthMeasureSpec) != EXACTLY
- || getMode(heightMeasureSpec) != EXACTLY) {
-
- for (int i = 0; i < count; i++) {
- final View child = getChildAt(i);
- child.setRotation(rotation.surfaceRotation);
- }
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- } else {
-
- for (int i = 0; i < count; i++) {
- final View child = getChildAt(i);
- if (child.getVisibility() == GONE) {
- continue;
- }
- if (!(child instanceof Transposable)) {
- measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
- } else {
- measureChildWithMargins(child, heightMeasureSpec, 0, widthMeasureSpec, 0);
-
- child.setPivotX(child.getMeasuredWidth() / 2);
- child.setPivotY(child.getMeasuredHeight() / 2);
- child.setRotation(rotation.surfaceRotation);
- }
- }
- setMeasuredDimension(getSize(widthMeasureSpec), getSize(heightMeasureSpec));
- }
- }
-
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- RotationMode rotation = mActivity.getRotationMode();
- if (!rotation.isTransposed) {
- super.onLayout(changed, left, top, right, bottom);
- return;
- }
-
- final int count = getChildCount();
-
- final int parentWidth = right - left;
- final int parentHeight = bottom - top;
-
- for (int i = 0; i < count; i++) {
- final View child = getChildAt(i);
- if (child.getVisibility() == GONE) {
- continue;
- }
-
- final FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) child.getLayoutParams();
-
- if (lp instanceof LayoutParams) {
- final LayoutParams dlp = (LayoutParams) lp;
- if (dlp.customPosition) {
- child.layout(dlp.x, dlp.y, dlp.x + dlp.width, dlp.y + dlp.height);
- continue;
- }
- }
-
- final int width = child.getMeasuredWidth();
- final int height = child.getMeasuredHeight();
-
- int childLeft;
- int childTop;
-
- int gravity = lp.gravity;
- if (gravity == -1) {
- gravity = Gravity.TOP | Gravity.START;
- }
-
- final int layoutDirection = getLayoutDirection();
-
- int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);
-
- if (child instanceof Transposable) {
- absoluteGravity = rotation.toNaturalGravity(absoluteGravity);
-
- switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
- case Gravity.CENTER_HORIZONTAL:
- childTop = (parentHeight - height) / 2 +
- lp.topMargin - lp.bottomMargin;
- break;
- case Gravity.RIGHT:
- childTop = width / 2 + lp.rightMargin - height / 2;
- break;
- case Gravity.LEFT:
- default:
- childTop = parentHeight - lp.leftMargin - width / 2 - height / 2;
- }
-
- switch (absoluteGravity & Gravity.VERTICAL_GRAVITY_MASK) {
- case Gravity.CENTER_VERTICAL:
- childLeft = (parentWidth - width) / 2 +
- lp.leftMargin - lp.rightMargin;
- break;
- case Gravity.BOTTOM:
- childLeft = parentWidth - width / 2 - height / 2 - lp.bottomMargin;
- break;
- case Gravity.TOP:
- default:
- childLeft = height / 2 - width / 2 + lp.topMargin;
- }
- } else {
- switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
- case Gravity.CENTER_HORIZONTAL:
- childLeft = (parentWidth - width) / 2 +
- lp.leftMargin - lp.rightMargin;
- break;
- case Gravity.RIGHT:
- childLeft = parentWidth - width - lp.rightMargin;
- break;
- case Gravity.LEFT:
- default:
- childLeft = lp.leftMargin;
- }
-
- switch (absoluteGravity & Gravity.VERTICAL_GRAVITY_MASK) {
- case Gravity.TOP:
- childTop = lp.topMargin;
- break;
- case Gravity.CENTER_VERTICAL:
- childTop = (parentHeight - height) / 2 +
- lp.topMargin - lp.bottomMargin;
- break;
- case Gravity.BOTTOM:
- childTop = parentHeight - height - lp.bottomMargin;
- break;
- default:
- childTop = lp.topMargin;
- }
- }
-
- child.layout(childLeft, childTop, childLeft + width, childTop + height);
- }
- }
}
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index 365e76f..202836d 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -437,7 +437,7 @@
}
mItemsInvalidated = true;
mInfo.addListener(this);
- mPreviousLabel = mInfo.title.toString();
+ Optional.ofNullable(mInfo.title).ifPresent(title -> mPreviousLabel = title.toString());
mIsPreviousLabelSuggested = !mInfo.hasOption(FLAG_MANUAL_FOLDER_NAME);
if (!isEmpty(mInfo.title)) {
@@ -1648,6 +1648,10 @@
}
}
+ public FolderPagedView getContent() {
+ return mContent;
+ }
+
private void logEditFolderLabel() {
LauncherEvent launcherEvent = LauncherEvent.newBuilder()
.setAction(Action.newBuilder().setType(Action.Type.SOFT_KEYBOARD))
diff --git a/src/com/android/launcher3/folder/FolderAnimationManager.java b/src/com/android/launcher3/folder/FolderAnimationManager.java
index b83609e..3d72b49 100644
--- a/src/com/android/launcher3/folder/FolderAnimationManager.java
+++ b/src/com/android/launcher3/folder/FolderAnimationManager.java
@@ -115,6 +115,7 @@
*/
public AnimatorSet getAnimator() {
final DragLayer.LayoutParams lp = (DragLayer.LayoutParams) mFolder.getLayoutParams();
+ mFolderIcon.getPreviewItemManager().recomputePreviewDrawingParams();
ClippedFolderIconLayoutRule rule = mFolderIcon.getLayoutRule();
final List<BubbleTextView> itemsInPreview = getPreviewIconsOnPage(0);
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index 8251d68..eda9545 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -172,7 +172,7 @@
"is dependent on this");
}
- DeviceProfile grid = activity.getWallpaperDeviceProfile();
+ DeviceProfile grid = activity.getDeviceProfile();
FolderIcon icon = (FolderIcon) LayoutInflater.from(group.getContext())
.inflate(resId, group, false);
@@ -570,8 +570,7 @@
public void drawDot(Canvas canvas) {
if (!mForceHideDot && ((mDotInfo != null && mDotInfo.hasDot()) || mDotScale > 0)) {
Rect iconBounds = mDotParams.iconBounds;
- BubbleTextView.getIconBounds(this, iconBounds,
- mActivity.getWallpaperDeviceProfile().iconSizePx);
+ BubbleTextView.getIconBounds(this, iconBounds, mActivity.getDeviceProfile().iconSizePx);
float iconScale = (float) mBackground.previewSize / iconBounds.width();
Utilities.scaleRectAboutCenter(iconBounds, iconScale);
diff --git a/src/com/android/launcher3/folder/FolderPagedView.java b/src/com/android/launcher3/folder/FolderPagedView.java
index c6d62f8..dcd0e14 100644
--- a/src/com/android/launcher3/folder/FolderPagedView.java
+++ b/src/com/android/launcher3/folder/FolderPagedView.java
@@ -16,6 +16,9 @@
package com.android.launcher3.folder;
+import static com.android.launcher3.AbstractFloatingView.TYPE_ALL;
+import static com.android.launcher3.AbstractFloatingView.TYPE_FOLDER;
+
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
@@ -27,6 +30,7 @@
import android.view.View;
import android.view.ViewDebug;
+import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BaseActivity;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.CellLayout;
@@ -258,7 +262,7 @@
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
- mPageIndicator.setScroll(l, mMaxScroll);
+ if (mMaxScroll > 0) mPageIndicator.setScroll(l, mMaxScroll);
}
/**
@@ -614,6 +618,12 @@
}
}
+ @Override
+ protected boolean canScroll(float absVScroll, float absHScroll) {
+ return AbstractFloatingView.getTopOpenViewWithType(mFolder.mLauncher,
+ TYPE_ALL & ~TYPE_FOLDER) == null;
+ }
+
public int itemsPerPage() {
return mOrganizer.getMaxItemsPerPage();
}
diff --git a/src/com/android/launcher3/folder/PreviewBackground.java b/src/com/android/launcher3/folder/PreviewBackground.java
index 2d177d2..27b906b 100644
--- a/src/com/android/launcher3/folder/PreviewBackground.java
+++ b/src/com/android/launcher3/folder/PreviewBackground.java
@@ -153,7 +153,7 @@
mBgColor = ta.getColor(R.styleable.FolderIconPreview_folderFillColor, 0);
ta.recycle();
- DeviceProfile grid = activity.getWallpaperDeviceProfile();
+ DeviceProfile grid = activity.getDeviceProfile();
previewSize = grid.folderIconSizePx;
basePreviewOffsetX = (availableSpaceX - previewSize) / 2;
diff --git a/src/com/android/launcher3/graphics/RotationMode.java b/src/com/android/launcher3/graphics/RotationMode.java
deleted file mode 100644
index 6dd356a..0000000
--- a/src/com/android/launcher3/graphics/RotationMode.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2019 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.graphics;
-
-import android.content.Context;
-import android.graphics.Rect;
-
-public abstract class RotationMode {
-
- public static final RotationMode NORMAL = new RotationMode(0) { };
-
- public final float surfaceRotation;
- public final boolean isTransposed;
-
- public RotationMode(float surfaceRotation) {
- this.surfaceRotation = surfaceRotation;
- isTransposed = surfaceRotation != 0;
- }
-
- public final void mapRect(Rect rect, Rect out) {
- mapRect(rect.left, rect.top, rect.right, rect.bottom, out);
- }
-
- public void mapRect(int left, int top, int right, int bottom, Rect out) {
- out.set(left, top, right, bottom);
- }
-
- public void mapInsets(Context context, Rect insets, Rect out) {
- out.set(insets);
- }
-
- public int toNaturalGravity(int absoluteGravity) {
- return absoluteGravity;
- }
-}
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index 62904ae..fc0997b 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -45,8 +45,6 @@
import android.util.MutableInt;
import android.util.TimingLogger;
-import androidx.annotation.VisibleForTesting;
-
import com.android.launcher3.AppInfo;
import com.android.launcher3.FolderInfo;
import com.android.launcher3.InstallShortcutReceiver;
@@ -282,8 +280,7 @@
this.notify();
}
- @VisibleForTesting
- void loadWorkspace(List<ShortcutInfo> allDeepShortcuts) {
+ private void loadWorkspace(List<ShortcutInfo> allDeepShortcuts) {
loadWorkspace(allDeepShortcuts, LauncherSettings.Favorites.CONTENT_URI);
}
diff --git a/src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java b/src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java
index 0f2ca72..408796f 100644
--- a/src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java
+++ b/src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java
@@ -121,7 +121,7 @@
mLinePaint.setAlpha(0);
mLauncher = Launcher.getLauncher(context);
- mLineHeight = res.getDimensionPixelSize(R.dimen.dynamic_grid_page_indicator_line_height);
+ mLineHeight = res.getDimensionPixelSize(R.dimen.workspace_page_indicator_line_height);
boolean darkText = WallpaperColorInfo.INSTANCE.get(context).supportsDarkText();
mActiveAlpha = darkText ? BLACK_ALPHA : WHITE_ALPHA;
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index 9bac259..406e1b2 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -185,6 +185,13 @@
}
/**
+ * Returns true if we can show the container.
+ */
+ public static boolean canShow(View icon, ItemInfo item) {
+ return icon instanceof BubbleTextView && ShortcutUtil.supportsShortcuts(item);
+ }
+
+ /**
* Shows the notifications and deep shortcuts associated with {@param icon}.
* @return the container if shown or null.
*/
@@ -196,7 +203,7 @@
return null;
}
ItemInfo item = (ItemInfo) icon.getTag();
- if (!ShortcutUtil.supportsShortcuts(item)) {
+ if (!canShow(icon, item)) {
return null;
}
diff --git a/src/com/android/launcher3/states/HintState.java b/src/com/android/launcher3/states/HintState.java
index 290dbb6..43f30f1 100644
--- a/src/com/android/launcher3/states/HintState.java
+++ b/src/com/android/launcher3/states/HintState.java
@@ -17,6 +17,7 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
+import com.android.launcher3.LauncherStateManager;
import com.android.launcher3.Workspace;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
@@ -50,8 +51,13 @@
@Override
public void onStateTransitionEnd(Launcher launcher) {
- launcher.getStateManager().goToState(NORMAL);
+ LauncherStateManager stateManager = launcher.getStateManager();
Workspace workspace = launcher.getWorkspace();
- workspace.post(workspace::moveToDefaultScreen);
+ boolean willMoveScreens = workspace.getNextPage() != Workspace.DEFAULT_PAGE;
+ stateManager.goToState(NORMAL, true, willMoveScreens ? null
+ : launcher.getScrimView()::startDragHandleEducationAnim);
+ if (willMoveScreens) {
+ workspace.post(workspace::moveToDefaultScreen);
+ }
}
}
diff --git a/src/com/android/launcher3/states/RotationHelper.java b/src/com/android/launcher3/states/RotationHelper.java
index d28fcf6..8bb6a08 100644
--- a/src/com/android/launcher3/states/RotationHelper.java
+++ b/src/com/android/launcher3/states/RotationHelper.java
@@ -26,6 +26,7 @@
import static com.android.launcher3.config.FeatureFlags.FLAG_ENABLE_FIXED_ROTATION_TRANSFORM;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
+import android.app.Activity;
import android.content.ContentResolver;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
@@ -36,12 +37,9 @@
import android.provider.Settings;
import android.view.MotionEvent;
import android.view.Surface;
-import android.view.WindowManager;
-import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.UiThreadHelper;
import java.util.ArrayList;
@@ -77,7 +75,7 @@
public static final int REQUEST_ROTATE = 1;
public static final int REQUEST_LOCK = 2;
- private final Launcher mLauncher;
+ private final Activity mActivity;
private final SharedPreferences mSharedPrefs;
private final SharedPreferences mFeatureFlagsPrefs;
@@ -104,17 +102,16 @@
// This is used to defer setting rotation flags until the activity is being created
private boolean mInitialized;
private boolean mDestroyed;
- private boolean mRotationHasDifferentUI;
private int mLastActivityFlags = -1;
- public RotationHelper(Launcher launcher) {
- mLauncher = launcher;
+ public RotationHelper(Activity activity) {
+ mActivity = activity;
// On large devices we do not handle auto-rotate differently.
- mIgnoreAutoRotateSettings = mLauncher.getResources().getBoolean(R.bool.allow_rotation);
+ mIgnoreAutoRotateSettings = mActivity.getResources().getBoolean(R.bool.allow_rotation);
if (!mIgnoreAutoRotateSettings) {
- mSharedPrefs = Utilities.getPrefs(mLauncher);
+ mSharedPrefs = Utilities.getPrefs(mActivity);
mSharedPrefs.registerOnSharedPreferenceChangeListener(this);
mAutoRotateEnabled = mSharedPrefs.getBoolean(ALLOW_ROTATION_PREFERENCE_KEY,
getAllowRotationDefaultValue());
@@ -122,8 +119,8 @@
mSharedPrefs = null;
}
- mContentResolver = launcher.getContentResolver();
- mFeatureFlagsPrefs = Utilities.getFeatureFlagsPrefs(mLauncher);
+ mContentResolver = activity.getContentResolver();
+ mFeatureFlagsPrefs = Utilities.getFeatureFlagsPrefs(mActivity);
mFeatureFlagsPrefs.registerOnSharedPreferenceChangeListener(this);
updateForcedRotation(true);
}
@@ -144,7 +141,7 @@
mForcedRotation = isForcedRotation;
}
UI_HELPER_EXECUTOR.execute(() -> {
- if (mLauncher.checkSelfPermission(WRITE_SECURE_SETTINGS) == PERMISSION_GRANTED) {
+ if (mActivity.checkSelfPermission(WRITE_SECURE_SETTINGS) == PERMISSION_GRANTED) {
Settings.Global.putInt(mContentResolver, FIXED_ROTATION_TRANSFORM_SETTING_NAME,
mForcedRotation ? 1 : 0);
}
@@ -165,29 +162,6 @@
mForcedRotationChangedListeners.remove(listener);
}
- public void setRotationHadDifferentUI(boolean rotationHasDifferentUI) {
- mRotationHasDifferentUI = rotationHasDifferentUI;
- }
-
- public boolean homeScreenCanRotate() {
- return mRotationHasDifferentUI || mIgnoreAutoRotateSettings || mAutoRotateEnabled
- || mStateHandlerRequest != REQUEST_NONE
- || mLauncher.getDeviceProfile().isMultiWindowMode;
- }
-
- public void updateRotationAnimation() {
- if (FeatureFlags.FAKE_LANDSCAPE_UI.get()) {
- WindowManager.LayoutParams lp = mLauncher.getWindow().getAttributes();
- int oldAnim = lp.rotationAnimation;
- lp.rotationAnimation = homeScreenCanRotate()
- ? WindowManager.LayoutParams.ROTATION_ANIMATION_ROTATE
- : WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS;
- if (oldAnim != lp.rotationAnimation) {
- mLauncher.getWindow().setAttributes(lp);
- }
- }
- }
-
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) {
if (FLAG_ENABLE_FIXED_ROTATION_TRANSFORM.equals(s)) {
@@ -199,17 +173,13 @@
mAutoRotateEnabled = mSharedPrefs.getBoolean(ALLOW_ROTATION_PREFERENCE_KEY,
getAllowRotationDefaultValue());
if (mAutoRotateEnabled != wasRotationEnabled) {
-
notifyChange();
- updateRotationAnimation();
- mLauncher.reapplyUi();
}
}
public void setStateHandlerRequest(int request) {
if (mStateHandlerRequest != request) {
mStateHandlerRequest = request;
- updateRotationAnimation();
notifyChange();
}
}
@@ -231,7 +201,7 @@
// Used by tests only.
public void forceAllowRotationForTesting(boolean allowRotation) {
mIgnoreAutoRotateSettings =
- allowRotation || mLauncher.getResources().getBoolean(R.bool.allow_rotation);
+ allowRotation || mActivity.getResources().getBoolean(R.bool.allow_rotation);
// TODO(b/150214193) Tests currently expect launcher to be able to be rotated
// Modify tests for this new behavior
mForcedRotation = !allowRotation;
@@ -243,7 +213,6 @@
if (!mInitialized) {
mInitialized = true;
notifyChange();
- updateRotationAnimation();
}
}
@@ -285,7 +254,7 @@
}
if (activityFlags != mLastActivityFlags) {
mLastActivityFlags = activityFlags;
- UiThreadHelper.setOrientationAsync(mLauncher, activityFlags);
+ UiThreadHelper.setOrientationAsync(mActivity, activityFlags);
}
}
diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java
index 4e49c6e..e786f07 100644
--- a/src/com/android/launcher3/testing/TestInformationHandler.java
+++ b/src/com/android/launcher3/testing/TestInformationHandler.java
@@ -184,6 +184,10 @@
mDeviceProfile.allAppsCellHeightPx);
break;
}
+
+ case TestProtocol.REQUEST_MOCK_SENSOR_ROTATION:
+ TestProtocol.sDisableSensorRotation = true;
+ break;
}
return response;
}
diff --git a/src/com/android/launcher3/testing/TestProtocol.java b/src/com/android/launcher3/testing/TestProtocol.java
index 9f20df6..3181752 100644
--- a/src/com/android/launcher3/testing/TestProtocol.java
+++ b/src/com/android/launcher3/testing/TestProtocol.java
@@ -92,6 +92,9 @@
public static final String REQUEST_OVERVIEW_ACTIONS_ENABLED = "overview-actions-enabled";
+ public static boolean sDisableSensorRotation;
+ public static final String REQUEST_MOCK_SENSOR_ROTATION = "mock-sensor-rotation";
+
public static final String PERMANENT_DIAG_TAG = "TaplTarget";
public static final String NO_BACKGROUND_TO_OVERVIEW_TAG = "b/138251824";
diff --git a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
index 1db65b9..6715bc1 100644
--- a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
+++ b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
@@ -16,8 +16,11 @@
package com.android.launcher3.touch;
+import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
+import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
+import static com.android.launcher3.touch.SingleAxisSwipeDetector.HORIZONTAL;
+
import android.content.res.Resources;
-import android.graphics.Matrix;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
@@ -32,13 +35,8 @@
import com.android.launcher3.LauncherState.ScaleAndTranslation;
import com.android.launcher3.PagedView;
import com.android.launcher3.Utilities;
-import com.android.launcher3.states.RotationHelper;
import com.android.launcher3.util.OverScroller;
-import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
-import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
-import static com.android.launcher3.touch.SingleAxisSwipeDetector.HORIZONTAL;
-
public class LandscapePagedViewHandler implements PagedOrientationHandler {
@Override
@@ -67,12 +65,11 @@
}
@Override
- public CurveProperties getCurveProperties(PagedView pagedView, Rect mInsets) {
- int scroll = pagedView.getScrollY();
- final int halfPageSize = pagedView.getNormalChildHeight() / 2;
- final int screenCenter = mInsets.top + pagedView.getPaddingTop() + scroll + halfPageSize;
- final int halfScreenSize = pagedView.getMeasuredHeight() / 2;
- return new CurveProperties(scroll, halfPageSize, screenCenter, halfScreenSize);
+ public void getCurveProperties(PagedView view, Rect mInsets, CurveProperties out) {
+ out.scroll = view.getScrollY();
+ out.halfPageSize = view.getNormalChildHeight() / 2;
+ out.halfScreenSize = view.getMeasuredHeight() / 2;
+ out.screenCenter = mInsets.top + view.getPaddingTop() + out.scroll + out.halfPageSize;
}
@Override
diff --git a/src/com/android/launcher3/touch/PagedOrientationHandler.java b/src/com/android/launcher3/touch/PagedOrientationHandler.java
index b4802cd..24fa815 100644
--- a/src/com/android/launcher3/touch/PagedOrientationHandler.java
+++ b/src/com/android/launcher3/touch/PagedOrientationHandler.java
@@ -83,7 +83,7 @@
void delegateScrollTo(PagedView pagedView, int primaryScroll);
void delegateScrollBy(PagedView pagedView, int unboundedScroll, int x, int y);
void scrollerStartScroll(OverScroller scroller, int newPosition);
- CurveProperties getCurveProperties(PagedView pagedView, Rect insets);
+ void getCurveProperties(PagedView view, Rect mInsets, CurveProperties out);
boolean isGoingUp(float displacement);
/**
@@ -92,18 +92,12 @@
*/
void adjustFloatingIconStartVelocity(PointF velocity);
- class CurveProperties {
- public final int scroll;
- public final int halfPageSize;
- public final int screenCenter;
- public final int halfScreenSize;
- public CurveProperties(int scroll, int halfPageSize, int screenCenter, int halfScreenSize) {
- this.scroll = scroll;
- this.halfPageSize = halfPageSize;
- this.screenCenter = screenCenter;
- this.halfScreenSize = halfScreenSize;
- }
+ class CurveProperties {
+ public int scroll;
+ public int halfPageSize;
+ public int screenCenter;
+ public int halfScreenSize;
}
class ChildBounds {
diff --git a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
index 22eee49..6d903b3 100644
--- a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
+++ b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
@@ -16,8 +16,11 @@
package com.android.launcher3.touch;
+import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
+import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
+import static com.android.launcher3.touch.SingleAxisSwipeDetector.VERTICAL;
+
import android.content.res.Resources;
-import android.graphics.Matrix;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
@@ -32,13 +35,8 @@
import com.android.launcher3.LauncherState.ScaleAndTranslation;
import com.android.launcher3.PagedView;
import com.android.launcher3.Utilities;
-import com.android.launcher3.states.RotationHelper;
import com.android.launcher3.util.OverScroller;
-import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
-import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
-import static com.android.launcher3.touch.SingleAxisSwipeDetector.VERTICAL;
-
public class PortraitPagedViewHandler implements PagedOrientationHandler {
@Override
@@ -67,12 +65,11 @@
}
@Override
- public CurveProperties getCurveProperties(PagedView pagedView, Rect mInsets) {
- int scroll = pagedView.getScrollX();
- final int halfPageSize = pagedView.getNormalChildWidth() / 2;
- final int screenCenter = mInsets.left + pagedView.getPaddingLeft() + scroll + halfPageSize;
- final int halfScreenSize = pagedView.getMeasuredWidth() / 2;
- return new CurveProperties(scroll, halfPageSize, screenCenter, halfScreenSize);
+ public void getCurveProperties(PagedView view, Rect mInsets, CurveProperties out) {
+ out.scroll = view.getScrollX();
+ out.halfPageSize = view.getNormalChildWidth() / 2;
+ out.halfScreenSize = view.getMeasuredWidth() / 2;
+ out.screenCenter = mInsets.left + view.getPaddingLeft() + out.scroll + out.halfPageSize;
}
@Override
diff --git a/src/com/android/launcher3/views/ActivityContext.java b/src/com/android/launcher3/views/ActivityContext.java
index 0331a86..c9cdeff 100644
--- a/src/com/android/launcher3/views/ActivityContext.java
+++ b/src/com/android/launcher3/views/ActivityContext.java
@@ -22,7 +22,6 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.ItemInfo;
-import com.android.launcher3.graphics.RotationMode;
import com.android.launcher3.dot.DotInfo;
/**
@@ -57,19 +56,6 @@
DeviceProfile getDeviceProfile();
- /**
- * Device profile to be used by UI elements which are shown directly on top of the wallpaper
- * and whose presentation is tied to the wallpaper (and physical device) and not the activity
- * configuration.
- */
- default DeviceProfile getWallpaperDeviceProfile() {
- return getDeviceProfile();
- }
-
- default RotationMode getRotationMode() {
- return RotationMode.NORMAL;
- }
-
static ActivityContext lookupContext(Context context) {
if (context instanceof ActivityContext) {
return (ActivityContext) context;
diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java
index 3e2560f..ad8d69d 100644
--- a/src/com/android/launcher3/views/FloatingIconView.java
+++ b/src/com/android/launcher3/views/FloatingIconView.java
@@ -92,8 +92,6 @@
private ClipIconView mClipIconView;
private @Nullable Drawable mBadge;
- private float mRotation;
-
private View mOriginalIcon;
private RectF mPositionOut;
private Runnable mOnTargetChangeRunnable;
@@ -194,18 +192,17 @@
* @param positionOut Rect that will hold the size and position of v.
*/
private void matchPositionOf(Launcher launcher, View v, boolean isOpening, RectF positionOut) {
- float rotation = getLocationBoundsForView(launcher, v, isOpening, positionOut);
+ getLocationBoundsForView(launcher, v, isOpening, positionOut);
final InsettableFrameLayout.LayoutParams lp = new InsettableFrameLayout.LayoutParams(
Math.round(positionOut.width()),
Math.round(positionOut.height()));
- updatePosition(rotation, positionOut, lp);
+ updatePosition(positionOut, lp);
setLayoutParams(lp);
mClipIconView.setLayoutParams(new FrameLayout.LayoutParams(lp.width, lp.height));
}
- private void updatePosition(float rotation, RectF pos, InsettableFrameLayout.LayoutParams lp) {
- mRotation = rotation;
+ private void updatePosition(RectF pos, InsettableFrameLayout.LayoutParams lp) {
mPositionOut.set(pos);
lp.ignoreInsets = true;
// Position the floating view exactly on top of the original
@@ -228,7 +225,7 @@
* - For DeepShortcutView, we return the bounds of the icon view.
* - For BubbleTextView, we return the icon bounds.
*/
- private static float getLocationBoundsForView(Launcher launcher, View v, boolean isOpening,
+ private static void getLocationBoundsForView(Launcher launcher, View v, boolean isOpening,
RectF outRect) {
boolean ignoreTransform = !isOpening;
if (v instanceof DeepShortcutView) {
@@ -239,7 +236,7 @@
ignoreTransform = false;
}
if (v == null) {
- return 0;
+ return;
}
Rect iconBounds = new Rect();
@@ -253,15 +250,13 @@
float[] points = new float[] {iconBounds.left, iconBounds.top, iconBounds.right,
iconBounds.bottom};
- float[] rotation = new float[] {0};
Utilities.getDescendantCoordRelativeToAncestor(v, launcher.getDragLayer(), points,
- false, ignoreTransform, rotation);
+ false, ignoreTransform);
outRect.set(
Math.min(points[0], points[2]),
Math.min(points[1], points[3]),
Math.max(points[0], points[2]),
Math.max(points[1], points[3]));
- return rotation[0];
}
/**
@@ -443,14 +438,10 @@
@Override
protected void dispatchDraw(Canvas canvas) {
- int count = canvas.save();
- canvas.rotate(mRotation,
- mFinalDrawableBounds.exactCenterX(), mFinalDrawableBounds.exactCenterY());
super.dispatchDraw(canvas);
if (mBadge != null) {
mBadge.draw(canvas);
}
- canvas.restoreToCount(count);
}
public void fastFinish() {
@@ -487,11 +478,10 @@
@Override
public void onGlobalLayout() {
if (mOriginalIcon.isAttachedToWindow() && mPositionOut != null) {
- float rotation = getLocationBoundsForView(mLauncher, mOriginalIcon, mIsOpening,
+ getLocationBoundsForView(mLauncher, mOriginalIcon, mIsOpening,
sTmpRectF);
- if (rotation != mRotation || !sTmpRectF.equals(mPositionOut)) {
- updatePosition(rotation, sTmpRectF,
- (InsettableFrameLayout.LayoutParams) getLayoutParams());
+ if (!sTmpRectF.equals(mPositionOut)) {
+ updatePosition(sTmpRectF, (InsettableFrameLayout.LayoutParams) getLayoutParams());
if (mOnTargetChangeRunnable != null) {
mOnTargetChangeRunnable.run();
}
diff --git a/src/com/android/launcher3/views/ScrimView.java b/src/com/android/launcher3/views/ScrimView.java
index 6d204f6..39e1eac 100644
--- a/src/com/android/launcher3/views/ScrimView.java
+++ b/src/com/android/launcher3/views/ScrimView.java
@@ -22,8 +22,10 @@
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.NORMAL;
-import static com.android.launcher3.anim.Interpolators.ACCEL;
+import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
import static com.android.launcher3.anim.Interpolators.DEACCEL;
+import static com.android.launcher3.anim.Interpolators.LINEAR;
+import static com.android.launcher3.anim.Interpolators.clampToProgress;
import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
import android.animation.Animator;
@@ -33,8 +35,10 @@
import android.animation.PropertyValuesHolder;
import android.animation.RectEvaluator;
import android.content.Context;
+import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color;
+import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
@@ -98,6 +102,12 @@
private static final int SETTINGS = R.string.settings_button_text;
private static final int ALPHA_CHANNEL_COUNT = 1;
+ private static final long DRAG_HANDLE_BOUNCE_DURATION_MS = 300;
+ // How much to delay before repeating the bounce.
+ private static final long DRAG_HANDLE_BOUNCE_DELAY_MS = 200;
+ // Repeat this many times (i.e. total number of bounces is 1 + this).
+ private static final int DRAG_HANDLE_BOUNCE_REPEAT_COUNT = 2;
+
private final Rect mTempRect = new Rect();
private final int[] mTempPos = new int[2];
@@ -115,10 +125,13 @@
protected int mEndFlatColor;
protected int mEndFlatColorAlpha;
- protected final int mDragHandleSize;
+ protected final Point mDragHandleSize;
+ private final int mDragHandleTouchSize;
+ private final int mDragHandlePaddingInVerticalBarLayout;
protected float mDragHandleOffset;
private final Rect mDragHandleBounds;
private final RectF mHitRect = new RectF();
+ private ObjectAnimator mDragHandleAnim;
private final MultiValueAlpha mMultiValueAlpha;
@@ -136,9 +149,13 @@
mMaxScrimAlpha = 0.7f;
- mDragHandleSize = context.getResources()
- .getDimensionPixelSize(R.dimen.vertical_drag_handle_size);
- mDragHandleBounds = new Rect(0, 0, mDragHandleSize, mDragHandleSize);
+ Resources res = context.getResources();
+ mDragHandleSize = new Point(res.getDimensionPixelSize(R.dimen.vertical_drag_handle_width),
+ res.getDimensionPixelSize(R.dimen.vertical_drag_handle_height));
+ mDragHandleBounds = new Rect(0, 0, mDragHandleSize.x, mDragHandleSize.y);
+ mDragHandleTouchSize = res.getDimensionPixelSize(R.dimen.vertical_drag_handle_touch_size);
+ mDragHandlePaddingInVerticalBarLayout = context.getResources()
+ .getDimensionPixelSize(R.dimen.vertical_drag_handle_padding_in_vertical_bar_layout);
mAccessibilityHelper = createAccessibilityHelper();
ViewCompat.setAccessibilityDelegate(this, mAccessibilityHelper);
@@ -204,6 +221,7 @@
public void setProgress(float progress) {
if (mProgress != progress) {
mProgress = progress;
+ stopDragHandleEducationAnim();
updateColors();
updateDragHandleAlpha();
invalidate();
@@ -251,70 +269,103 @@
@Override
public boolean onTouchEvent(MotionEvent event) {
- boolean value = super.onTouchEvent(event);
- if (!value && mDragHandle != null && event.getAction() == ACTION_DOWN
- && mDragHandle.getAlpha() == 255
- && mHitRect.contains(event.getX(), event.getY())) {
-
- final Drawable drawable = mDragHandle;
- mDragHandle = null;
-
- Rect bounds = new Rect(mDragHandleBounds);
- bounds.offset(0, -(int) mDragHandleOffset);
- drawable.setBounds(bounds);
-
- Rect topBounds = new Rect(bounds);
- topBounds.offset(0, -bounds.height() / 2);
-
- Rect invalidateRegion = new Rect(bounds);
- invalidateRegion.top = topBounds.top;
-
- Keyframe frameTop = Keyframe.ofObject(0.6f, topBounds);
- frameTop.setInterpolator(DEACCEL);
- Keyframe frameBot = Keyframe.ofObject(1, bounds);
- frameBot.setInterpolator(ACCEL);
- PropertyValuesHolder holder = PropertyValuesHolder .ofKeyframe("bounds",
- Keyframe.ofObject(0, bounds), frameTop, frameBot);
- holder.setEvaluator(new RectEvaluator());
-
- ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(drawable, holder);
- anim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- getOverlay().remove(drawable);
- updateDragHandleVisibility(drawable);
+ boolean superHandledTouch = super.onTouchEvent(event);
+ if (event.getAction() == ACTION_DOWN) {
+ if (!superHandledTouch && mHitRect.contains(event.getX(), event.getY())) {
+ if (startDragHandleEducationAnim()) {
+ return true;
}
- });
- anim.addUpdateListener((v) -> invalidate(invalidateRegion));
- getOverlay().add(drawable);
- anim.start();
- return true;
+ }
+ stopDragHandleEducationAnim();
}
- return value;
+ return superHandledTouch;
+ }
+
+ /**
+ * Animates the drag handle to demonstrate how to get to all apps.
+ * @return Whether the animation was started (false if drag handle is invisible).
+ */
+ public boolean startDragHandleEducationAnim() {
+ stopDragHandleEducationAnim();
+
+ if (mDragHandle == null || mDragHandle.getAlpha() != 255) {
+ return false;
+ }
+
+ final Drawable drawable = mDragHandle;
+ mDragHandle = null;
+
+ Rect bounds = new Rect(mDragHandleBounds);
+ bounds.offset(0, -(int) mDragHandleOffset);
+ drawable.setBounds(bounds);
+
+ Rect topBounds = new Rect(bounds);
+ topBounds.offset(0, -bounds.height());
+
+ Rect invalidateRegion = new Rect(bounds);
+ invalidateRegion.top = topBounds.top;
+
+ final float progressToReachTop = 0.6f;
+ Keyframe frameTop = Keyframe.ofObject(progressToReachTop, topBounds);
+ frameTop.setInterpolator(DEACCEL);
+ Keyframe frameBot = Keyframe.ofObject(1, bounds);
+ frameBot.setInterpolator(ACCEL_DEACCEL);
+ PropertyValuesHolder holder = PropertyValuesHolder.ofKeyframe("bounds",
+ Keyframe.ofObject(0, bounds), frameTop, frameBot);
+ holder.setEvaluator(new RectEvaluator());
+
+ mDragHandleAnim = ObjectAnimator.ofPropertyValuesHolder(drawable, holder);
+ long totalBounceDuration = DRAG_HANDLE_BOUNCE_DURATION_MS + DRAG_HANDLE_BOUNCE_DELAY_MS;
+ // The bounce finishes by this progress, the rest of the duration just delays next bounce.
+ float delayStartProgress = 1f - (float) DRAG_HANDLE_BOUNCE_DELAY_MS / totalBounceDuration;
+ mDragHandleAnim.addUpdateListener((v) -> invalidate(invalidateRegion));
+ mDragHandleAnim.setDuration(totalBounceDuration);
+ mDragHandleAnim.setInterpolator(clampToProgress(LINEAR, 0, delayStartProgress));
+ mDragHandleAnim.setRepeatCount(DRAG_HANDLE_BOUNCE_REPEAT_COUNT);
+ getOverlay().add(drawable);
+
+ mDragHandleAnim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mDragHandleAnim = null;
+ getOverlay().remove(drawable);
+ updateDragHandleVisibility(drawable);
+ }
+ });
+ mDragHandleAnim.start();
+ return true;
+ }
+
+ private void stopDragHandleEducationAnim() {
+ if (mDragHandleAnim != null) {
+ mDragHandleAnim.end();
+ }
}
protected void updateDragHandleBounds() {
DeviceProfile grid = mLauncher.getDeviceProfile();
final int left;
final int width = getMeasuredWidth();
- final int top = getMeasuredHeight() - mDragHandleSize - grid.getInsets().bottom;
+ final int top = getMeasuredHeight() - mDragHandleSize.y - grid.getInsets().bottom;
final int topMargin;
if (grid.isVerticalBarLayout()) {
- topMargin = grid.workspacePadding.bottom;
+ topMargin = grid.workspacePadding.bottom + mDragHandlePaddingInVerticalBarLayout;
if (grid.isSeascape()) {
- left = width - grid.getInsets().right - mDragHandleSize;
+ left = width - grid.getInsets().right - mDragHandleSize.x
+ - mDragHandlePaddingInVerticalBarLayout;
} else {
- left = mDragHandleSize + grid.getInsets().left;
+ left = grid.getInsets().left + mDragHandlePaddingInVerticalBarLayout;
}
} else {
- left = (width - mDragHandleSize) / 2;
+ left = Math.round((width - mDragHandleSize.x) / 2f);
topMargin = grid.hotseatBarSizePx;
}
mDragHandleBounds.offsetTo(left, top - topMargin);
mHitRect.set(mDragHandleBounds);
- float inset = -mDragHandleSize / 2;
- mHitRect.inset(inset, inset);
+ // Inset outwards to increase touch size.
+ mHitRect.inset((mDragHandleSize.x - mDragHandleTouchSize) / 2f,
+ (mDragHandleSize.y - mDragHandleTouchSize) / 2f);
if (mDragHandle != null) {
mDragHandle.setBounds(mDragHandleBounds);
@@ -341,7 +392,7 @@
if (visible != wasVisible) {
if (visible) {
mDragHandle = recycle != null ? recycle :
- mLauncher.getDrawable(R.drawable.drag_handle_indicator);
+ mLauncher.getDrawable(R.drawable.drag_handle_indicator_shadow);
mDragHandle.setBounds(mDragHandleBounds);
updateDragHandleAlpha();
@@ -397,7 +448,7 @@
@Override
protected int getVirtualViewAt(float x, float y) {
- return mDragHandleBounds.contains((int) x, (int) y)
+ return mHitRect.contains((int) x, (int) y)
? DRAG_HANDLE_ID : INVALID_ID;
}
@@ -470,7 +521,10 @@
}
}
- public int getDragHandleSize() {
- return mDragHandleSize;
+ /**
+ * @return The top of this scrim view, or {@link Float#MAX_VALUE} if there's no distinct top.
+ */
+ public float getVisualTop() {
+ return Float.MAX_VALUE;
}
}
diff --git a/src/com/android/launcher3/views/Transposable.java b/src/com/android/launcher3/views/Transposable.java
deleted file mode 100644
index 929c1aa..0000000
--- a/src/com/android/launcher3/views/Transposable.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/**
- * Copyright (C) 2019 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.views;
-
-import com.android.launcher3.graphics.RotationMode;
-
-/**
- * Indicates that a view can be transposed.
- */
-public interface Transposable {
-
- RotationMode getRotationMode();
-}
diff --git a/src/com/android/launcher3/widget/WidgetsFullSheet.java b/src/com/android/launcher3/widget/WidgetsFullSheet.java
index aaebedd..b3e9734 100644
--- a/src/com/android/launcher3/widget/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/WidgetsFullSheet.java
@@ -98,6 +98,11 @@
onWidgetsBound();
}
+ @VisibleForTesting
+ public WidgetsRecyclerView getRecyclerView() {
+ return mRecyclerView;
+ }
+
@Override
protected Pair<View, String> getAccessibilityTarget() {
return Pair.create(mRecyclerView, getContext().getString(
diff --git a/src/com/android/launcher3/widget/WidgetsRecyclerView.java b/src/com/android/launcher3/widget/WidgetsRecyclerView.java
index c15557b..7ec6214 100644
--- a/src/com/android/launcher3/widget/WidgetsRecyclerView.java
+++ b/src/com/android/launcher3/widget/WidgetsRecyclerView.java
@@ -19,11 +19,14 @@
import android.content.Context;
import android.graphics.Point;
import android.util.AttributeSet;
+import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import com.android.launcher3.BaseRecyclerView;
import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.testing.TestProtocol;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
@@ -155,18 +158,66 @@
mScrollbar.isHitInParent(e.getX(), e.getY(), mFastScrollerOffset);
}
if (mTouchDownOnScroller) {
- return mScrollbar.handleTouchEvent(e, mFastScrollerOffset);
+ final boolean result = mScrollbar.handleTouchEvent(e, mFastScrollerOffset);
+ if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
+ Log.d(TestProtocol.NO_SCROLL_END_WIDGETS, "onInterceptTouchEvent 1 " + result);
+ }
+ return result;
+ }
+ if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
+ Log.d(TestProtocol.NO_SCROLL_END_WIDGETS, "onInterceptTouchEvent 2 false");
}
return false;
}
@Override
public void onTouchEvent(RecyclerView rv, MotionEvent e) {
+ if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
+ Log.d(TestProtocol.NO_SCROLL_END_WIDGETS, "WidgetsRecyclerView.onTouchEvent");
+ }
if (mTouchDownOnScroller) {
mScrollbar.handleTouchEvent(e, mFastScrollerOffset);
}
}
@Override
- public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) { }
+ public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
+ if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
+ Log.d(TestProtocol.NO_SCROLL_END_WIDGETS, "onRequestDisallowInterceptTouchEvent "
+ + disallowIntercept);
+ }
+ }
+
+ @Override
+ public boolean dispatchTouchEvent(MotionEvent ev) {
+ final boolean result = super.dispatchTouchEvent(ev);
+ if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
+ Log.d(TestProtocol.NO_SCROLL_END_WIDGETS, "WidgetsRecyclerView: state: "
+ + getScrollState()
+ + " can scroll: " + getLayoutManager().canScrollVertically()
+ + " result: " + result
+ + " layout suppressed: " + isLayoutSuppressed()
+ + " event: " + ev);
+ }
+ return result;
+ }
+
+ @Override
+ public void stopNestedScroll() {
+ if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
+ Log.d(TestProtocol.NO_SCROLL_END_WIDGETS, "stopNestedScroll");
+ }
+ super.stopNestedScroll();
+ }
+
+ @Override
+ public void setLayoutFrozen(boolean frozen) {
+ if (frozen != isLayoutSuppressed()) {
+ if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
+ Log.d(TestProtocol.NO_SCROLL_END_WIDGETS, "setLayoutFrozen " + frozen
+ + " @ " + android.util.Log.getStackTraceString(new Throwable()));
+ }
+ }
+ super.setLayoutFrozen(frozen);
+ }
}
\ No newline at end of file
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 7cd656e..873f1cb 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -162,6 +162,7 @@
mLauncher.enableDebugTracing();
// Avoid double-reporting of Launcher crashes.
mLauncher.setOnLauncherCrashed(() -> mLauncherPid = 0);
+ mLauncher.disableSensorRotation();
}
protected final LauncherActivityRule mActivityMonitor = new LauncherActivityRule();
@@ -277,6 +278,7 @@
clearPackageData(mDevice.getLauncherPackageName());
mLauncher.enableDebugTracing();
mLauncherPid = mLauncher.getPid();
+ mLauncher.disableSensorRotation();
}
}
diff --git a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
index a3c70ec..001a88f 100644
--- a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
@@ -275,8 +275,10 @@
}
private void verifyPendingWidgetPresent() {
+ final Widget widget = mLauncher.getWorkspace().tryGetPendingWidget(DEFAULT_UI_TIMEOUT);
+ if (widget == null) mLauncher.dumpViewHierarchy(); // b/152645831
assertTrue("Pending widget is not present",
- mLauncher.getWorkspace().tryGetPendingWidget(DEFAULT_UI_TIMEOUT) != null);
+ widget != null);
}
/**
diff --git a/tests/tapl/com/android/launcher3/tapl/AllApps.java b/tests/tapl/com/android/launcher3/tapl/AllApps.java
index 4a2d699..808be66 100644
--- a/tests/tapl/com/android/launcher3/tapl/AllApps.java
+++ b/tests/tapl/com/android/launcher3/tapl/AllApps.java
@@ -43,7 +43,7 @@
AllApps(LauncherInstrumentation launcher) {
super(launcher);
final UiObject2 allAppsContainer = verifyActiveContainer();
- mHeight = allAppsContainer.getVisibleBounds().height();
+ mHeight = mLauncher.getVisibleBounds(allAppsContainer).height();
final UiObject2 appListRecycler = mLauncher.waitForObjectInContainer(allAppsContainer,
"apps_list_view");
// Wait for the recycler to populate.
@@ -66,7 +66,7 @@
LauncherInstrumentation.log("hasClickableIcon: icon not visible");
return false;
}
- final Rect iconBounds = icon.getVisibleBounds();
+ final Rect iconBounds = mLauncher.getVisibleBounds(icon);
LauncherInstrumentation.log("hasClickableIcon: icon bounds: " + iconBounds);
if (iconBounds.height() < mIconHeight / 2) {
LauncherInstrumentation.log("hasClickableIcon: icon has insufficient height");
@@ -86,7 +86,7 @@
private boolean iconCenterInSearchBox(UiObject2 allAppsContainer, UiObject2 icon) {
final Point iconCenter = icon.getVisibleCenter();
- return getSearchBox(allAppsContainer).getVisibleBounds().contains(
+ return mLauncher.getVisibleBounds(getSearchBox(allAppsContainer)).contains(
iconCenter.x, iconCenter.y);
}
@@ -125,11 +125,11 @@
mLauncher.getObjectsInContainer(allAppsContainer, "icon")
.stream()
.filter(icon ->
- icon.getVisibleBounds().bottom
+ mLauncher.getVisibleBounds(icon).bottom
<= displayBottom)
.collect(Collectors.toList()),
- searchBox.getVisibleBounds().bottom
- - allAppsContainer.getVisibleBounds().top);
+ mLauncher.getVisibleBounds(searchBox).bottom
+ - mLauncher.getVisibleBounds(allAppsContainer).top);
final int newScroll = getAllAppsScroll();
mLauncher.assertTrue(
"Scrolled in a wrong direction in AllApps: from " + scroll + " to "
@@ -166,7 +166,8 @@
final UiObject2 searchBox = getSearchBox(allAppsContainer);
int attempts = 0;
- final Rect margins = new Rect(0, searchBox.getVisibleBounds().bottom + 1, 0, 5);
+ final Rect margins =
+ new Rect(0, mLauncher.getVisibleBounds(searchBox).bottom + 1, 0, 5);
for (int scroll = getAllAppsScroll();
scroll != 0;
diff --git a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
index a769acf..69afcc4 100644
--- a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
+++ b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
@@ -117,8 +117,8 @@
// part) one in the center, and parts of its right and left siblings. Find the
// main task view by its width.
final UiObject2 widestTask = Collections.max(taskViews,
- (t1, t2) -> Integer.compare(t1.getVisibleBounds().width(),
- t2.getVisibleBounds().width()));
+ (t1, t2) -> Integer.compare(mLauncher.getVisibleBounds(t1).width(),
+ mLauncher.getVisibleBounds(t2).width()));
return new OverviewTask(mLauncher, widestTask, this);
}
diff --git a/tests/tapl/com/android/launcher3/tapl/Launchable.java b/tests/tapl/com/android/launcher3/tapl/Launchable.java
index 2177032..2922acf 100644
--- a/tests/tapl/com/android/launcher3/tapl/Launchable.java
+++ b/tests/tapl/com/android/launcher3/tapl/Launchable.java
@@ -57,7 +57,7 @@
private Background launch(BySelector selector) {
LauncherInstrumentation.log("Launchable.launch before click " +
- mObject.getVisibleCenter() + " in " + mObject.getVisibleBounds());
+ mObject.getVisibleCenter() + " in " + mLauncher.getVisibleBounds(mObject));
mLauncher.executeAndWaitForEvent(
() -> mLauncher.clickLauncherObject(mObject),
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 3ddc0d2..975fe9c 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -977,7 +977,7 @@
int getBottomGestureMarginInContainer(UiObject2 container) {
final int bottomGestureStartOnScreen = getRealDisplaySize().y - getBottomGestureSize();
- return container.getVisibleBounds().bottom - bottomGestureStartOnScreen;
+ return getVisibleBounds(container).bottom - bottomGestureStartOnScreen;
}
void clickLauncherObject(UiObject2 object) {
@@ -995,10 +995,10 @@
Collection<UiObject2> items,
int topPaddingInContainer) {
final UiObject2 lowestItem = Collections.max(items, (i1, i2) ->
- Integer.compare(i1.getVisibleBounds().top, i2.getVisibleBounds().top));
+ Integer.compare(getVisibleBounds(i1).top, getVisibleBounds(i2).top));
- final int itemRowCurrentTopOnScreen = lowestItem.getVisibleBounds().top;
- final Rect containerRect = container.getVisibleBounds();
+ final int itemRowCurrentTopOnScreen = getVisibleBounds(lowestItem).top;
+ final Rect containerRect = getVisibleBounds(container);
final int itemRowNewTopOnScreen = containerRect.top + topPaddingInContainer;
final int distance = itemRowCurrentTopOnScreen - itemRowNewTopOnScreen + getTouchSlop();
@@ -1017,7 +1017,7 @@
void scroll(
UiObject2 container, Direction direction, Rect margins, int steps, boolean slowDown) {
- final Rect rect = container.getVisibleBounds();
+ final Rect rect = getVisibleBounds(container);
if (margins != null) {
rect.left += margins.left;
rect.top += margins.top;
@@ -1263,6 +1263,10 @@
TestProtocol.TEST_INFO_RESPONSE_FIELD);
}
+ public void disableSensorRotation() {
+ getTestInfo(TestProtocol.REQUEST_MOCK_SENSOR_ROTATION);
+ }
+
public void disableDebugTracing() {
getTestInfo(TestProtocol.REQUEST_DISABLE_DEBUG_TRACING);
}
@@ -1330,4 +1334,13 @@
void expectEvent(String sequence, Pattern expected) {
if (sCheckingEvents) sEventChecker.expectPattern(sequence, expected);
}
+
+ Rect getVisibleBounds(UiObject2 object) {
+ try {
+ return object.getVisibleBounds();
+ } catch (Throwable t) {
+ fail(t.toString());
+ return null;
+ }
+ }
}
diff --git a/tests/tapl/com/android/launcher3/tapl/OptionsPopupMenuItem.java b/tests/tapl/com/android/launcher3/tapl/OptionsPopupMenuItem.java
index b8e6c0e..63a97f4 100644
--- a/tests/tapl/com/android/launcher3/tapl/OptionsPopupMenuItem.java
+++ b/tests/tapl/com/android/launcher3/tapl/OptionsPopupMenuItem.java
@@ -41,7 +41,7 @@
public void launch(@NonNull String expectedPackageName) {
try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
LauncherInstrumentation.log("OptionsPopupMenuItem before click "
- + mObject.getVisibleCenter() + " in " + mObject.getVisibleBounds());
+ + mObject.getVisibleCenter() + " in " + mLauncher.getVisibleBounds(mObject));
mLauncher.clickLauncherObject(mObject);
if (!Build.MODEL.contains("Cuttlefish") ||
Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q &&
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
index 5c51782..fae5f19 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
@@ -56,7 +56,7 @@
"want to dismiss a task")) {
verifyActiveContainer();
// Dismiss the task via flinging it up.
- final Rect taskBounds = mTask.getVisibleBounds();
+ final Rect taskBounds = mLauncher.getVisibleBounds(mTask);
final int centerX = taskBounds.centerX();
final int centerY = taskBounds.centerY();
mLauncher.linearGesture(centerX, centerY, centerX, 0, 10, false,
diff --git a/tests/tapl/com/android/launcher3/tapl/Widgets.java b/tests/tapl/com/android/launcher3/tapl/Widgets.java
index a14d2f0..5be57c6 100644
--- a/tests/tapl/com/android/launcher3/tapl/Widgets.java
+++ b/tests/tapl/com/android/launcher3/tapl/Widgets.java
@@ -73,7 +73,7 @@
mLauncher.scroll(
widgetsContainer,
Direction.UP,
- new Rect(0, 0, widgetsContainer.getVisibleBounds().width(), 0),
+ new Rect(0, 0, mLauncher.getVisibleBounds(widgetsContainer).width(), 0),
FLING_STEPS, false);
try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("flung back")) {
verifyActiveContainer();
@@ -111,19 +111,19 @@
int maxWidth = 0;
for (UiObject2 sibling : widget.getParent().getChildren()) {
- maxWidth = Math.max(sibling.getVisibleBounds().width(), maxWidth);
+ maxWidth = Math.max(mLauncher.getVisibleBounds(sibling).width(), maxWidth);
}
- int visibleDelta = maxWidth - widget.getVisibleBounds().width();
+ int visibleDelta = maxWidth - mLauncher.getVisibleBounds(widget).width();
if (visibleDelta > 0) {
- Rect parentBounds = cell.getVisibleBounds();
+ Rect parentBounds = mLauncher.getVisibleBounds(cell);
mLauncher.linearGesture(parentBounds.centerX() + visibleDelta
+ mLauncher.getTouchSlop(),
parentBounds.centerY(), parentBounds.centerX(),
parentBounds.centerY(), 10, true, GestureScope.INSIDE);
}
- if (widget.getVisibleBounds().bottom
+ if (mLauncher.getVisibleBounds(widget).bottom
<= displaySize.y - mLauncher.getBottomGestureSize()) {
return new Widget(mLauncher, widget);
}
diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java
index 86aafc2..b3b5e32 100644
--- a/tests/tapl/com/android/launcher3/tapl/Workspace.java
+++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java
@@ -177,7 +177,7 @@
mLauncher,
getHotseatAppIcon("Chrome"),
new Point(mLauncher.getDevice().getDisplayWidth(),
- workspace.getVisibleBounds().centerY()),
+ mLauncher.getVisibleBounds(workspace).centerY()),
"deep_shortcuts_container",
false,
() -> mLauncher.expectEvent(