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:
Sunny Goyal
2019-05-22 17:24:58 -07:00
44 changed files with 462 additions and 158 deletions
+2 -1
View File
@@ -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>
+2 -1
View File
@@ -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>
@@ -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;
@@ -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()) {
@@ -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() {
@@ -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);
}
}
}
@@ -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);
@@ -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);
}
}
}
}
@@ -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)
@@ -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;
}
+2 -1
View File
@@ -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;
}
+19
View File
@@ -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" />
-1
View File
@@ -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));
+4
View File
@@ -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;
}
+4 -2
View File
@@ -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";
}
+10
View File
@@ -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;
+8
View File
@@ -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);
}
/**