Merging ub-launcher3-qt-dev, build 5595491
Test: Manual Bug:122345781 P1 Inflation happens and a binder call during swipe up gesture, that may cause jank Bug:123900446 P1 App to home animation should zoom into the app icon Bug:124510042 P1 [Gesture Nav] Home animation polish Bug:126744445 P1 Add chips support for Overview UI library Bug:127783075 P1 When swiping up to recents, sometimes velocity is really wrong Bug:129036789 P2 [a11y] Talkback doesn't indicate App paused in Home/Apps list. Bug:131839392 P2 Ensure Go Launcher follows theming standards Bug:132283018 P1 Shelf Jump Bug:132356358 P1 Fix invocation animation for fling Bug:132588097 P1 Launcher folder shadow and image flickers on going home Bug:132716177 P4 Swiping right at home shows alphabet index Bug:132900132 P1 Apparently, tests start running while provisioning is still in progress Bug:132917885 P1 Reduce swipe-up gesture region height in landscape Bug:133009122 P2 Rare flake: dragged launchable to workspace, but the current state is not WORKSPACE; Can't find a launcher object; selector: BySelector [RES='\Qcom.google.android.apps.nexuslauncher:id/apps_view\E'] Bug:133010447 P2 Blueline: flake: test manages to click search box instead of starting an app Bug:133010773 P2 qt-dev / crosshatch: flake: java.lang.AssertionError: http://go/tapl : want to switch from background to overview; Swipe failed to receive an event for the swipe end: 720, 2959, 720, 2050 Bug:133011252 P2 flake: Launching an app didn't open a new window: Calendar Bug:133265591 P1 Blocked touches in thin region over home Change-Id: Iac4013556a2a49418d1634762698ea59bbf95a75
This commit is contained in:
@@ -29,5 +29,6 @@
|
||||
android:text="@string/recents_clear_all"
|
||||
android:textAllCaps="false"
|
||||
android:textColor="@color/clear_all_button_text"
|
||||
android:textSize="14sp"/>
|
||||
android:textSize="14sp"
|
||||
style="@style/TextTitle"/>
|
||||
</FrameLayout>
|
||||
|
||||
@@ -36,5 +36,6 @@
|
||||
android:text="@string/recents_empty_message"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="25sp"
|
||||
style="@style/TextTitle"
|
||||
android:visibility="gone"/>
|
||||
</com.android.quickstep.views.IconRecentsView>
|
||||
@@ -41,5 +41,6 @@
|
||||
android:layout_gravity="center_vertical"
|
||||
android:singleLine="true"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="24sp"/>
|
||||
android:textSize="24sp"
|
||||
style="@style/TextTitle"/>
|
||||
</com.android.quickstep.views.TaskItemView>
|
||||
|
||||
+9
-2
@@ -76,8 +76,13 @@ public abstract class RecentsUiFactory {
|
||||
|
||||
@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.set(insets);
|
||||
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;
|
||||
@@ -99,7 +104,9 @@ public abstract class RecentsUiFactory {
|
||||
@Override
|
||||
public void mapInsets(Context context, Rect insets, Rect out) {
|
||||
if (SysUINavigationMode.getMode(context) == NO_BUTTON) {
|
||||
out.set(insets);
|
||||
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;
|
||||
|
||||
+8
@@ -17,6 +17,7 @@ package com.android.launcher3.uioverrides.states;
|
||||
|
||||
import static com.android.launcher3.LauncherAnimUtils.OVERVIEW_TRANSITION_MS;
|
||||
|
||||
import com.android.launcher3.AbstractFloatingView;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.allapps.AllAppsTransitionController;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||
@@ -41,6 +42,13 @@ public class BackgroundAppState extends OverviewState {
|
||||
super(id, logContainer, OVERVIEW_TRANSITION_MS, STATE_FLAGS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStateEnabled(Launcher launcher) {
|
||||
RecentsView rv = launcher.getOverviewPanel();
|
||||
rv.setOverviewStateEnabled(true);
|
||||
AbstractFloatingView.closeAllOpenViews(launcher, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getVerticalProgress(Launcher launcher) {
|
||||
if (launcher.getDeviceProfile().isVerticalBarLayout()) {
|
||||
|
||||
+2
-1
@@ -118,7 +118,8 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe
|
||||
final RectF iconLocation = new RectF();
|
||||
boolean canUseWorkspaceView = workspaceView != null && workspaceView.isAttachedToWindow();
|
||||
FloatingIconView floatingIconView = canUseWorkspaceView
|
||||
? recentsView.getFloatingIconView(activity, workspaceView, iconLocation)
|
||||
? FloatingIconView.getFloatingIconView(activity, workspaceView,
|
||||
true /* hideOriginal */, iconLocation, false /* isOpening */)
|
||||
: null;
|
||||
|
||||
return new HomeAnimationFactory() {
|
||||
|
||||
+13
-5
@@ -331,21 +331,29 @@ public class TouchInteractionService extends Service implements
|
||||
defaultDisplay.getRealSize(realSize);
|
||||
mSwipeTouchRegion.set(0, 0, realSize.x, realSize.y);
|
||||
if (mMode == Mode.NO_BUTTON) {
|
||||
mSwipeTouchRegion.top = mSwipeTouchRegion.bottom - getNavbarSize(
|
||||
ResourceUtils.NAVBAR_VERTICAL_SIZE);
|
||||
switch (defaultDisplay.getRotation()) {
|
||||
case Surface.ROTATION_90:
|
||||
case Surface.ROTATION_270:
|
||||
mSwipeTouchRegion.top = mSwipeTouchRegion.bottom - getNavbarSize(
|
||||
ResourceUtils.NAVBAR_LANDSCAPE_BOTTOM_SIZE);
|
||||
break;
|
||||
default:
|
||||
mSwipeTouchRegion.top = mSwipeTouchRegion.bottom - getNavbarSize(
|
||||
ResourceUtils.NAVBAR_PORTRAIT_BOTTOM_SIZE);
|
||||
}
|
||||
} else {
|
||||
switch (defaultDisplay.getRotation()) {
|
||||
case Surface.ROTATION_90:
|
||||
mSwipeTouchRegion.left = mSwipeTouchRegion.right
|
||||
- getNavbarSize(ResourceUtils.NAVBAR_HORIZONTAL_SIZE);
|
||||
- getNavbarSize(ResourceUtils.NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE);
|
||||
break;
|
||||
case Surface.ROTATION_270:
|
||||
mSwipeTouchRegion.right = mSwipeTouchRegion.left
|
||||
+ getNavbarSize(ResourceUtils.NAVBAR_HORIZONTAL_SIZE);
|
||||
+ getNavbarSize(ResourceUtils.NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE);
|
||||
break;
|
||||
default:
|
||||
mSwipeTouchRegion.top = mSwipeTouchRegion.bottom
|
||||
- getNavbarSize(ResourceUtils.NAVBAR_VERTICAL_SIZE);
|
||||
- getNavbarSize(ResourceUtils.NAVBAR_PORTRAIT_BOTTOM_SIZE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+7
-2
@@ -902,7 +902,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
|
||||
float minFlingVelocity = mContext.getResources()
|
||||
.getDimension(R.dimen.quickstep_fling_min_velocity);
|
||||
if (Math.abs(endVelocity) > minFlingVelocity && mTransitionDragLength > 0) {
|
||||
if (endTarget == RECENTS) {
|
||||
if (endTarget == RECENTS && mMode != Mode.NO_BUTTON) {
|
||||
Interpolators.OvershootParams overshoot = new Interpolators.OvershootParams(
|
||||
startShift, endShift, endShift, velocityPxPerMs.y,
|
||||
mTransitionDragLength);
|
||||
@@ -918,6 +918,10 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
|
||||
// derivative of the scroll interpolator at zero, ie. 2.
|
||||
long baseDuration = Math.round(Math.abs(distanceToTravel / velocityPxPerMs.y));
|
||||
duration = Math.min(MAX_SWIPE_DURATION, 2 * baseDuration);
|
||||
|
||||
if (endTarget == RECENTS) {
|
||||
interpolator = OVERSHOOT_1_2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -932,7 +936,8 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
|
||||
} else if (endTarget == RECENTS) {
|
||||
mLiveTileOverlay.startIconAnimation();
|
||||
if (mRecentsView != null) {
|
||||
duration = Math.max(duration, mRecentsView.getScroller().getDuration());
|
||||
duration = Utilities.boundToRange(mRecentsView.getScroller().getDuration(),
|
||||
duration, MAX_SWIPE_DURATION);
|
||||
}
|
||||
if (mMode == Mode.NO_BUTTON) {
|
||||
setShelfState(ShelfAnimState.OVERVIEW, interpolator, duration);
|
||||
|
||||
+47
-26
@@ -23,6 +23,7 @@ import static android.view.MotionEvent.ACTION_POINTER_DOWN;
|
||||
import static android.view.MotionEvent.ACTION_POINTER_UP;
|
||||
import static android.view.MotionEvent.ACTION_UP;
|
||||
|
||||
import static com.android.launcher3.Utilities.squaredHypot;
|
||||
import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction.UPLEFT;
|
||||
import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction.UPRIGHT;
|
||||
import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch.FLING;
|
||||
@@ -40,6 +41,7 @@ import android.os.SystemClock;
|
||||
import android.util.Log;
|
||||
import android.view.HapticFeedbackConstants;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.ViewConfiguration;
|
||||
|
||||
import com.android.launcher3.BaseDraggingActivity;
|
||||
import com.android.launcher3.R;
|
||||
@@ -81,7 +83,7 @@ public class AssistantTouchConsumer extends DelegateInputConsumer
|
||||
private final float mDistThreshold;
|
||||
private final long mTimeThreshold;
|
||||
private final int mAngleThreshold;
|
||||
private final float mSlop;
|
||||
private final float mSquaredSlop;
|
||||
private final ISystemUiProxy mSysUiProxy;
|
||||
private final Context mContext;
|
||||
private final SwipeDetector mSwipeDetector;
|
||||
@@ -96,7 +98,10 @@ public class AssistantTouchConsumer extends DelegateInputConsumer
|
||||
mDistThreshold = res.getDimension(R.dimen.gestures_assistant_drag_threshold);
|
||||
mTimeThreshold = res.getInteger(R.integer.assistant_gesture_min_time_threshold);
|
||||
mAngleThreshold = res.getInteger(R.integer.assistant_gesture_corner_deg_threshold);
|
||||
mSlop = QuickStepContract.getQuickStepDragSlopPx();
|
||||
|
||||
float slop = ViewConfiguration.get(context).getScaledTouchSlop();
|
||||
|
||||
mSquaredSlop = slop * slop;
|
||||
mActivityControlHelper = activityControlHelper;
|
||||
mSwipeDetector = new SwipeDetector(mContext, this, SwipeDetector.VERTICAL);
|
||||
mSwipeDetector.setDetectableScrollConditions(SwipeDetector.DIRECTION_POSITIVE, false);
|
||||
@@ -155,7 +160,8 @@ public class AssistantTouchConsumer extends DelegateInputConsumer
|
||||
|
||||
if (!mPassedSlop) {
|
||||
// Normal gesture, ensure we pass the slop before we start tracking the gesture
|
||||
if (Math.hypot(mLastPos.x - mDownPos.x, mLastPos.y - mDownPos.y) > mSlop) {
|
||||
if (squaredHypot(mLastPos.x - mDownPos.x, mLastPos.y - mDownPos.y)
|
||||
> mSquaredSlop) {
|
||||
|
||||
mPassedSlop = true;
|
||||
mStartDragPos.set(mLastPos.x, mLastPos.y);
|
||||
@@ -218,31 +224,35 @@ public class AssistantTouchConsumer extends DelegateInputConsumer
|
||||
private void updateAssistantProgress() {
|
||||
if (!mLaunchedAssistant) {
|
||||
mLastProgress = Math.min(mDistance * 1f / mDistThreshold, 1) * mTimeFraction;
|
||||
updateAssistant(SWIPE);
|
||||
try {
|
||||
if (mDistance >= mDistThreshold && mTimeFraction >= 1) {
|
||||
mSysUiProxy.onAssistantGestureCompletion(0);
|
||||
startAssistantInternal(SWIPE);
|
||||
|
||||
Bundle args = new Bundle();
|
||||
args.putInt(INVOCATION_TYPE_KEY, INVOCATION_TYPE_GESTURE);
|
||||
mSysUiProxy.startAssistant(args);
|
||||
mLaunchedAssistant = true;
|
||||
} else {
|
||||
mSysUiProxy.onAssistantProgress(mLastProgress);
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Failed to send SysUI start/send assistant progress: " + mLastProgress,
|
||||
e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateAssistant(int gestureType) {
|
||||
try {
|
||||
mSysUiProxy.onAssistantProgress(mLastProgress);
|
||||
if (gestureType == FLING || (mDistance >= mDistThreshold && mTimeFraction >= 1)) {
|
||||
UserEventDispatcher.newInstance(mContext)
|
||||
.logActionOnContainer(gestureType, mDirection, NAVBAR);
|
||||
Bundle args = new Bundle();
|
||||
args.putInt(INVOCATION_TYPE_KEY, INVOCATION_TYPE_GESTURE);
|
||||
private void startAssistantInternal(int gestureType) {
|
||||
UserEventDispatcher.newInstance(mContext)
|
||||
.logActionOnContainer(gestureType, mDirection, NAVBAR);
|
||||
|
||||
BaseDraggingActivity launcherActivity = mActivityControlHelper.getCreatedActivity();
|
||||
if (launcherActivity != null) {
|
||||
launcherActivity.getRootView().performHapticFeedback(
|
||||
13, // HapticFeedbackConstants.GESTURE_END
|
||||
HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
|
||||
}
|
||||
|
||||
mSysUiProxy.startAssistant(args);
|
||||
mLaunchedAssistant = true;
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Failed to send SysUI start/send assistant progress: " + mLastProgress, e);
|
||||
BaseDraggingActivity launcherActivity = mActivityControlHelper
|
||||
.getCreatedActivity();
|
||||
if (launcherActivity != null) {
|
||||
launcherActivity.getRootView().performHapticFeedback(
|
||||
13, // HapticFeedbackConstants.GESTURE_END
|
||||
HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,9 +276,20 @@ public class AssistantTouchConsumer extends DelegateInputConsumer
|
||||
|
||||
@Override
|
||||
public void onDragEnd(float velocity, boolean fling) {
|
||||
if (fling && !mLaunchedAssistant) {
|
||||
if (fling && !mLaunchedAssistant && mState != STATE_DELEGATE_ACTIVE) {
|
||||
mLastProgress = 1;
|
||||
updateAssistant(FLING);
|
||||
try {
|
||||
mSysUiProxy.onAssistantGestureCompletion(velocity);
|
||||
startAssistantInternal(FLING);
|
||||
|
||||
Bundle args = new Bundle();
|
||||
args.putInt(INVOCATION_TYPE_KEY, INVOCATION_TYPE_GESTURE);
|
||||
mSysUiProxy.startAssistant(args);
|
||||
mLaunchedAssistant = true;
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Failed to send SysUI start/send assistant progress: " + mLastProgress,
|
||||
e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
-6
@@ -15,11 +15,13 @@
|
||||
*/
|
||||
package com.android.quickstep.inputconsumers;
|
||||
|
||||
import static com.android.launcher3.Utilities.squaredHypot;
|
||||
import static com.android.launcher3.Utilities.squaredTouchSlop;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.PointF;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.ViewConfiguration;
|
||||
|
||||
/**
|
||||
* A dummy input consumer used when the device is still locked, e.g. from secure camera.
|
||||
@@ -32,8 +34,7 @@ public class DeviceLockedInputConsumer implements InputConsumer {
|
||||
|
||||
public DeviceLockedInputConsumer(Context context) {
|
||||
mContext = context;
|
||||
float touchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
|
||||
mTouchSlopSquared = touchSlop * touchSlop;
|
||||
mTouchSlopSquared = squaredTouchSlop(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -48,9 +49,7 @@ public class DeviceLockedInputConsumer implements InputConsumer {
|
||||
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
|
||||
mTouchDown.set(x, y);
|
||||
} else if (ev.getAction() == MotionEvent.ACTION_MOVE) {
|
||||
float xSquared = (x - mTouchDown.x) * (x - mTouchDown.x);
|
||||
float ySquared = (y - mTouchDown.y) * (y - mTouchDown.y);
|
||||
if (xSquared + ySquared > mTouchSlopSquared) {
|
||||
if (squaredHypot(x - mTouchDown.x, y - mTouchDown.y) > mTouchSlopSquared) {
|
||||
// For now, just start the home intent so user is prompted to unlock the device.
|
||||
mContext.startActivity(new Intent(Intent.ACTION_MAIN)
|
||||
.addCategory(Intent.CATEGORY_HOME)
|
||||
|
||||
+5
-3
@@ -23,6 +23,7 @@ import static android.view.MotionEvent.ACTION_POINTER_UP;
|
||||
import static android.view.MotionEvent.ACTION_UP;
|
||||
import static android.view.MotionEvent.INVALID_POINTER_ID;
|
||||
import static com.android.launcher3.Utilities.EDGE_NAV_BAR;
|
||||
import static com.android.launcher3.Utilities.squaredHypot;
|
||||
import static com.android.launcher3.uioverrides.RecentsUiFactory.ROTATION_LANDSCAPE;
|
||||
import static com.android.launcher3.uioverrides.RecentsUiFactory.ROTATION_SEASCAPE;
|
||||
import static com.android.launcher3.util.RaceConditionTracker.ENTER;
|
||||
@@ -109,7 +110,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
|
||||
private int mActivePointerId = INVALID_POINTER_ID;
|
||||
|
||||
private final float mDragSlop;
|
||||
private final float mTouchSlop;
|
||||
private final float mSquaredTouchSlop;
|
||||
|
||||
// Slop used to check when we start moving window.
|
||||
private boolean mPassedDragSlop;
|
||||
@@ -157,7 +158,8 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
|
||||
|
||||
mDisplayRotation = getSystemService(WindowManager.class).getDefaultDisplay().getRotation();
|
||||
mDragSlop = QuickStepContract.getQuickStepDragSlopPx();
|
||||
mTouchSlop = QuickStepContract.getQuickStepTouchSlopPx();
|
||||
float slop = QuickStepContract.getQuickStepTouchSlopPx();
|
||||
mSquaredTouchSlop = slop * slop;
|
||||
|
||||
mPassedTouchSlop = mPassedDragSlop = continuingPreviousGesture;
|
||||
}
|
||||
@@ -256,7 +258,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
|
||||
}
|
||||
|
||||
if (!mPassedTouchSlop) {
|
||||
if (Math.hypot(displacementX, mLastPos.y - mDownPos.y) >= mTouchSlop) {
|
||||
if (squaredHypot(displacementX, mLastPos.y - mDownPos.y) >= mSquaredTouchSlop) {
|
||||
mPassedTouchSlop = true;
|
||||
|
||||
if (mIsDeferredDownTarget) {
|
||||
|
||||
@@ -20,6 +20,8 @@ import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAG
|
||||
import static com.android.launcher3.InvariantDeviceProfile.CHANGE_FLAG_ICON_PARAMS;
|
||||
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
|
||||
import static com.android.launcher3.Utilities.EDGE_NAV_BAR;
|
||||
import static com.android.launcher3.Utilities.squaredHypot;
|
||||
import static com.android.launcher3.Utilities.squaredTouchSlop;
|
||||
import static com.android.launcher3.anim.Interpolators.ACCEL;
|
||||
import static com.android.launcher3.anim.Interpolators.ACCEL_2;
|
||||
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
|
||||
@@ -64,7 +66,6 @@ import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.view.ViewDebug;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
@@ -75,7 +76,6 @@ import com.android.launcher3.BaseActivity;
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.Insettable;
|
||||
import com.android.launcher3.InvariantDeviceProfile;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherAnimUtils.ViewProgressProperty;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.PagedView;
|
||||
@@ -93,7 +93,6 @@ import com.android.launcher3.util.OverScroller;
|
||||
import com.android.launcher3.util.PendingAnimation;
|
||||
import com.android.launcher3.util.Themes;
|
||||
import com.android.launcher3.util.ViewPool;
|
||||
import com.android.launcher3.views.FloatingIconView;
|
||||
import com.android.quickstep.RecentsAnimationWrapper;
|
||||
import com.android.quickstep.RecentsModel;
|
||||
import com.android.quickstep.RecentsModel.TaskThumbnailChangeListener;
|
||||
@@ -281,7 +280,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
private boolean mHandleTaskStackChanges;
|
||||
private boolean mSwipeDownShouldLaunchApp;
|
||||
private boolean mTouchDownToStartHome;
|
||||
private final int mTouchSlop;
|
||||
private final float mSquaredTouchSlop;
|
||||
private int mDownX;
|
||||
private int mDownY;
|
||||
|
||||
@@ -306,8 +305,6 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
private Layout mEmptyTextLayout;
|
||||
private LiveTileOverlay mLiveTileOverlay;
|
||||
|
||||
private FloatingIconView mFloatingIconView;
|
||||
|
||||
private BaseActivity.MultiWindowModeChangedListener mMultiWindowModeChangedListener =
|
||||
(inMultiWindowMode) -> {
|
||||
if (!inMultiWindowMode && mOverviewStateEnabled) {
|
||||
@@ -339,7 +336,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
setLayoutDirection(mIsRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR);
|
||||
mTaskTopMargin = getResources()
|
||||
.getDimensionPixelSize(R.dimen.task_thumbnail_top_margin);
|
||||
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
|
||||
mSquaredTouchSlop = squaredTouchSlop(context);
|
||||
|
||||
mEmptyIcon = context.getDrawable(R.drawable.ic_empty_recents);
|
||||
mEmptyIcon.setCallback(this);
|
||||
@@ -496,7 +493,8 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
// Passing the touch slop will not allow dismiss to home
|
||||
if (mTouchDownToStartHome &&
|
||||
(isHandlingTouch() || Math.hypot(mDownX - x, mDownY - y) > mTouchSlop)) {
|
||||
(isHandlingTouch() ||
|
||||
squaredHypot(mDownX - x, mDownY - y) > mSquaredTouchSlop)) {
|
||||
mTouchDownToStartHome = false;
|
||||
}
|
||||
break;
|
||||
@@ -1684,12 +1682,6 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
}
|
||||
}
|
||||
|
||||
public FloatingIconView getFloatingIconView(Launcher launcher, View view, RectF iconLocation) {
|
||||
mFloatingIconView = FloatingIconView.getFloatingIconView(launcher, view,
|
||||
true /* hideOriginal */, iconLocation, false /* isOpening */, mFloatingIconView);
|
||||
return mFloatingIconView;
|
||||
}
|
||||
|
||||
public ClipAnimationHelper getTempClipAnimationHelper() {
|
||||
return mTempClipAnimationHelper;
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
android:importantForAccessibility="no" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/task_footer_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
@@ -43,7 +44,7 @@
|
||||
<FrameLayout
|
||||
android:id="@+id/proactive_suggest_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="36dp"
|
||||
android:layout_height="48dp"
|
||||
android:gravity="center"
|
||||
android:visibility="gone"
|
||||
/>
|
||||
|
||||
@@ -142,7 +142,6 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans
|
||||
private final float mClosingWindowTransY;
|
||||
|
||||
private DeviceProfile mDeviceProfile;
|
||||
private FloatingIconView mFloatingView;
|
||||
|
||||
private RemoteAnimationProvider mRemoteAnimationProvider;
|
||||
|
||||
@@ -411,15 +410,15 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans
|
||||
private ValueAnimator getOpeningWindowAnimators(View v, RemoteAnimationTargetCompat[] targets,
|
||||
Rect windowTargetBounds, boolean toggleVisibility) {
|
||||
RectF bounds = new RectF();
|
||||
mFloatingView = FloatingIconView.getFloatingIconView(mLauncher, v, toggleVisibility,
|
||||
bounds, true /* isOpening */, mFloatingView);
|
||||
FloatingIconView floatingView = FloatingIconView.getFloatingIconView(mLauncher, v,
|
||||
toggleVisibility, bounds, true /* isOpening */);
|
||||
Rect crop = new Rect();
|
||||
Matrix matrix = new Matrix();
|
||||
|
||||
RemoteAnimationTargetSet openingTargets = new RemoteAnimationTargetSet(targets,
|
||||
MODE_OPENING);
|
||||
SyncRtSurfaceTransactionApplierCompat surfaceApplier =
|
||||
new SyncRtSurfaceTransactionApplierCompat(mFloatingView);
|
||||
new SyncRtSurfaceTransactionApplierCompat(floatingView);
|
||||
openingTargets.addDependentTransactionApplier(surfaceApplier);
|
||||
|
||||
// Scale the app icon to take up the entire screen. This simplifies the math when
|
||||
@@ -463,7 +462,7 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans
|
||||
ValueAnimator appAnimator = ValueAnimator.ofFloat(0, 1);
|
||||
appAnimator.setDuration(APP_LAUNCH_DURATION);
|
||||
appAnimator.setInterpolator(LINEAR);
|
||||
appAnimator.addListener(mFloatingView);
|
||||
appAnimator.addListener(floatingView);
|
||||
appAnimator.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
@@ -557,7 +556,7 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans
|
||||
} else {
|
||||
currentBounds.bottom -= croppedHeight;
|
||||
}
|
||||
mFloatingView.update(currentBounds, mIconAlpha.value, percent, 0f,
|
||||
floatingView.update(currentBounds, mIconAlpha.value, percent, 0f,
|
||||
cornerRadius * scale, true /* isOpening */);
|
||||
} else {
|
||||
matrix.setTranslate(target.position.x, target.position.y);
|
||||
|
||||
@@ -111,6 +111,14 @@ public class TestInformationProvider extends ContentProvider {
|
||||
response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, (int) distance);
|
||||
break;
|
||||
}
|
||||
|
||||
case TestProtocol.REQUEST_ENABLE_DEBUG_TRACING:
|
||||
TestProtocol.sDebugTracing = true;
|
||||
break;
|
||||
|
||||
case TestProtocol.REQUEST_DISABLE_DEBUG_TRACING:
|
||||
TestProtocol.sDebugTracing = false;
|
||||
break;
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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.
|
||||
-->
|
||||
<com.android.launcher3.views.FloatingIconView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
@@ -86,7 +86,6 @@
|
||||
|
||||
<!-- View IDs to store item highlight information -->
|
||||
<item type="id" name="view_unhighlight_background" />
|
||||
<item type="id" name="view_highlighted" />
|
||||
|
||||
<!-- Menu id for feature flags -->
|
||||
<item type="id" name="menu_apply_flags" />
|
||||
|
||||
@@ -36,6 +36,7 @@ import com.android.launcher3.logging.UserEventDispatcher.UserEventDelegate;
|
||||
import com.android.launcher3.uioverrides.UiFactory;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||
import com.android.launcher3.util.SystemUiController;
|
||||
import com.android.launcher3.util.ViewCache;
|
||||
import com.android.launcher3.views.ActivityContext;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
@@ -102,6 +103,12 @@ public abstract class BaseActivity extends Activity
|
||||
// animation
|
||||
@InvisibilityFlags private int mForceInvisible;
|
||||
|
||||
private final ViewCache mViewCache = new ViewCache();
|
||||
|
||||
public ViewCache getViewCache() {
|
||||
return mViewCache;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeviceProfile getDeviceProfile() {
|
||||
return mDeviceProfile;
|
||||
|
||||
@@ -134,6 +134,10 @@ public abstract class BaseDraggingActivity extends BaseActivity
|
||||
|
||||
public boolean startActivitySafely(View v, Intent intent, @Nullable ItemInfo item,
|
||||
@Nullable String sourceContainer) {
|
||||
if (com.android.launcher3.TestProtocol.sDebugTracing) {
|
||||
android.util.Log.d(com.android.launcher3.TestProtocol.NO_START_TAG,
|
||||
"startActivitySafely 1");
|
||||
}
|
||||
if (mIsSafeModeEnabled && !Utilities.isSystemApp(this, intent)) {
|
||||
Toast.makeText(this, R.string.safemode_shortcut_error, Toast.LENGTH_SHORT).show();
|
||||
return false;
|
||||
@@ -157,6 +161,10 @@ public abstract class BaseDraggingActivity extends BaseActivity
|
||||
startShortcutIntentSafely(intent, optsBundle, item, sourceContainer);
|
||||
} else if (user == null || user.equals(Process.myUserHandle())) {
|
||||
// Could be launching some bookkeeping activity
|
||||
if (com.android.launcher3.TestProtocol.sDebugTracing) {
|
||||
android.util.Log.d(com.android.launcher3.TestProtocol.NO_START_TAG,
|
||||
"startActivitySafely 2");
|
||||
}
|
||||
startActivity(intent, optsBundle);
|
||||
AppLaunchTracker.INSTANCE.get(this).onStartApp(intent.getComponent(),
|
||||
Process.myUserHandle(), sourceContainer);
|
||||
|
||||
@@ -51,7 +51,6 @@ import com.android.launcher3.graphics.PreloadIconDrawable;
|
||||
import com.android.launcher3.icons.DotRenderer;
|
||||
import com.android.launcher3.icons.IconCache.IconLoadRequest;
|
||||
import com.android.launcher3.icons.IconCache.ItemInfoUpdateReceiver;
|
||||
import com.android.launcher3.icons.LauncherIcons;
|
||||
import com.android.launcher3.model.PackageItemInfo;
|
||||
import com.android.launcher3.views.ActivityContext;
|
||||
|
||||
@@ -561,7 +560,10 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
|
||||
}
|
||||
}
|
||||
if (itemInfo.contentDescription != null) {
|
||||
if (hasDot()) {
|
||||
if (itemInfo.isDisabled()) {
|
||||
setContentDescription(getContext().getString(R.string.disabled_app_label,
|
||||
itemInfo.contentDescription));
|
||||
} else if (hasDot()) {
|
||||
int count = mDotInfo.getNotificationCount();
|
||||
setContentDescription(getContext().getResources().getQuantityString(
|
||||
R.plurals.dotted_app_label, count, itemInfo.contentDescription, count));
|
||||
|
||||
@@ -1782,6 +1782,10 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
||||
|
||||
public boolean startActivitySafely(View v, Intent intent, ItemInfo item,
|
||||
@Nullable String sourceContainer) {
|
||||
if (com.android.launcher3.TestProtocol.sDebugTracing) {
|
||||
android.util.Log.d(com.android.launcher3.TestProtocol.NO_START_TAG,
|
||||
"startActivitySafely outer");
|
||||
}
|
||||
boolean success = super.startActivitySafely(v, intent, item, sourceContainer);
|
||||
if (success && v instanceof BubbleTextView) {
|
||||
// This is set to the view that launched the activity that navigated the user away
|
||||
|
||||
@@ -447,6 +447,10 @@ public class LauncherStateManager {
|
||||
}
|
||||
|
||||
private void onStateTransitionStart(LauncherState state) {
|
||||
if (com.android.launcher3.TestProtocol.sDebugTracing) {
|
||||
android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
|
||||
"onStateTransitionStart");
|
||||
}
|
||||
if (mState != state) {
|
||||
mState.onStateDisabled(mLauncher);
|
||||
}
|
||||
@@ -572,6 +576,10 @@ public class LauncherStateManager {
|
||||
private final AnimatorSet mAnim;
|
||||
|
||||
public StartAnimRunnable(AnimatorSet anim) {
|
||||
if (com.android.launcher3.TestProtocol.sDebugTracing) {
|
||||
android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
|
||||
"StartAnimRunnable");
|
||||
}
|
||||
mAnim = anim;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,8 +21,10 @@ import android.util.DisplayMetrics;
|
||||
import android.util.TypedValue;
|
||||
|
||||
public class ResourceUtils {
|
||||
public static final String NAVBAR_VERTICAL_SIZE = "navigation_bar_frame_height";
|
||||
public static final String NAVBAR_HORIZONTAL_SIZE = "navigation_bar_width";
|
||||
public static final String NAVBAR_PORTRAIT_BOTTOM_SIZE = "navigation_bar_frame_height";
|
||||
public static final String NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE = "navigation_bar_width";
|
||||
public static final String NAVBAR_LANDSCAPE_BOTTOM_SIZE
|
||||
= "navigation_bar_frame_height_landscape";
|
||||
|
||||
public static int getNavbarSize(String resName, Resources res) {
|
||||
return getDimenByName(resName, res, 48);
|
||||
|
||||
@@ -64,4 +64,9 @@ public final class TestProtocol {
|
||||
"all-apps-to-overview-swipe-height";
|
||||
public static final String REQUEST_HOME_TO_ALL_APPS_SWIPE_HEIGHT =
|
||||
"home-to-all-apps-swipe-height";
|
||||
public static boolean sDebugTracing = false;
|
||||
public static final String REQUEST_ENABLE_DEBUG_TRACING = "enable-debug-tracing";
|
||||
public static final String REQUEST_DISABLE_DEBUG_TRACING = "disable-debug-tracing";
|
||||
public static final String NO_DRAG_TAG = "b/133009122";
|
||||
public static final String NO_START_TAG = "b/132900132";
|
||||
}
|
||||
|
||||
@@ -61,6 +61,7 @@ import android.util.Pair;
|
||||
import android.util.TypedValue;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import com.android.launcher3.compat.LauncherAppsCompat;
|
||||
@@ -726,6 +727,15 @@ public final class Utilities {
|
||||
return str.toString();
|
||||
}
|
||||
|
||||
public static float squaredHypot(float x, float y) {
|
||||
return x * x + y * y;
|
||||
}
|
||||
|
||||
public static float squaredTouchSlop(Context context) {
|
||||
float slop = ViewConfiguration.get(context).getScaledTouchSlop();
|
||||
return slop * slop;
|
||||
}
|
||||
|
||||
private static class FixedSizeEmptyDrawable extends ColorDrawable {
|
||||
|
||||
private final int mSize;
|
||||
|
||||
@@ -371,6 +371,10 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
||||
|
||||
@Override
|
||||
public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) {
|
||||
if (com.android.launcher3.TestProtocol.sDebugTracing) {
|
||||
android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
|
||||
"onDragStart 1");
|
||||
}
|
||||
if (ENFORCE_DRAG_EVENT_ORDER) {
|
||||
enforceDragParity("onDragStart", 0, 0);
|
||||
}
|
||||
@@ -421,6 +425,10 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
||||
}
|
||||
|
||||
// Always enter the spring loaded mode
|
||||
if (com.android.launcher3.TestProtocol.sDebugTracing) {
|
||||
android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
|
||||
"onDragStart 2");
|
||||
}
|
||||
mLauncher.getStateManager().goToState(SPRING_LOADED);
|
||||
}
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ import com.android.launcher3.Insettable;
|
||||
import com.android.launcher3.InsettableFrameLayout;
|
||||
import com.android.launcher3.ItemInfo;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.TestProtocol;
|
||||
import com.android.launcher3.Utilities;
|
||||
@@ -193,11 +194,18 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
|
||||
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
||||
|
||||
// The AllAppsContainerView houses the QSB and is hence visible from the Workspace
|
||||
// Overview states. We shouldn't intercept for the scrubber in these cases.
|
||||
if (!mLauncher.isInState(LauncherState.ALL_APPS)) return false;
|
||||
|
||||
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
|
||||
AllAppsRecyclerView rv = getActiveRecyclerView();
|
||||
if (rv != null &&
|
||||
rv.getScrollbar().isHitInParent(ev.getX(), ev.getY(), mFastScrollerOffset)) {
|
||||
mTouchHandler = rv.getScrollbar();
|
||||
} else {
|
||||
mTouchHandler = null;
|
||||
}
|
||||
}
|
||||
if (mTouchHandler != null) {
|
||||
|
||||
@@ -472,6 +472,10 @@ public class DragController implements DragDriver.EventListener, TouchController
|
||||
}
|
||||
|
||||
private void handleMoveEvent(int x, int y) {
|
||||
if (com.android.launcher3.TestProtocol.sDebugTracing) {
|
||||
android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
|
||||
"handleMoveEvent 1");
|
||||
}
|
||||
mDragObject.dragView.move(x, y);
|
||||
|
||||
// Drop on someone?
|
||||
@@ -488,6 +492,10 @@ public class DragController implements DragDriver.EventListener, TouchController
|
||||
|
||||
if (mIsInPreDrag && mOptions.preDragCondition != null
|
||||
&& mOptions.preDragCondition.shouldStartDrag(mDistanceSinceScroll)) {
|
||||
if (com.android.launcher3.TestProtocol.sDebugTracing) {
|
||||
android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
|
||||
"handleMoveEvent 2");
|
||||
}
|
||||
callOnDragStart();
|
||||
}
|
||||
}
|
||||
@@ -525,6 +533,10 @@ public class DragController implements DragDriver.EventListener, TouchController
|
||||
* Call this from a drag source view.
|
||||
*/
|
||||
public boolean onControllerTouchEvent(MotionEvent ev) {
|
||||
if (com.android.launcher3.TestProtocol.sDebugTracing) {
|
||||
android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
|
||||
"onControllerTouchEvent");
|
||||
}
|
||||
if (mDragDriver == null || mOptions == null || mOptions.isAccessibleDrag) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -44,7 +44,6 @@ import android.view.View;
|
||||
import com.android.launcher3.FastBitmapDrawable;
|
||||
import com.android.launcher3.ItemInfo;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherModel;
|
||||
import com.android.launcher3.LauncherSettings;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.LauncherStateManager;
|
||||
@@ -55,6 +54,7 @@ import com.android.launcher3.anim.Interpolators;
|
||||
import com.android.launcher3.icons.LauncherIcons;
|
||||
import com.android.launcher3.util.Themes;
|
||||
import com.android.launcher3.util.Thunk;
|
||||
import com.android.launcher3.util.UiThreadHelper;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
@@ -210,8 +210,7 @@ public class DragView extends View implements LauncherStateManager.StateListener
|
||||
return;
|
||||
}
|
||||
// Load the adaptive icon on a background thread and add the view in ui thread.
|
||||
final Looper workerLooper = LauncherModel.getWorkerLooper();
|
||||
new Handler(workerLooper).postAtFrontOfQueue(new Runnable() {
|
||||
new Handler(UiThreadHelper.getBackgroundLooper()).postAtFrontOfQueue(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Object[] outObj = new Object[1];
|
||||
|
||||
@@ -593,6 +593,10 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
||||
protected void handleClose(boolean animate) {
|
||||
mIsOpen = false;
|
||||
|
||||
if (!animate && mCurrentAnimator != null && mCurrentAnimator.isRunning()) {
|
||||
mCurrentAnimator.cancel();
|
||||
}
|
||||
|
||||
if (isEditingName()) {
|
||||
mFolderName.dispatchBackKey();
|
||||
}
|
||||
|
||||
@@ -102,7 +102,6 @@ public class FolderIcon extends FrameLayout implements FolderListener {
|
||||
private List<BubbleTextView> mCurrentPreviewItems = new ArrayList<>();
|
||||
|
||||
boolean mAnimating = false;
|
||||
private Rect mTempBounds = new Rect();
|
||||
|
||||
private float mSlop;
|
||||
|
||||
@@ -203,6 +202,10 @@ public class FolderIcon extends FrameLayout implements FolderListener {
|
||||
mBackground.getBounds(outBounds);
|
||||
}
|
||||
|
||||
public float getBackgroundStrokeWidth() {
|
||||
return mBackground.getStrokeWidth();
|
||||
}
|
||||
|
||||
public Folder getFolder() {
|
||||
return mFolder;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package com.android.launcher3.popup;
|
||||
|
||||
import static com.android.launcher3.Utilities.squaredHypot;
|
||||
import static com.android.launcher3.Utilities.squaredTouchSlop;
|
||||
import static com.android.launcher3.notification.NotificationMainView.NOTIFICATION_ITEM_INFO;
|
||||
import static com.android.launcher3.popup.PopupPopulator.MAX_SHORTCUTS;
|
||||
import static com.android.launcher3.popup.PopupPopulator.MAX_SHORTCUTS_IF_NOTIFICATIONS;
|
||||
@@ -37,7 +39,6 @@ import android.util.AttributeSet;
|
||||
import android.util.Pair;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
|
||||
@@ -51,6 +52,7 @@ import com.android.launcher3.ItemInfoWithIcon;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherModel;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
|
||||
import com.android.launcher3.accessibility.ShortcutMenuAccessibilityDelegate;
|
||||
import com.android.launcher3.dot.DotInfo;
|
||||
@@ -136,8 +138,8 @@ public class PopupContainerWithArrow extends ArrowPopup implements DragSource,
|
||||
return true;
|
||||
}
|
||||
// Stop sending touch events to deep shortcut views if user moved beyond touch slop.
|
||||
return Math.hypot(mInterceptTouchDown.x - ev.getX(), mInterceptTouchDown.y - ev.getY())
|
||||
> ViewConfiguration.get(getContext()).getScaledTouchSlop();
|
||||
return squaredHypot(mInterceptTouchDown.x - ev.getX(), mInterceptTouchDown.y - ev.getY())
|
||||
> squaredTouchSlop(getContext());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -66,14 +66,26 @@ public class ItemClickHandler {
|
||||
}
|
||||
|
||||
private static void onClick(View v, String sourceContainer) {
|
||||
if (com.android.launcher3.TestProtocol.sDebugTracing) {
|
||||
android.util.Log.d(com.android.launcher3.TestProtocol.NO_START_TAG,
|
||||
"onClick 1");
|
||||
}
|
||||
// Make sure that rogue clicks don't get through while allapps is launching, or after the
|
||||
// view has detached (it's possible for this to happen if the view is removed mid touch).
|
||||
if (v.getWindowToken() == null) {
|
||||
if (com.android.launcher3.TestProtocol.sDebugTracing) {
|
||||
android.util.Log.d(com.android.launcher3.TestProtocol.NO_START_TAG,
|
||||
"onClick 2");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Launcher launcher = Launcher.getLauncher(v.getContext());
|
||||
if (!launcher.getWorkspace().isFinishedSwitchingState()) {
|
||||
if (com.android.launcher3.TestProtocol.sDebugTracing) {
|
||||
android.util.Log.d(com.android.launcher3.TestProtocol.NO_START_TAG,
|
||||
"onClick 3");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -85,6 +97,10 @@ public class ItemClickHandler {
|
||||
onClickFolderIcon(v);
|
||||
}
|
||||
} else if (tag instanceof AppInfo) {
|
||||
if (com.android.launcher3.TestProtocol.sDebugTracing) {
|
||||
android.util.Log.d(com.android.launcher3.TestProtocol.NO_START_TAG,
|
||||
"onClick 4");
|
||||
}
|
||||
startAppShortcutOrInfoActivity(v, (AppInfo) tag, launcher,
|
||||
sourceContainer == null ? CONTAINER_ALL_APPS: sourceContainer);
|
||||
} else if (tag instanceof LauncherAppWidgetInfo) {
|
||||
@@ -216,6 +232,10 @@ public class ItemClickHandler {
|
||||
|
||||
private static void startAppShortcutOrInfoActivity(View v, ItemInfo item, Launcher launcher,
|
||||
@Nullable String sourceContainer) {
|
||||
if (com.android.launcher3.TestProtocol.sDebugTracing) {
|
||||
android.util.Log.d(com.android.launcher3.TestProtocol.NO_START_TAG,
|
||||
"startAppShortcutOrInfoActivity");
|
||||
}
|
||||
Intent intent;
|
||||
if (item instanceof PromiseAppInfo) {
|
||||
PromiseAppInfo promiseAppInfo = (PromiseAppInfo) item;
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.SparseArray;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
/**
|
||||
* Utility class to cache views at an activity level
|
||||
*/
|
||||
public class ViewCache {
|
||||
|
||||
protected final SparseArray<CacheEntry> mCache = new SparseArray();
|
||||
|
||||
public void setCacheSize(int layoutId, int size) {
|
||||
mCache.put(layoutId, new CacheEntry(size));
|
||||
}
|
||||
|
||||
public <T extends View> T getView(int layoutId, Context context, ViewGroup parent) {
|
||||
CacheEntry entry = mCache.get(layoutId);
|
||||
if (entry == null) {
|
||||
entry = new CacheEntry(1);
|
||||
mCache.put(layoutId, entry);
|
||||
}
|
||||
|
||||
if (entry.mCurrentSize > 0) {
|
||||
entry.mCurrentSize --;
|
||||
T result = (T) entry.mViews[entry.mCurrentSize];
|
||||
entry.mViews[entry.mCurrentSize] = null;
|
||||
return result;
|
||||
}
|
||||
|
||||
return (T) LayoutInflater.from(context).inflate(layoutId, parent, false);
|
||||
}
|
||||
|
||||
public void recycleView(int layoutId, View view) {
|
||||
CacheEntry entry = mCache.get(layoutId);
|
||||
if (entry != null && entry.mCurrentSize < entry.mMaxSize) {
|
||||
entry.mViews[entry.mCurrentSize] = view;
|
||||
entry.mCurrentSize++;
|
||||
}
|
||||
}
|
||||
|
||||
private static class CacheEntry {
|
||||
|
||||
final int mMaxSize;
|
||||
final View[] mViews;
|
||||
|
||||
int mCurrentSize;
|
||||
|
||||
public CacheEntry(int maxSize) {
|
||||
mMaxSize = maxSize;
|
||||
mViews = new View[maxSize];
|
||||
mCurrentSize = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -213,6 +213,10 @@ public abstract class BaseDragLayer<T extends Context & ActivityContext>
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent ev) {
|
||||
if (com.android.launcher3.TestProtocol.sDebugTracing) {
|
||||
android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
|
||||
"onTouchEvent " + ev);
|
||||
}
|
||||
int action = ev.getAction();
|
||||
if (action == ACTION_UP || action == ACTION_CANCEL) {
|
||||
if (mTouchCompleteListener != null) {
|
||||
@@ -222,6 +226,10 @@ public abstract class BaseDragLayer<T extends Context & ActivityContext>
|
||||
}
|
||||
|
||||
if (mActiveController != null) {
|
||||
if (com.android.launcher3.TestProtocol.sDebugTracing) {
|
||||
android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
|
||||
"onTouchEvent 1");
|
||||
}
|
||||
return mActiveController.onControllerTouchEvent(ev);
|
||||
} else {
|
||||
// In case no child view handled the touch event, we may not get onIntercept anymore
|
||||
|
||||
@@ -27,6 +27,7 @@ import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Outline;
|
||||
@@ -40,6 +41,7 @@ import android.os.Build;
|
||||
import android.os.CancellationSignal;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewOutlineProvider;
|
||||
@@ -61,6 +63,7 @@ import com.android.launcher3.graphics.ShiftedBitmapDrawable;
|
||||
import com.android.launcher3.icons.LauncherIcons;
|
||||
import com.android.launcher3.popup.SystemShortcut;
|
||||
import com.android.launcher3.shortcuts.DeepShortcutView;
|
||||
import com.android.launcher3.util.UiThreadHelper;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.WorkerThread;
|
||||
@@ -148,12 +151,20 @@ public class FloatingIconView extends View implements
|
||||
private final SpringAnimation mFgSpringX;
|
||||
private float mFgTransX;
|
||||
|
||||
private FloatingIconView(Launcher launcher) {
|
||||
super(launcher);
|
||||
mLauncher = launcher;
|
||||
public FloatingIconView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public FloatingIconView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public FloatingIconView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
mLauncher = Launcher.getLauncher(context);
|
||||
mBlurSizeOutline = getResources().getDimensionPixelSize(
|
||||
R.dimen.blur_size_medium_outline);
|
||||
mListenerView = new ListenerView(launcher, null);
|
||||
mListenerView = new ListenerView(context, attrs);
|
||||
|
||||
mFgSpringX = new SpringAnimation(this, mFgTransXProperty)
|
||||
.setSpring(new SpringForce()
|
||||
@@ -259,8 +270,6 @@ public class FloatingIconView extends View implements
|
||||
mFgSpringX.animateToFinalPosition(diffX);
|
||||
mFgSpringY.animateToFinalPosition(diffY);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
invalidate();
|
||||
invalidateOutline();
|
||||
@@ -352,6 +361,7 @@ public class FloatingIconView extends View implements
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
@SuppressWarnings("WrongThread")
|
||||
private void getIcon(View v, ItemInfo info, boolean isOpening,
|
||||
Runnable onIconLoadedRunnable, CancellationSignal loadIconSignal) {
|
||||
final LayoutParams lp = (LayoutParams) getLayoutParams();
|
||||
@@ -368,10 +378,13 @@ public class FloatingIconView extends View implements
|
||||
drawable = v.getBackground();
|
||||
}
|
||||
} else {
|
||||
boolean isFolderIcon = v instanceof FolderIcon;
|
||||
int width = isFolderIcon ? v.getWidth() : lp.width;
|
||||
int height = isFolderIcon ? v.getHeight() : lp.height;
|
||||
if (supportsAdaptiveIcons) {
|
||||
drawable = Utilities.getFullDrawable(mLauncher, info, lp.width, lp.height,
|
||||
false, sTmpObjArray);
|
||||
if ((drawable instanceof AdaptiveIconDrawable)) {
|
||||
drawable = Utilities.getFullDrawable(mLauncher, info, width, height, false,
|
||||
sTmpObjArray);
|
||||
if (drawable instanceof AdaptiveIconDrawable) {
|
||||
mBadge = getBadge(mLauncher, info, sTmpObjArray[0]);
|
||||
} else {
|
||||
// The drawable we get back is not an adaptive icon, so we need to use the
|
||||
@@ -383,8 +396,8 @@ public class FloatingIconView extends View implements
|
||||
// Similar to DragView, we simply use the BubbleTextView icon here.
|
||||
drawable = btvIcon;
|
||||
} else {
|
||||
drawable = Utilities.getFullDrawable(mLauncher, info, lp.width, lp.height,
|
||||
false, sTmpObjArray);
|
||||
drawable = Utilities.getFullDrawable(mLauncher, info, width, height, false,
|
||||
sTmpObjArray);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -395,7 +408,7 @@ public class FloatingIconView extends View implements
|
||||
&& finalDrawable instanceof AdaptiveIconDrawable;
|
||||
int iconOffset = getOffsetForIconBounds(finalDrawable);
|
||||
|
||||
new Handler(Looper.getMainLooper()).post(() -> {
|
||||
mLauncher.getMainExecutor().execute(() -> {
|
||||
if (isAdaptiveIcon) {
|
||||
mIsAdaptiveIcon = true;
|
||||
boolean isFolderIcon = finalDrawable instanceof FolderAdaptiveIcon;
|
||||
@@ -412,13 +425,6 @@ public class FloatingIconView extends View implements
|
||||
}
|
||||
mForeground = foreground;
|
||||
|
||||
if (mForeground instanceof ShiftedBitmapDrawable && v instanceof FolderIcon) {
|
||||
ShiftedBitmapDrawable sbd = (ShiftedBitmapDrawable) mForeground;
|
||||
((FolderIcon) v).getPreviewBounds(sTmpRect);
|
||||
sbd.setShiftX(sbd.getShiftX() - sTmpRect.left);
|
||||
sbd.setShiftY(sbd.getShiftY() - sTmpRect.top);
|
||||
}
|
||||
|
||||
final int originalHeight = lp.height;
|
||||
final int originalWidth = lp.width;
|
||||
|
||||
@@ -434,13 +440,25 @@ public class FloatingIconView extends View implements
|
||||
|
||||
if (mBadge != null) {
|
||||
mBadge.setBounds(mStartRevealRect);
|
||||
if (!isOpening) {
|
||||
if (!isOpening && !isFolderIcon) {
|
||||
DRAWABLE_ALPHA.set(mBadge, 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!isFolderIcon) {
|
||||
if (isFolderIcon) {
|
||||
((FolderIcon) v).getPreviewBounds(sTmpRect);
|
||||
float bgStroke = ((FolderIcon) v).getBackgroundStrokeWidth();
|
||||
if (mForeground instanceof ShiftedBitmapDrawable) {
|
||||
ShiftedBitmapDrawable sbd = (ShiftedBitmapDrawable) mForeground;
|
||||
sbd.setShiftX(sbd.getShiftX() - sTmpRect.left - bgStroke);
|
||||
sbd.setShiftY(sbd.getShiftY() - sTmpRect.top - bgStroke);
|
||||
}
|
||||
if (mBadge instanceof ShiftedBitmapDrawable) {
|
||||
ShiftedBitmapDrawable sbd = (ShiftedBitmapDrawable) mBadge;
|
||||
sbd.setShiftX(sbd.getShiftX() - sTmpRect.left - bgStroke);
|
||||
sbd.setShiftY(sbd.getShiftY() - sTmpRect.top - bgStroke);
|
||||
}
|
||||
} else {
|
||||
Utilities.scaleRectAboutCenter(mStartRevealRect,
|
||||
IconShape.getNormalizationScale());
|
||||
}
|
||||
@@ -475,6 +493,7 @@ public class FloatingIconView extends View implements
|
||||
setClipToOutline(true);
|
||||
} else {
|
||||
setBackground(finalDrawable);
|
||||
setClipToOutline(false);
|
||||
}
|
||||
|
||||
if (!loadIconSignal.isCanceled()) {
|
||||
@@ -498,6 +517,7 @@ public class FloatingIconView extends View implements
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
@SuppressWarnings("WrongThread")
|
||||
private int getOffsetForIconBounds(Drawable drawable) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O ||
|
||||
!(drawable instanceof AdaptiveIconDrawable)) {
|
||||
@@ -508,7 +528,7 @@ public class FloatingIconView extends View implements
|
||||
Rect bounds = new Rect(0, 0, lp.width + mBlurSizeOutline, lp.height + mBlurSizeOutline);
|
||||
bounds.inset(mBlurSizeOutline / 2, mBlurSizeOutline / 2);
|
||||
|
||||
try (LauncherIcons li = LauncherIcons.obtain(getContext())) {
|
||||
try (LauncherIcons li = LauncherIcons.obtain(mLauncher)) {
|
||||
Utilities.scaleRectAboutCenter(bounds, li.getNormalizer().getScale(drawable, null));
|
||||
}
|
||||
|
||||
@@ -597,11 +617,14 @@ public class FloatingIconView extends View implements
|
||||
* @param isOpening True if this view replaces the icon for app open animation.
|
||||
*/
|
||||
public static FloatingIconView getFloatingIconView(Launcher launcher, View originalView,
|
||||
boolean hideOriginal, RectF positionOut, boolean isOpening, FloatingIconView recycle) {
|
||||
if (recycle != null) {
|
||||
recycle.recycle();
|
||||
}
|
||||
FloatingIconView view = recycle != null ? recycle : new FloatingIconView(launcher);
|
||||
boolean hideOriginal, RectF positionOut, boolean isOpening) {
|
||||
final DragLayer dragLayer = launcher.getDragLayer();
|
||||
ViewGroup parent = (ViewGroup) dragLayer.getParent();
|
||||
|
||||
FloatingIconView view = launcher.getViewCache().getView(R.layout.floating_icon_view,
|
||||
launcher, parent);
|
||||
view.recycle();
|
||||
|
||||
view.mIsVerticalBarLayout = launcher.getDeviceProfile().isVerticalBarLayout();
|
||||
|
||||
view.mOriginalIcon = originalView;
|
||||
@@ -619,16 +642,15 @@ public class FloatingIconView extends View implements
|
||||
originalView.setVisibility(INVISIBLE);
|
||||
};
|
||||
CancellationSignal loadIconSignal = view.mLoadIconSignal;
|
||||
new Handler(LauncherModel.getWorkerLooper()).postAtFrontOfQueue(() -> {
|
||||
new Handler(UiThreadHelper.getBackgroundLooper()).postAtFrontOfQueue(() -> {
|
||||
view.getIcon(originalView, (ItemInfo) originalView.getTag(), isOpening,
|
||||
onIconLoaded, loadIconSignal);
|
||||
});
|
||||
}
|
||||
|
||||
// We need to add it to the overlay, but keep it invisible until animation starts..
|
||||
final DragLayer dragLayer = launcher.getDragLayer();
|
||||
view.setVisibility(INVISIBLE);
|
||||
((ViewGroup) dragLayer.getParent()).addView(view);
|
||||
parent.addView(view);
|
||||
dragLayer.addView(view.mListenerView);
|
||||
view.mListenerView.setListener(view::onListenerViewClosed);
|
||||
|
||||
@@ -665,7 +687,7 @@ public class FloatingIconView extends View implements
|
||||
}
|
||||
});
|
||||
|
||||
if (mBadge != null) {
|
||||
if (mBadge != null && !(mOriginalIcon instanceof FolderIcon)) {
|
||||
ObjectAnimator badgeFade = ObjectAnimator.ofInt(mBadge, DRAWABLE_ALPHA, 255);
|
||||
badgeFade.addUpdateListener(valueAnimator -> invalidate());
|
||||
fade.play(badgeFade);
|
||||
@@ -691,7 +713,6 @@ public class FloatingIconView extends View implements
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
folderIcon.setBackgroundVisible(true);
|
||||
folderIcon.animateBgShadowAndStroke();
|
||||
if (folderIcon.hasDot()) {
|
||||
folderIcon.animateDotScale(0, 1f);
|
||||
}
|
||||
@@ -708,6 +729,7 @@ public class FloatingIconView extends View implements
|
||||
((ViewGroup) dragLayer.getParent()).removeView(this);
|
||||
dragLayer.removeView(mListenerView);
|
||||
recycle();
|
||||
mLauncher.getViewCache().recycleView(R.layout.floating_icon_view, this);
|
||||
}
|
||||
|
||||
private void recycle() {
|
||||
@@ -746,5 +768,6 @@ public class FloatingIconView extends View implements
|
||||
mFgTransX = 0;
|
||||
mFgSpringY.cancel();
|
||||
mBadge = null;
|
||||
sTmpObjArray[0] = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -243,7 +243,7 @@ public abstract class AbstractLauncherUiTest {
|
||||
*/
|
||||
protected UiObject2 scrollAndFind(UiObject2 container, BySelector condition) {
|
||||
final int margin = ResourceUtils.getNavbarSize(
|
||||
ResourceUtils.NAVBAR_VERTICAL_SIZE, mLauncher.getResources()) + 1;
|
||||
ResourceUtils.NAVBAR_PORTRAIT_BOTTOM_SIZE, mLauncher.getResources()) + 1;
|
||||
container.setGestureMargins(0, 0, 0, margin);
|
||||
|
||||
int i = 0;
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.android.launcher3.tapl;
|
||||
|
||||
import static com.android.launcher3.tapl.LauncherInstrumentation.NavigationModel.ZERO_BUTTON;
|
||||
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
@@ -48,12 +49,34 @@ public class AllApps extends LauncherInstrumentation.VisibleContainer {
|
||||
return LauncherInstrumentation.ContainerType.ALL_APPS;
|
||||
}
|
||||
|
||||
private boolean hasClickableIcon(UiObject2 allAppsContainer, BySelector appIconSelector) {
|
||||
final UiObject2 icon = allAppsContainer.findObject(appIconSelector);
|
||||
if (icon == null) return false;
|
||||
if (mLauncher.getNavigationModel() == ZERO_BUTTON) return true;
|
||||
final UiObject2 navBar = mLauncher.waitForSystemUiObject("navigation_bar_frame");
|
||||
return icon.getVisibleBounds().bottom < navBar.getVisibleBounds().top;
|
||||
private boolean hasClickableIcon(
|
||||
UiObject2 allAppsContainer, UiObject2 appListRecycler, BySelector appIconSelector) {
|
||||
final UiObject2 icon = appListRecycler.findObject(appIconSelector);
|
||||
if (icon == null) {
|
||||
LauncherInstrumentation.log("hasClickableIcon: icon not visible");
|
||||
return false;
|
||||
}
|
||||
final Rect iconBounds = icon.getVisibleBounds();
|
||||
LauncherInstrumentation.log("hasClickableIcon: icon bounds: " + iconBounds);
|
||||
if (mLauncher.getNavigationModel() != ZERO_BUTTON) {
|
||||
final UiObject2 navBar = mLauncher.waitForSystemUiObject("navigation_bar_frame");
|
||||
if (iconBounds.bottom >= navBar.getVisibleBounds().top) {
|
||||
LauncherInstrumentation.log("hasClickableIcon: icon intersects with nav bar");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (iconCenterInSearchBox(allAppsContainer, icon)) {
|
||||
LauncherInstrumentation.log("hasClickableIcon: icon center is under search box");
|
||||
return false;
|
||||
}
|
||||
LauncherInstrumentation.log("hasClickableIcon: icon is clickable");
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean iconCenterInSearchBox(UiObject2 allAppsContainer, UiObject2 icon) {
|
||||
final Point iconCenter = icon.getVisibleCenter();
|
||||
return getSearchBox(allAppsContainer).getVisibleBounds().contains(
|
||||
iconCenter.x, iconCenter.y);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -66,17 +89,22 @@ public class AllApps extends LauncherInstrumentation.VisibleContainer {
|
||||
@NonNull
|
||||
public AppIcon getAppIcon(String appName) {
|
||||
try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
|
||||
"want to get app icon on all apps")) {
|
||||
"want to get app icon " + appName + " on all apps")) {
|
||||
final UiObject2 allAppsContainer = verifyActiveContainer();
|
||||
allAppsContainer.setGestureMargins(0, 0, 0,
|
||||
ResourceUtils.getNavbarSize(ResourceUtils.NAVBAR_VERTICAL_SIZE,
|
||||
final UiObject2 appListRecycler = mLauncher.waitForObjectInContainer(allAppsContainer,
|
||||
"apps_list_view");
|
||||
allAppsContainer.setGestureMargins(
|
||||
0,
|
||||
getSearchBox(allAppsContainer).getVisibleBounds().bottom + 1,
|
||||
0,
|
||||
ResourceUtils.getNavbarSize(ResourceUtils.NAVBAR_PORTRAIT_BOTTOM_SIZE,
|
||||
mLauncher.getResources()) + 1);
|
||||
final BySelector appIconSelector = AppIcon.getAppIconSelector(appName, mLauncher);
|
||||
if (!hasClickableIcon(allAppsContainer, appIconSelector)) {
|
||||
if (!hasClickableIcon(allAppsContainer, appListRecycler, appIconSelector)) {
|
||||
scrollBackToBeginning();
|
||||
int attempts = 0;
|
||||
try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("scrolled")) {
|
||||
while (!hasClickableIcon(allAppsContainer, appIconSelector) &&
|
||||
while (!hasClickableIcon(allAppsContainer, appListRecycler, appIconSelector) &&
|
||||
allAppsContainer.scroll(Direction.DOWN, 0.8f)) {
|
||||
mLauncher.assertTrue(
|
||||
"Exceeded max scroll attempts: " + MAX_SCROLL_ATTEMPTS,
|
||||
@@ -89,7 +117,7 @@ public class AllApps extends LauncherInstrumentation.VisibleContainer {
|
||||
|
||||
final UiObject2 appIcon = mLauncher.getObjectInContainer(allAppsContainer,
|
||||
appIconSelector);
|
||||
ensureIconVisible(appIcon, allAppsContainer);
|
||||
ensureIconVisible(appIcon, allAppsContainer, appListRecycler);
|
||||
return new AppIcon(mLauncher, appIcon);
|
||||
}
|
||||
}
|
||||
@@ -97,10 +125,9 @@ public class AllApps extends LauncherInstrumentation.VisibleContainer {
|
||||
private void scrollBackToBeginning() {
|
||||
try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
|
||||
"want to scroll back in all apps")) {
|
||||
LauncherInstrumentation.log("Scrolling to the beginning");
|
||||
final UiObject2 allAppsContainer = verifyActiveContainer();
|
||||
final UiObject2 searchBox =
|
||||
mLauncher.waitForObjectInContainer(allAppsContainer,
|
||||
"search_container_all_apps");
|
||||
final UiObject2 searchBox = getSearchBox(allAppsContainer);
|
||||
|
||||
int attempts = 0;
|
||||
final Rect margins = new Rect(0, searchBox.getVisibleBounds().bottom + 1, 0, 5);
|
||||
@@ -128,19 +155,26 @@ public class AllApps extends LauncherInstrumentation.VisibleContainer {
|
||||
getInt(TestProtocol.SCROLL_Y_FIELD, -1);
|
||||
}
|
||||
|
||||
private void ensureIconVisible(UiObject2 appIcon, UiObject2 allAppsContainer) {
|
||||
private void ensureIconVisible(
|
||||
UiObject2 appIcon, UiObject2 allAppsContainer, UiObject2 appListRecycler) {
|
||||
final int appHeight = appIcon.getVisibleBounds().height();
|
||||
if (appHeight < MIN_INTERACT_SIZE) {
|
||||
// Try to figure out how much percentage of the container needs to be scrolled in order
|
||||
// to reveal the app icon to have the MIN_INTERACT_SIZE
|
||||
final float pct = Math.max(((float) (MIN_INTERACT_SIZE - appHeight)) / mHeight, 0.2f);
|
||||
mLauncher.scroll(allAppsContainer, Direction.DOWN, pct, null, 10);
|
||||
mLauncher.scroll(appListRecycler, Direction.DOWN, pct, null, 10);
|
||||
try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
|
||||
"scrolled an icon in all apps to make it visible - and then")) {
|
||||
mLauncher.waitForIdle();
|
||||
verifyActiveContainer();
|
||||
}
|
||||
}
|
||||
mLauncher.assertTrue("Couldn't scroll app icon to not intersect with the search box",
|
||||
!iconCenterInSearchBox(allAppsContainer, appIcon));
|
||||
}
|
||||
|
||||
private UiObject2 getSearchBox(UiObject2 allAppsContainer) {
|
||||
return mLauncher.waitForObjectInContainer(allAppsContainer, "search_container_all_apps");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -53,9 +53,9 @@ public final class AllAppsFromOverview extends AllApps {
|
||||
TestProtocol.REQUEST_ALL_APPS_TO_OVERVIEW_SWIPE_HEIGHT).
|
||||
getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
|
||||
|
||||
final int endY = start.y + swipeHeight + mLauncher.getTouchSlop();
|
||||
final int endY = start.y + swipeHeight;
|
||||
LauncherInstrumentation.log("AllAppsFromOverview.switchBackToOverview before swipe");
|
||||
mLauncher.swipe(start.x, start.y, start.x, endY, OVERVIEW_STATE_ORDINAL);
|
||||
mLauncher.swipeToState(start.x, start.y, start.x, endY, 60, OVERVIEW_STATE_ORDINAL);
|
||||
|
||||
try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("swiped down")) {
|
||||
return new Overview(mLauncher);
|
||||
|
||||
@@ -86,9 +86,10 @@ public class Background extends LauncherInstrumentation.VisibleContainer {
|
||||
final int swipeHeight = mLauncher.getTestInfo(getSwipeHeightRequestName()).
|
||||
getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
|
||||
|
||||
mLauncher.swipe(
|
||||
mLauncher.swipeToState(
|
||||
centerX, startY, centerX,
|
||||
startY - swipeHeight - mLauncher.getTouchSlop(),
|
||||
60,
|
||||
expectedState);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -24,6 +24,8 @@ import androidx.test.uiautomator.UiDevice;
|
||||
import androidx.test.uiautomator.UiObject2;
|
||||
import androidx.test.uiautomator.Until;
|
||||
|
||||
import com.android.launcher3.TestProtocol;
|
||||
|
||||
/**
|
||||
* Ancestor for AppIcon and AppMenuItem.
|
||||
*/
|
||||
@@ -51,9 +53,11 @@ abstract class Launchable {
|
||||
private Background launch(BySelector selector) {
|
||||
LauncherInstrumentation.log("Launchable.launch before click " +
|
||||
mObject.getVisibleCenter());
|
||||
mLauncher.getTestInfo(TestProtocol.REQUEST_ENABLE_DEBUG_TRACING);
|
||||
mLauncher.assertTrue(
|
||||
"Launching an app didn't open a new window: " + mObject.getText(),
|
||||
mObject.clickAndWait(Until.newWindow(), LauncherInstrumentation.WAIT_TIME_MS));
|
||||
mLauncher.getTestInfo(TestProtocol.REQUEST_DISABLE_DEBUG_TRACING);
|
||||
mLauncher.assertTrue(
|
||||
"App didn't start: " + selector,
|
||||
mLauncher.getDevice().wait(Until.hasObject(selector),
|
||||
|
||||
@@ -584,18 +584,15 @@ public final class LauncherInstrumentation {
|
||||
return mDevice;
|
||||
}
|
||||
|
||||
void swipe(int startX, int startY, int endX, int endY, int expectedState) {
|
||||
swipe(startX, startY, endX, endY, expectedState, 60);
|
||||
}
|
||||
|
||||
void swipe(int startX, int startY, int endX, int endY, int expectedState, int steps) {
|
||||
changeStateViaGesture(startX, startY, endX, endY, expectedState,
|
||||
() -> mDevice.swipe(startX, startY, endX, endY, steps));
|
||||
}
|
||||
|
||||
void swipeToState(int startX, int startY, int endX, int endY, int steps, int expectedState) {
|
||||
changeStateViaGesture(startX, startY, endX, endY, expectedState,
|
||||
() -> linearGesture(startX, startY, endX, endY, steps));
|
||||
final Bundle parcel = (Bundle) executeAndWaitForEvent(
|
||||
() -> linearGesture(startX, startY, endX, endY, steps),
|
||||
event -> TestProtocol.SWITCHED_TO_STATE_MESSAGE.equals(event.getClassName()),
|
||||
"Swipe failed to receive an event for the swipe end: " + startX + ", " + startY
|
||||
+ ", " + endX + ", " + endY);
|
||||
assertEquals("Swipe switched launcher to a wrong state;",
|
||||
TestProtocol.stateOrdinalToString(expectedState),
|
||||
TestProtocol.stateOrdinalToString(parcel.getInt(TestProtocol.STATE_FIELD)));
|
||||
}
|
||||
|
||||
void scroll(UiObject2 container, Direction direction, float percent, Rect margins, int steps) {
|
||||
@@ -652,18 +649,6 @@ public final class LauncherInstrumentation {
|
||||
sendPointer(downTime, endTime, MotionEvent.ACTION_UP, end);
|
||||
}
|
||||
|
||||
private void changeStateViaGesture(int startX, int startY, int endX, int endY,
|
||||
int expectedState, Runnable gesture) {
|
||||
final Bundle parcel = (Bundle) executeAndWaitForEvent(
|
||||
gesture,
|
||||
event -> TestProtocol.SWITCHED_TO_STATE_MESSAGE.equals(event.getClassName()),
|
||||
"Swipe failed to receive an event for the swipe end: " + startX + ", " + startY
|
||||
+ ", " + endX + ", " + endY);
|
||||
assertEquals("Swipe switched launcher to a wrong state;",
|
||||
TestProtocol.stateOrdinalToString(expectedState),
|
||||
TestProtocol.stateOrdinalToString(parcel.getInt(TestProtocol.STATE_FIELD)));
|
||||
}
|
||||
|
||||
void waitForIdle() {
|
||||
mDevice.waitForIdle();
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ public final class Widgets extends LauncherInstrumentation.VisibleContainer {
|
||||
LauncherInstrumentation.log("Widgets.flingForward enter");
|
||||
final UiObject2 widgetsContainer = verifyActiveContainer();
|
||||
widgetsContainer.setGestureMargins(0, 0, 0,
|
||||
ResourceUtils.getNavbarSize(ResourceUtils.NAVBAR_VERTICAL_SIZE,
|
||||
ResourceUtils.getNavbarSize(ResourceUtils.NAVBAR_PORTRAIT_BOTTOM_SIZE,
|
||||
mLauncher.getResources()) + 1);
|
||||
widgetsContainer.fling(Direction.DOWN,
|
||||
(int) (FLING_SPEED * mLauncher.getDisplayDensity()));
|
||||
|
||||
@@ -148,6 +148,7 @@ public final class Workspace extends Home {
|
||||
static void dragIconToWorkspace(
|
||||
LauncherInstrumentation launcher, Launchable launchable, Point dest,
|
||||
String longPressIndicator) {
|
||||
launcher.getTestInfo(TestProtocol.REQUEST_ENABLE_DEBUG_TRACING);
|
||||
LauncherInstrumentation.log("dragIconToWorkspace: begin");
|
||||
final Point launchableCenter = launchable.getObject().getVisibleCenter();
|
||||
final long downTime = SystemClock.uptimeMillis();
|
||||
@@ -162,6 +163,7 @@ public final class Workspace extends Home {
|
||||
downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, dest);
|
||||
LauncherInstrumentation.log("dragIconToWorkspace: end");
|
||||
launcher.waitUntilGone("drop_target_bar");
|
||||
launcher.getTestInfo(TestProtocol.REQUEST_DISABLE_DEBUG_TRACING);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user