Merge "[a11y] fix the issue where launcher announces item added to homescreen before it does" into ub-launcher3-master
diff --git a/AndroidManifest-common.xml b/AndroidManifest-common.xml
index 8db875b..555cc73 100644
--- a/AndroidManifest-common.xml
+++ b/AndroidManifest-common.xml
@@ -169,7 +169,7 @@
<activity
android:name="com.android.launcher3.settings.SettingsActivity"
android:label="@string/settings_button_text"
- android:theme="@android:style/Theme.DeviceDefault.Settings"
+ android:theme="@style/HomeSettingsTheme"
android:autoRemoveFromRecents="true">
<intent-filter>
<action android:name="android.intent.action.APPLICATION_PREFERENCES" />
diff --git a/go/AndroidManifest.xml b/go/AndroidManifest.xml
index fae1eff..f84a82e 100644
--- a/go/AndroidManifest.xml
+++ b/go/AndroidManifest.xml
@@ -22,7 +22,7 @@
xmlns:tools="http://schemas.android.com/tools"
package="com.android.launcher3" >
- <uses-sdk android:targetSdkVersion="28" android:minSdkVersion="25"/>
+ <uses-sdk android:targetSdkVersion="29" android:minSdkVersion="25"/>
<application
android:backupAgent="com.android.launcher3.LauncherBackupAgent"
diff --git a/go/quickstep/res/values/override.xml b/go/quickstep/res/values/override.xml
index 7636fb3..bb267a3 100644
--- a/go/quickstep/res/values/override.xml
+++ b/go/quickstep/res/values/override.xml
@@ -22,5 +22,7 @@
<string name="instant_app_resolver_class" translatable="false">com.android.quickstep.InstantAppResolverImpl</string>
<string name="main_process_initializer_class" translatable="false">com.android.quickstep.QuickstepProcessInitializer</string>
+
+ <string name="user_event_dispatcher_class" translatable="false">com.android.quickstep.logging.UserEventDispatcherExtension</string>
</resources>
diff --git a/go/quickstep/src/com/android/quickstep/util/ShelfPeekAnim.java b/go/quickstep/src/com/android/quickstep/util/ShelfPeekAnim.java
new file mode 100644
index 0000000..e7099ec
--- /dev/null
+++ b/go/quickstep/src/com/android/quickstep/util/ShelfPeekAnim.java
@@ -0,0 +1,27 @@
+/*
+ * 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.quickstep.util;
+
+import com.android.launcher3.Launcher;
+
+/** Empty class, only exists so that lowRamWithQuickstepIconRecentsDebug compiles. */
+public class ShelfPeekAnim {
+ public ShelfPeekAnim(Launcher launcher) {
+ }
+
+ public enum ShelfAnimState {
+ }
+}
diff --git a/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java b/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java
index 535c5d8..8bd9dba 100644
--- a/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java
+++ b/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java
@@ -44,6 +44,7 @@
private final PackageManager mPm;
private final ColorExtractor mColorExtractor;
private boolean mDisableColorExtractor;
+ private boolean mBadgeOnLeft = false;
protected final int mFillResIconDpi;
protected final int mIconBitmapSize;
@@ -77,6 +78,7 @@
protected void clear() {
mWrapperBackgroundColor = DEFAULT_WRAPPER_BACKGROUND;
mDisableColorExtractor = false;
+ mBadgeOnLeft = false;
}
public ShadowGenerator getShadowGenerator() {
@@ -201,6 +203,13 @@
}
/**
+ * Switches badging to left/right
+ */
+ public void setBadgeOnLeft(boolean badgeOnLeft) {
+ mBadgeOnLeft = badgeOnLeft;
+ }
+
+ /**
* Sets the background color used for wrapped adaptive icon
*/
public void setWrapperBackgroundColor(int color) {
@@ -261,8 +270,12 @@
*/
public void badgeWithDrawable(Canvas target, Drawable badge) {
int badgeSize = getBadgeSizeForIconSize(mIconBitmapSize);
- badge.setBounds(mIconBitmapSize - badgeSize, mIconBitmapSize - badgeSize,
- mIconBitmapSize, mIconBitmapSize);
+ if (mBadgeOnLeft) {
+ badge.setBounds(0, mIconBitmapSize - badgeSize, badgeSize, mIconBitmapSize);
+ } else {
+ badge.setBounds(mIconBitmapSize - badgeSize, mIconBitmapSize - badgeSize,
+ mIconBitmapSize, mIconBitmapSize);
+ }
badge.draw(target);
}
diff --git a/quickstep/recents_ui_overrides/res/drawable/predicted_icon_background.xml b/quickstep/recents_ui_overrides/res/drawable/predicted_icon_background.xml
new file mode 100644
index 0000000..cfc6d48
--- /dev/null
+++ b/quickstep/recents_ui_overrides/res/drawable/predicted_icon_background.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+ android:inset="@dimen/predicted_icon_background_inset">
+ <shape>
+ <solid android:color="?attr/folderFillColor" />
+ <corners android:radius="@dimen/predicted_icon_background_corner_radius" />
+ </shape>
+</inset>
diff --git a/quickstep/recents_ui_overrides/res/values/dimens.xml b/quickstep/recents_ui_overrides/res/values/dimens.xml
index 863a8ba..ee672d4 100644
--- a/quickstep/recents_ui_overrides/res/values/dimens.xml
+++ b/quickstep/recents_ui_overrides/res/values/dimens.xml
@@ -28,4 +28,9 @@
<dimen name="swipe_up_fling_min_visible_change">18dp</dimen>
<dimen name="swipe_up_y_overshoot">10dp</dimen>
<dimen name="swipe_up_max_workspace_trans_y">-60dp</dimen>
+
+ <!-- Predicted icon related -->
+ <dimen name="predicted_icon_background_corner_radius">15dp</dimen>
+ <dimen name="predicted_icon_background_inset">8dp</dimen>
+
</resources>
\ No newline at end of file
diff --git a/quickstep/recents_ui_overrides/res/values/override.xml b/quickstep/recents_ui_overrides/res/values/override.xml
index 1ddd3f5..ed3ba92 100644
--- a/quickstep/recents_ui_overrides/res/values/override.xml
+++ b/quickstep/recents_ui_overrides/res/values/override.xml
@@ -24,5 +24,7 @@
<string name="app_launch_tracker_class" translatable="false">com.android.launcher3.appprediction.PredictionAppTracker</string>
<string name="main_process_initializer_class" translatable="false">com.android.quickstep.QuickstepProcessInitializer</string>
+
+ <string name="user_event_dispatcher_class" translatable="false">com.android.quickstep.logging.UserEventDispatcherAppPredictionExtension</string>
</resources>
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/HotseatPredictionController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/HotseatPredictionController.java
index 32846dc..fe9fd60 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/HotseatPredictionController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/HotseatPredictionController.java
@@ -23,7 +23,10 @@
import android.app.prediction.AppPredictionManager;
import android.app.prediction.AppPredictor;
import android.app.prediction.AppTarget;
+import android.app.prediction.AppTargetEvent;
+import android.app.prediction.AppTargetId;
import android.content.ComponentName;
+import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
@@ -60,9 +63,12 @@
private static final String TAG = "PredictiveHotseat";
private static final boolean DEBUG = false;
+ //TODO: replace this with AppTargetEvent.ACTION_UNPIN (b/144119543)
+ private static final int APPTARGET_ACTION_UNPIN = 4;
+
private static final String PREDICTION_CLIENT = "hotseat";
- private boolean mDragStarted = false;
+ private DropTarget.DragObject mDragObject;
private int mHotSeatItemsCount;
private Launcher mLauncher;
@@ -84,7 +90,6 @@
mHotSeatItemsCount = mLauncher.getDeviceProfile().inv.numHotseatIcons;
launcher.getDeviceProfile().inv.addOnChangeListener(this);
mHotseat.addOnAttachStateChangeListener(this);
- createPredictor();
}
@Override
@@ -101,7 +106,7 @@
* Fills gaps in the hotseat with predictions
*/
public void fillGapsWithPrediction(boolean animate) {
- if (mDragStarted) {
+ if (mDragObject != null) {
return;
}
List<WorkspaceItemInfo> predictedApps = mapToWorkspaceItemInfo(mComponentKeyMappers);
@@ -139,6 +144,7 @@
PopupContainerWithArrow.showForIcon((BubbleTextView) v);
return true;
});
+ icon.setBackgroundResource(R.drawable.predicted_icon_background);
}
}
@@ -154,7 +160,10 @@
}
}
- private void createPredictor() {
+ /**
+ * Creates App Predictor with all the current apps pinned on the hotseat
+ */
+ public void createPredictor() {
AppPredictionManager apm = mLauncher.getSystemService(AppPredictionManager.class);
if (apm == null) {
return;
@@ -166,12 +175,28 @@
new AppPredictionContext.Builder(mLauncher)
.setUiSurface(PREDICTION_CLIENT)
.setPredictedTargetCount(mHotSeatItemsCount)
+ .setExtras(getAppPredictionContextExtra())
.build());
mAppPredictor.registerPredictionUpdates(mLauncher.getMainExecutor(),
this::setPredictedApps);
mAppPredictor.requestPredictionUpdate();
}
+ private Bundle getAppPredictionContextExtra() {
+ Bundle bundle = new Bundle();
+ ViewGroup vg = mHotseat.getShortcutsAndWidgets();
+ ArrayList<AppTarget> pinnedApps = new ArrayList<>();
+ for (int i = 0; i < vg.getChildCount(); i++) {
+ View child = vg.getChildAt(i);
+ if (isPinnedIcon(child)) {
+ WorkspaceItemInfo itemInfo = (WorkspaceItemInfo) child.getTag();
+ pinnedApps.add(getAppTargetFromItemInfo(itemInfo));
+ }
+ }
+ bundle.putParcelableArrayList("pinned_apps", pinnedApps);
+ return bundle;
+ }
+
private void setPredictedApps(List<AppTarget> appTargets) {
mComponentKeyMappers.clear();
for (AppTarget appTarget : appTargets) {
@@ -205,8 +230,11 @@
LauncherSettings.Favorites.CONTAINER_HOTSEAT, workspaceItemInfo.screenId,
workspaceItemInfo.cellX, workspaceItemInfo.cellY);
ObjectAnimator.ofFloat(icon, SCALE_PROPERTY, 1, 0.8f, 1).start();
+ icon.reset();
icon.applyFromWorkspaceItem(workspaceItemInfo);
icon.setOnLongClickListener(ItemLongClickListener.INSTANCE_WORKSPACE);
+ AppTarget appTarget = getAppTargetFromItemInfo(workspaceItemInfo);
+ notifyItemAction(appTarget, AppTargetEvent.ACTION_PIN);
}
private List<WorkspaceItemInfo> mapToWorkspaceItemInfo(
@@ -268,18 +296,32 @@
}
}
+ private void notifyItemAction(AppTarget target, int action) {
+ if (mAppPredictor != null) {
+ mAppPredictor.notifyAppTargetEvent(new AppTargetEvent.Builder(target, action).build());
+ }
+ }
+
@Override
public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) {
removePredictedApps(true);
- mDragStarted = true;
+ mDragObject = dragObject;
}
@Override
public void onDragEnd() {
- if (!mDragStarted) {
+ if (mDragObject == null) {
return;
}
- mDragStarted = false;
+ ItemInfo dragInfo = mDragObject.dragInfo;
+ if (dragInfo instanceof WorkspaceItemInfo && dragInfo.getTargetComponent() != null) {
+ if (isInHotseat(dragInfo) && !isInHotseat(mDragObject.originalDragInfo)) {
+ notifyItemAction(getAppTargetFromItemInfo(dragInfo), AppTargetEvent.ACTION_PIN);
+ } else if (!isInHotseat(dragInfo) && isInHotseat(mDragObject.originalDragInfo)) {
+ notifyItemAction(getAppTargetFromItemInfo(dragInfo), APPTARGET_ACTION_UNPIN);
+ }
+ }
+ mDragObject = null;
fillGapsWithPrediction(true);
}
@@ -337,4 +379,26 @@
&& ((WorkspaceItemInfo) view.getTag()).container
== LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
}
+
+ private static boolean isPinnedIcon(View view) {
+ if (!(view instanceof BubbleTextView && view.getTag() instanceof WorkspaceItemInfo)) {
+ return false;
+ }
+ ItemInfo info = (ItemInfo) view.getTag();
+ return info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT && (
+ info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
+ || info.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT);
+ }
+
+ private static boolean isInHotseat(ItemInfo itemInfo) {
+ return itemInfo.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT;
+ }
+
+ private static AppTarget getAppTargetFromItemInfo(ItemInfo info) {
+ if (info.getTargetComponent() == null) return null;
+ return new AppTarget.Builder(
+ new AppTargetId("app:" + info.getTargetComponent().getPackageName()),
+ info.getTargetComponent().getPackageName(), info.user).setClassName(
+ info.getTargetComponent().getClassName()).build();
+ }
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
index d842484..6946508 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
@@ -17,7 +17,10 @@
package com.android.launcher3;
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
+import static com.android.launcher3.LauncherState.BACKGROUND_APP;
+import static com.android.launcher3.LauncherState.HOTSEAT_ICONS;
import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.anim.Interpolators.AGGRESSIVE_EASE;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.quickstep.TaskViewUtils.findTaskViewToLaunch;
@@ -27,12 +30,15 @@
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
import android.content.Context;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.launcher3.LauncherState.ScaleAndTranslation;
+import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.anim.SpringAnimationBuilder;
@@ -145,8 +151,37 @@
@Override
public Animator createStateElementAnimation(int index, float... values) {
switch (index) {
- case INDEX_SHELF_ANIM:
- return mLauncher.getAllAppsController().createSpringAnimation(values);
+ case INDEX_SHELF_ANIM: {
+ AllAppsTransitionController aatc = mLauncher.getAllAppsController();
+ Animator springAnim = aatc.createSpringAnimation(values);
+
+ if ((OVERVIEW.getVisibleElements(mLauncher) & HOTSEAT_ICONS) != 0) {
+ // Translate hotseat with the shelf until reaching overview.
+ float overviewProgress = OVERVIEW.getVerticalProgress(mLauncher);
+ ScaleAndTranslation sat = OVERVIEW.getHotseatScaleAndTranslation(mLauncher);
+ float shiftRange = aatc.getShiftRange();
+ if (values.length == 1) {
+ values = new float[] {aatc.getProgress(), values[0]};
+ }
+ ValueAnimator hotseatAnim = ValueAnimator.ofFloat(values);
+ hotseatAnim.addUpdateListener(anim -> {
+ float progress = (Float) anim.getAnimatedValue();
+ if (progress >= overviewProgress || mLauncher.isInState(BACKGROUND_APP)) {
+ float hotseatShift = (progress - overviewProgress) * shiftRange;
+ mLauncher.getHotseat().setTranslationY(hotseatShift + sat.translationY);
+ }
+ });
+ hotseatAnim.setInterpolator(LINEAR);
+ hotseatAnim.setDuration(springAnim.getDuration());
+
+ AnimatorSet anim = new AnimatorSet();
+ anim.play(hotseatAnim);
+ anim.play(springAnim);
+ return anim;
+ }
+
+ return springAnim;
+ }
case INDEX_RECENTS_FADE_ANIM:
return ObjectAnimator.ofFloat(mLauncher.getOverviewPanel(),
RecentsView.CONTENT_ALPHA, values);
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionUiStateManager.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionUiStateManager.java
index 8338c2e..f9ee701 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionUiStateManager.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionUiStateManager.java
@@ -24,11 +24,15 @@
import android.content.ComponentName;
import android.content.Context;
+import androidx.annotation.NonNull;
+
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.InvariantDeviceProfile.OnIDPChangeListener;
+import com.android.launcher3.ItemInfo;
import com.android.launcher3.ItemInfoWithIcon;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherSettings;
import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherStateManager.StateListener;
import com.android.launcher3.Utilities;
@@ -36,12 +40,14 @@
import com.android.launcher3.allapps.AllAppsStore.OnUpdateListener;
import com.android.launcher3.icons.IconCache.ItemInfoUpdateReceiver;
import com.android.launcher3.shortcuts.ShortcutKey;
+import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.MainThreadInitializedObject;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.stream.IntStream;
/**
* Handler responsible to updating the UI due to predicted apps changes. Operations:
@@ -294,6 +300,30 @@
return mCurrentState;
}
+ /**
+ * Fill in predicted_rank field based on app prediction.
+ * Only applicable when {@link ItemInfo#itemType} is one of the followings:
+ * {@link LauncherSettings.Favorites#ITEM_TYPE_APPLICATION},
+ * {@link LauncherSettings.Favorites#ITEM_TYPE_SHORTCUT},
+ * {@link LauncherSettings.Favorites#ITEM_TYPE_DEEP_SHORTCUT}
+ */
+ public static void fillInPredictedRank(
+ @NonNull ItemInfo itemInfo, @NonNull LauncherLogProto.Target target) {
+ final PredictionUiStateManager manager = PredictionUiStateManager.INSTANCE.getNoCreate();
+ if (manager == null || itemInfo.getTargetComponent() == null || itemInfo.user == null
+ || (itemInfo.itemType != LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
+ && itemInfo.itemType != LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT
+ && itemInfo.itemType != LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT)) {
+ return;
+ }
+ final ComponentKey k = new ComponentKey(itemInfo.getTargetComponent(), itemInfo.user);
+ final List<ComponentKeyMapper> predictedApps = manager.getCurrentState().apps;
+ IntStream.range(0, predictedApps.size())
+ .filter((i) -> k.equals(predictedApps.get(i).getComponentKey()))
+ .findFirst()
+ .ifPresent((rank) -> target.predictedRank = rank);
+ }
+
public static class PredictionState {
public boolean isEnabled;
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index eefb7dc..9144d5d 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -195,7 +195,7 @@
public void finishBindingItems(int pageBoundFirst) {
super.finishBindingItems(pageBoundFirst);
if (mHotseatPredictionController != null) {
- mHotseatPredictionController.fillGapsWithPrediction(false);
+ mHotseatPredictionController.createPredictor();
}
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
index e4e60a0..bb66ae1 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
@@ -69,7 +69,7 @@
return super.getOverviewScaleAndTranslation(launcher);
}
TaskView dummyTask;
- if (recentsView.getCurrentPage() >= 0) {
+ if (recentsView.getCurrentPage() >= recentsView.getTaskViewStartIndex()) {
if (recentsView.getCurrentPage() <= taskCount - 1) {
dummyTask = recentsView.getCurrentPageTaskView();
} else {
@@ -98,7 +98,7 @@
if ((getVisibleElements(launcher) & HOTSEAT_ICONS) != 0) {
// Translate hotseat offscreen if we show it in overview.
ScaleAndTranslation scaleAndTranslation = super.getHotseatScaleAndTranslation(launcher);
- scaleAndTranslation.translationY = LayoutUtils.getShelfTrackingDistance(launcher,
+ scaleAndTranslation.translationY += LayoutUtils.getShelfTrackingDistance(launcher,
launcher.getDeviceProfile());
return scaleAndTranslation;
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java
index 93d4de1..25eaab1 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java
@@ -32,7 +32,6 @@
import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
import static com.android.launcher3.states.RotationHelper.REQUEST_ROTATE;
-import android.content.Context;
import android.graphics.Rect;
import android.view.View;
@@ -47,6 +46,7 @@
import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.quickstep.SysUINavigationMode;
+import com.android.quickstep.util.LayoutUtils;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
@@ -91,8 +91,19 @@
@Override
public ScaleAndTranslation getHotseatScaleAndTranslation(Launcher launcher) {
if ((getVisibleElements(launcher) & HOTSEAT_ICONS) != 0) {
- // If the hotseat icons are visible in overview, keep them in their normal position.
- return super.getWorkspaceScaleAndTranslation(launcher);
+ DeviceProfile dp = launcher.getDeviceProfile();
+ if (dp.allAppsIconSizePx >= dp.iconSizePx) {
+ return new ScaleAndTranslation(1, 0, 0);
+ } else {
+ float scale = ((float) dp.allAppsIconSizePx) / dp.iconSizePx;
+ // Distance between the screen center (which is the pivotY for hotseat) and the
+ // bottom of the hotseat (which we want to preserve)
+ float distanceFromBottom = dp.heightPx / 2 - dp.hotseatBarBottomPaddingPx;
+ // On scaling, the bottom edge is moved closer to the pivotY. We move the
+ // hotseat back down so that the bottom edge's position is preserved.
+ float translationY = distanceFromBottom * (1 - scale);
+ return new ScaleAndTranslation(scale, 0, translationY);
+ }
}
return getWorkspaceScaleAndTranslation(launcher);
}
@@ -160,15 +171,7 @@
}
public static float getDefaultSwipeHeight(Launcher launcher) {
- return getDefaultSwipeHeight(launcher, launcher.getDeviceProfile());
- }
-
- public static float getDefaultSwipeHeight(Context context, DeviceProfile dp) {
- float swipeHeight = dp.allAppsCellHeightPx - dp.allAppsIconTextSizePx;
- if (SysUINavigationMode.getMode(context) == SysUINavigationMode.Mode.NO_BUTTON) {
- swipeHeight -= dp.getInsets().bottom;
- }
- return swipeHeight;
+ return LayoutUtils.getDefaultSwipeHeight(launcher, launcher.getDeviceProfile());
}
@Override
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java
index 4f50e33..b14da5c 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java
@@ -48,12 +48,12 @@
import com.android.launcher3.util.VibratorWrapper;
import com.android.launcher3.views.FloatingIconView;
import com.android.quickstep.BaseActivityInterface.HomeAnimationFactory;
+import com.android.quickstep.RecentsAnimationCallbacks.RecentsAnimationListener;
import com.android.quickstep.util.ActiveGestureLog;
import com.android.quickstep.util.ActivityInitListener;
import com.android.quickstep.util.AppWindowAnimationHelper;
import com.android.quickstep.util.AppWindowAnimationHelper.TransformParams;
import com.android.quickstep.util.RectFSpringAnim;
-import com.android.quickstep.RecentsAnimationCallbacks.RecentsAnimationListener;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -285,12 +285,18 @@
public void onRecentsAnimationCanceled(ThumbnailData thumbnailData) {
mRecentsAnimationController = null;
mRecentsAnimationTargets = null;
+ if (mRecentsView != null) {
+ mRecentsView.setRecentsAnimationTargets(null, null);
+ }
}
@Override
public void onRecentsAnimationFinished(RecentsAnimationController controller) {
mRecentsAnimationController = null;
mRecentsAnimationTargets = null;
+ if (mRecentsView != null) {
+ mRecentsView.setRecentsAnimationTargets(null, null);
+ }
}
private Rect getStackBounds(DeviceProfile dp) {
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackSwipeHandler.java
index 24f247b..c939de8 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackSwipeHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackSwipeHandler.java
@@ -19,10 +19,10 @@
import static com.android.quickstep.GestureState.GestureEndTarget.LAST_TASK;
import static com.android.quickstep.GestureState.GestureEndTarget.NEW_TASK;
import static com.android.quickstep.GestureState.GestureEndTarget.RECENTS;
+import static com.android.quickstep.LauncherSwipeHandler.MIN_PROGRESS_FOR_OVERVIEW;
import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
import static com.android.quickstep.RecentsActivity.EXTRA_TASK_ID;
import static com.android.quickstep.RecentsActivity.EXTRA_THUMBNAIL;
-import static com.android.quickstep.LauncherSwipeHandler.MIN_PROGRESS_FOR_OVERVIEW;
import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD;
import android.animation.Animator;
@@ -33,8 +33,8 @@
import android.graphics.PointF;
import android.graphics.RectF;
import android.os.Bundle;
-
import android.util.ArrayMap;
+
import com.android.launcher3.R;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
@@ -428,7 +428,6 @@
@Override
public void onRecentsAnimationCanceled(ThumbnailData thumbnailData) {
super.onRecentsAnimationCanceled(thumbnailData);
- mRecentsView.setRecentsAnimationTargets(null, null);
mStateCallback.setStateOnUiThread(STATE_HANDLER_INVALIDATED);
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java
index 01cf4bb..844152b 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java
@@ -47,6 +47,7 @@
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
+import com.android.launcher3.BaseQuickstepLauncher;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherInitListener;
@@ -56,12 +57,13 @@
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.appprediction.PredictionUiStateManager;
-import com.android.launcher3.uioverrides.states.OverviewState;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.views.FloatingIconView;
import com.android.quickstep.SysUINavigationMode.Mode;
import com.android.quickstep.util.ActivityInitListener;
import com.android.quickstep.util.LayoutUtils;
+import com.android.quickstep.util.ShelfPeekAnim;
+import com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState;
import com.android.quickstep.util.StaggeredWorkspaceAnim;
import com.android.quickstep.views.LauncherRecentsView;
import com.android.quickstep.views.RecentsView;
@@ -211,7 +213,7 @@
@Override
public AnimationFactory prepareRecentsUI(boolean activityVisible,
boolean animateActivity, Consumer<AnimatorPlaybackController> callback) {
- Launcher launcher = getCreatedActivity();
+ BaseQuickstepLauncher launcher = getCreatedActivity();
final LauncherState startState = launcher.getStateManager().getState();
LauncherState resetState = startState;
@@ -227,7 +229,7 @@
launcher.getAppsView().reset(false /* animate */);
return new AnimationFactory() {
- private ShelfAnimState mShelfState;
+ private final ShelfPeekAnim mShelfAnim = launcher.getShelfPeekAnim();
private boolean mIsAttachedToWindow;
@Override
@@ -256,30 +258,7 @@
@Override
public void setShelfState(ShelfAnimState shelfState, Interpolator interpolator,
long duration) {
- if (mShelfState == shelfState) {
- return;
- }
- mShelfState = shelfState;
- launcher.getStateManager().cancelStateElementAnimation(INDEX_SHELF_ANIM);
- if (mShelfState == ShelfAnimState.CANCEL) {
- return;
- }
- float shelfHiddenProgress = BACKGROUND_APP.getVerticalProgress(launcher);
- float shelfOverviewProgress = OVERVIEW.getVerticalProgress(launcher);
- // Peek based on default overview progress so we can see hotseat if we're showing
- // that instead of predictions in overview.
- float defaultOverviewProgress = OverviewState.getDefaultVerticalProgress(launcher);
- float shelfPeekingProgress = shelfHiddenProgress
- - (shelfHiddenProgress - defaultOverviewProgress) * 0.25f;
- float toProgress = mShelfState == ShelfAnimState.HIDE
- ? shelfHiddenProgress
- : mShelfState == ShelfAnimState.PEEK
- ? shelfPeekingProgress
- : shelfOverviewProgress;
- Animator shelfAnim = launcher.getStateManager()
- .createStateElementAnimation(INDEX_SHELF_ANIM, toProgress);
- shelfAnim.setInterpolator(interpolator);
- shelfAnim.setDuration(duration).start();
+ mShelfAnim.setShelfState(shelfState, interpolator, duration);
}
@Override
@@ -420,8 +399,8 @@
@Nullable
@Override
- public Launcher getCreatedActivity() {
- return Launcher.ACTIVITY_TRACKER.getCreatedActivity();
+ public BaseQuickstepLauncher getCreatedActivity() {
+ return BaseQuickstepLauncher.ACTIVITY_TRACKER.getCreatedActivity();
}
@Nullable
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandler.java
index 3eb183e..05cec2d 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandler.java
@@ -24,8 +24,6 @@
import static com.android.launcher3.config.FeatureFlags.QUICKSTEP_SPRINGS;
import static com.android.launcher3.util.DefaultDisplay.getSingleFrameMs;
import static com.android.launcher3.util.SystemUiController.UI_STATE_OVERVIEW;
-import static com.android.quickstep.BaseActivityInterface.AnimationFactory.ShelfAnimState.HIDE;
-import static com.android.quickstep.BaseActivityInterface.AnimationFactory.ShelfAnimState.PEEK;
import static com.android.quickstep.GestureState.GestureEndTarget.HOME;
import static com.android.quickstep.GestureState.GestureEndTarget.LAST_TASK;
import static com.android.quickstep.GestureState.GestureEndTarget.NEW_TASK;
@@ -33,6 +31,8 @@
import static com.android.quickstep.GestureState.STATE_END_TARGET_ANIMATION_FINISHED;
import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
import static com.android.quickstep.SysUINavigationMode.Mode.TWO_BUTTONS;
+import static com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState.HIDE;
+import static com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState.PEEK;
import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD;
import android.animation.Animator;
@@ -69,13 +69,15 @@
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.launcher3.util.TraceHelper;
import com.android.quickstep.BaseActivityInterface.AnimationFactory;
-import com.android.quickstep.BaseActivityInterface.AnimationFactory.ShelfAnimState;
import com.android.quickstep.BaseActivityInterface.HomeAnimationFactory;
import com.android.quickstep.GestureState.GestureEndTarget;
import com.android.quickstep.inputconsumers.OverviewInputConsumer;
import com.android.quickstep.util.ActiveGestureLog;
import com.android.quickstep.util.AppWindowAnimationHelper.TargetAlphaProvider;
import com.android.quickstep.util.RectFSpringAnim;
+import com.android.quickstep.util.SharedApiCompat;
+import com.android.quickstep.util.ShelfPeekAnim;
+import com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState;
import com.android.quickstep.views.LiveTileOverlay;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
@@ -151,7 +153,6 @@
Math.min(1 / MIN_PROGRESS_FOR_OVERVIEW, 1 / (1 - MIN_PROGRESS_FOR_OVERVIEW));
private static final String SCREENSHOT_CAPTURED_EVT = "ScreenshotCaptured";
- private static final long SHELF_ANIM_DURATION = 240;
public static final long RECENTS_ATTACH_DURATION = 300;
/**
@@ -176,8 +177,6 @@
private boolean mHasLauncherTransitionControllerStarted;
private AnimationFactory mAnimationFactory = (t) -> { };
- private LiveTileOverlay mLiveTileOverlay = new LiveTileOverlay();
- private boolean mLiveTileOverlayAttached = false;
private boolean mWasLauncherAlreadyVisible;
@@ -432,7 +431,7 @@
@Override
public void onMotionPauseChanged(boolean isPaused) {
- setShelfState(isPaused ? PEEK : HIDE, OVERSHOOT_1_2, SHELF_ANIM_DURATION);
+ setShelfState(isPaused ? PEEK : HIDE, ShelfPeekAnim.INTERPOLATOR, ShelfPeekAnim.DURATION);
if (mDeviceState.isFullyGesturalNavMode() && isPaused) {
// In fully gestural nav mode, switch to overview predictions once the user has paused
@@ -547,7 +546,8 @@
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
if (mRecentsAnimationTargets != null) {
- mLiveTileOverlay.update(mAppWindowAnimationHelper.getCurrentRectWithInsets(),
+ LiveTileOverlay.getInstance().update(
+ mAppWindowAnimationHelper.getCurrentRectWithInsets(),
mAppWindowAnimationHelper.getCurrentCornerRadius());
}
}
@@ -615,7 +615,6 @@
@Override
public void onRecentsAnimationCanceled(ThumbnailData thumbnailData) {
super.onRecentsAnimationCanceled(thumbnailData);
- mRecentsView.setRecentsAnimationTargets(null, null);
mActivityInitListener.unregister();
mStateCallback.setStateOnUiThread(STATE_GESTURE_CANCELLED | STATE_HANDLER_INVALIDATED);
ActiveGestureLog.INSTANCE.addLog("cancelRecentsAnimation");
@@ -835,7 +834,7 @@
setShelfState(ShelfAnimState.CANCEL, LINEAR, 0);
duration = Math.max(MIN_OVERSHOOT_DURATION, duration);
} else if (endTarget == RECENTS) {
- mLiveTileOverlay.startIconAnimation();
+ LiveTileOverlay.getInstance().startIconAnimation();
if (mRecentsView != null) {
int nearestPage = mRecentsView.getPageNearestToCenterOfScreen();
if (mRecentsView.getNextPage() != nearestPage) {
@@ -1022,6 +1021,7 @@
// In the off chance that the gesture ends before Launcher is started, we should clear
// the callback here so that it doesn't update with the wrong state
mActivity.clearRunOnceOnStartCallback();
+ resetLauncherListenersAndOverlays();
}
if (mGestureState.getEndTarget() != null && !mGestureState.isRunningAnimationToLauncher()) {
cancelCurrentAnimation();
@@ -1109,13 +1109,7 @@
endLauncherTransitionController();
mRecentsView.onGestureAnimationEnd();
-
- // Reset the callback for deferred activity launches
- if (!ENABLE_QUICKSTEP_LIVE_TILE.get()) {
- mActivityInterface.setOnDeferredActivityLaunchCallback(null);
- }
- mActivity.getRootView().setOnApplyWindowInsetsListener(null);
- removeLiveTileOverlay();
+ resetLauncherListenersAndOverlays();
}
private void endLauncherTransitionController() {
@@ -1126,6 +1120,15 @@
}
}
+ private void resetLauncherListenersAndOverlays() {
+ // Reset the callback for deferred activity launches
+ if (!ENABLE_QUICKSTEP_LIVE_TILE.get()) {
+ mActivityInterface.setOnDeferredActivityLaunchCallback(null);
+ }
+ mActivity.getRootView().setOnApplyWindowInsetsListener(null);
+ removeLiveTileOverlay();
+ }
+
private void notifyTransitionCancelled() {
mAnimationFactory.onTransitionCancelled();
}
@@ -1142,6 +1145,8 @@
final int runningTaskId = mGestureState.getRunningTaskId();
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
if (mRecentsAnimationController != null) {
+ SharedApiCompat.setWillFinishToHome(mRecentsAnimationController.getController(),
+ true /* willFinishToHome */);
// Update the screenshot of the task
if (mTaskSnapshot == null) {
mTaskSnapshot = mRecentsAnimationController.screenshotTask(runningTaskId);
@@ -1230,20 +1235,15 @@
updateFinalShift();
}
- private synchronized void addLiveTileOverlay() {
- if (!mLiveTileOverlayAttached) {
- mActivity.getRootView().getOverlay().add(mLiveTileOverlay);
- mRecentsView.setLiveTileOverlay(mLiveTileOverlay);
- mLiveTileOverlayAttached = true;
+ private void addLiveTileOverlay() {
+ if (LiveTileOverlay.getInstance().attach(mActivity.getRootView().getOverlay())) {
+ mRecentsView.setLiveTileOverlayAttached(true);
}
}
- private synchronized void removeLiveTileOverlay() {
- if (mLiveTileOverlayAttached) {
- mActivity.getRootView().getOverlay().remove(mLiveTileOverlay);
- mRecentsView.setLiveTileOverlay(null);
- mLiveTileOverlayAttached = false;
- }
+ private void removeLiveTileOverlay() {
+ LiveTileOverlay.getInstance().detach(mActivity.getRootView().getOverlay());
+ mRecentsView.setLiveTileOverlayAttached(false);
}
public static float getHiddenTargetAlpha(RemoteAnimationTargetCompat app, float expectedAlpha) {
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java
index 19c289d..92c55da 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java
@@ -10,7 +10,6 @@
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.testing.TestInformationHandler;
import com.android.launcher3.testing.TestProtocol;
-import com.android.launcher3.uioverrides.states.OverviewState;
import com.android.launcher3.uioverrides.touchcontrollers.PortraitStatesTouchController;
import com.android.quickstep.util.LayoutUtils;
import com.android.quickstep.views.RecentsView;
@@ -34,7 +33,7 @@
switch (method) {
case TestProtocol.REQUEST_HOME_TO_OVERVIEW_SWIPE_HEIGHT: {
final float swipeHeight =
- OverviewState.getDefaultSwipeHeight(mContext, mDeviceProfile);
+ LayoutUtils.getDefaultSwipeHeight(mContext, mDeviceProfile);
response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, (int) swipeHeight);
return response;
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsActivity.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsActivity.java
index 7b8ec4d..e0e20ee 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsActivity.java
@@ -89,9 +89,13 @@
int taskID = intent.getIntExtra(EXTRA_TASK_ID, 0);
IBinder thumbnail = intent.getExtras().getBinder(EXTRA_THUMBNAIL);
if (taskID != 0 && thumbnail instanceof ObjectWrapper) {
- ThumbnailData thumbnailData = ((ObjectWrapper<ThumbnailData>) thumbnail).get();
+ ObjectWrapper<ThumbnailData> obj = (ObjectWrapper<ThumbnailData>) thumbnail;
+ ThumbnailData thumbnailData = obj.get();
mFallbackRecentsView.showCurrentTask(taskID);
mFallbackRecentsView.updateThumbnail(taskID, thumbnailData);
+ // Clear the ref since any reference to the extras on the system side will still
+ // hold a reference to the wrapper
+ obj.clear();
}
}
intent.removeExtra(EXTRA_TASK_ID);
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskViewUtils.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskViewUtils.java
index 2522c0f..bfe5738 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskViewUtils.java
@@ -172,8 +172,11 @@
AppWindowAnimationHelper.TransformParams liveTileParams =
v.getRecentsView().getLiveTileParams(true /* mightNeedToRefill */);
if (liveTileParams != null) {
- Collections.addAll(surfaceParamsList,
- liveTileAnimationHelper.getSurfaceParams(liveTileParams));
+ SurfaceParams[] liveTileSurfaceParams =
+ liveTileAnimationHelper.getSurfaceParams(liveTileParams);
+ if (liveTileSurfaceParams != null) {
+ Collections.addAll(surfaceParamsList, liveTileSurfaceParams);
+ }
}
}
// Apply surface transform using the surface params list.
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/logging/UserEventDispatcherAppPredictionExtension.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/logging/UserEventDispatcherAppPredictionExtension.java
new file mode 100644
index 0000000..b251f9e
--- /dev/null
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/logging/UserEventDispatcherAppPredictionExtension.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.logging;
+
+import android.content.Context;
+
+import androidx.annotation.NonNull;
+
+import com.android.launcher3.ItemInfo;
+import com.android.launcher3.appprediction.PredictionUiStateManager;
+import com.android.launcher3.userevent.nano.LauncherLogProto;
+
+/**
+ * This class handles AOSP MetricsLogger function calls and logging around
+ * quickstep interactions and app launches.
+ */
+@SuppressWarnings("unused")
+public class UserEventDispatcherAppPredictionExtension extends UserEventDispatcherExtension {
+
+ public static final int ALL_APPS_PREDICTION_TIPS = 2;
+
+ private static final String TAG = "UserEventDispatcher";
+
+ public UserEventDispatcherAppPredictionExtension(Context context) {
+ super(context);
+ }
+
+ @Override
+ protected void onFillInLogContainerData(
+ @NonNull ItemInfo itemInfo, @NonNull LauncherLogProto.Target target,
+ @NonNull LauncherLogProto.Target targetParent) {
+ PredictionUiStateManager.fillInPredictedRank(itemInfo, target);
+ }
+}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/ShelfPeekAnim.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/ShelfPeekAnim.java
new file mode 100644
index 0000000..41be683
--- /dev/null
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/ShelfPeekAnim.java
@@ -0,0 +1,104 @@
+/*
+ * 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.quickstep.util;
+
+import static com.android.launcher3.LauncherAppTransitionManagerImpl.INDEX_SHELF_ANIM;
+import static com.android.launcher3.LauncherState.BACKGROUND_APP;
+import static com.android.launcher3.LauncherState.OVERVIEW;
+import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.view.animation.Interpolator;
+
+import com.android.launcher3.Launcher;
+import com.android.launcher3.uioverrides.states.OverviewState;
+
+/**
+ * Animates the shelf between states HIDE, PEEK, and OVERVIEW.
+ */
+public class ShelfPeekAnim {
+
+ public static final Interpolator INTERPOLATOR = OVERSHOOT_1_2;
+ public static final long DURATION = 240;
+
+ private final Launcher mLauncher;
+
+ private ShelfAnimState mShelfState;
+ private boolean mIsPeeking;
+
+ public ShelfPeekAnim(Launcher launcher) {
+ mLauncher = launcher;
+ }
+
+ /**
+ * Animates to the given state, canceling the previous animation if it was still running.
+ */
+ public void setShelfState(ShelfAnimState shelfState, Interpolator interpolator, long duration) {
+ if (mShelfState == shelfState) {
+ return;
+ }
+ mLauncher.getStateManager().cancelStateElementAnimation(INDEX_SHELF_ANIM);
+ mShelfState = shelfState;
+ mIsPeeking = mShelfState == ShelfAnimState.PEEK || mShelfState == ShelfAnimState.HIDE;
+ if (mShelfState == ShelfAnimState.CANCEL) {
+ return;
+ }
+ float shelfHiddenProgress = BACKGROUND_APP.getVerticalProgress(mLauncher);
+ float shelfOverviewProgress = OVERVIEW.getVerticalProgress(mLauncher);
+ // Peek based on default overview progress so we can see hotseat if we're showing
+ // that instead of predictions in overview.
+ float defaultOverviewProgress = OverviewState.getDefaultVerticalProgress(mLauncher);
+ float shelfPeekingProgress = shelfHiddenProgress
+ - (shelfHiddenProgress - defaultOverviewProgress) * 0.25f;
+ float toProgress = mShelfState == ShelfAnimState.HIDE
+ ? shelfHiddenProgress
+ : mShelfState == ShelfAnimState.PEEK
+ ? shelfPeekingProgress
+ : shelfOverviewProgress;
+ Animator shelfAnim = mLauncher.getStateManager()
+ .createStateElementAnimation(INDEX_SHELF_ANIM, toProgress);
+ shelfAnim.setInterpolator(interpolator);
+ shelfAnim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mShelfState = ShelfAnimState.CANCEL;
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animator) {
+ mIsPeeking = mShelfState == ShelfAnimState.PEEK;
+ }
+ });
+ shelfAnim.setDuration(duration).start();
+ }
+
+ /** @return Whether the shelf is currently peeking or animating to or from peeking. */
+ public boolean isPeeking() {
+ return mIsPeeking;
+ }
+
+ /** The various shelf states we can animate to. */
+ public enum ShelfAnimState {
+ HIDE(true), PEEK(true), OVERVIEW(false), CANCEL(false);
+
+ ShelfAnimState(boolean shouldPreformHaptic) {
+ this.shouldPreformHaptic = shouldPreformHaptic;
+ }
+
+ public final boolean shouldPreformHaptic;
+ }
+}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java
index ca33605..82fbbc6 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -326,8 +326,8 @@
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
- PluginManagerWrapper.INSTANCE.get(getContext())
- .addPluginListener(mRecentsExtraCardPluginListener, RecentsExtraCard.class);
+ PluginManagerWrapper.INSTANCE.get(getContext()).addPluginListener(
+ mRecentsExtraCardPluginListener, RecentsExtraCard.class);
}
@Override
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LiveTileOverlay.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LiveTileOverlay.java
index a838797..18eda60 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LiveTileOverlay.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LiveTileOverlay.java
@@ -16,6 +16,7 @@
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.util.FloatProperty;
+import android.view.ViewOverlay;
import com.android.launcher3.anim.Interpolators;
@@ -36,6 +37,15 @@
}
};
+ private static LiveTileOverlay sInstance;
+
+ public static LiveTileOverlay getInstance() {
+ if (sInstance == null) {
+ sInstance = new LiveTileOverlay();
+ }
+ return sInstance;
+ }
+
private final Paint mPaint = new Paint();
private Rect mBoundsRect = new Rect();
@@ -46,8 +56,9 @@
private boolean mDrawEnabled = true;
private float mIconAnimationProgress = 0f;
+ private boolean mIsAttached;
- public LiveTileOverlay() {
+ private LiveTileOverlay() {
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
}
@@ -124,6 +135,23 @@
return PixelFormat.TRANSLUCENT;
}
+ public boolean attach(ViewOverlay overlay) {
+ if (overlay != null && !mIsAttached) {
+ overlay.add(this);
+ mIsAttached = true;
+ return true;
+ }
+
+ return false;
+ }
+
+ public void detach(ViewOverlay overlay) {
+ if (overlay != null) {
+ overlay.remove(this);
+ mIsAttached = false;
+ }
+ }
+
private void setIconAnimationProgress(float progress) {
mIconAnimationProgress = progress;
invalidateSelf();
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
index cf616fe..6e7214e 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
@@ -308,7 +308,7 @@
private final int mEmptyMessagePadding;
private boolean mShowEmptyMessage;
private Layout mEmptyTextLayout;
- private LiveTileOverlay mLiveTileOverlay;
+ private boolean mLiveTileOverlayAttached;
// Keeps track of the index where the first TaskView should be
private int mTaskViewStartIndex = 0;
@@ -485,6 +485,11 @@
public void setOverviewStateEnabled(boolean enabled) {
mOverviewStateEnabled = enabled;
updateTaskStackListenerState();
+ if (!enabled) {
+ // Reset the running task when leaving overview since it can still have a reference to
+ // its thumbnail
+ mTmpRunningTask = null;
+ }
}
public void onDigitalWellbeingToastShown() {
@@ -876,8 +881,8 @@
*/
public void onSwipeUpAnimationSuccess() {
if (getRunningTaskView() != null) {
- float startProgress = ENABLE_QUICKSTEP_LIVE_TILE.get() && mLiveTileOverlay != null
- ? mLiveTileOverlay.cancelIconAnimation()
+ float startProgress = ENABLE_QUICKSTEP_LIVE_TILE.get() && mLiveTileOverlayAttached
+ ? LiveTileOverlay.getInstance().cancelIconAnimation()
: 0f;
animateUpRunningTaskIconScale(startProgress);
}
@@ -1724,13 +1729,13 @@
mAppWindowAnimationHelper = appWindowAnimationHelper;
}
- public void setLiveTileOverlay(LiveTileOverlay liveTileOverlay) {
- mLiveTileOverlay = liveTileOverlay;
+ public void setLiveTileOverlayAttached(boolean liveTileOverlayAttached) {
+ mLiveTileOverlayAttached = liveTileOverlayAttached;
}
public void updateLiveTileIcon(Drawable icon) {
- if (mLiveTileOverlay != null) {
- mLiveTileOverlay.setIcon(icon);
+ if (mLiveTileOverlayAttached) {
+ LiveTileOverlay.getInstance().setIcon(icon);
}
}
@@ -1855,8 +1860,8 @@
private void updateEnabledOverlays() {
int overlayEnabledPage = mOverlayEnabled ? getNextPage() : -1;
int taskCount = getTaskViewCount();
- for (int i = 0; i < taskCount; i++) {
- getTaskViewAt(i).setOverlayEnabled(i == overlayEnabledPage);
+ for (int i = mTaskViewStartIndex; i < mTaskViewStartIndex + taskCount; i++) {
+ getTaskViewAtByAbsoluteIndex(i).setOverlayEnabled(i == overlayEnabledPage);
}
}
diff --git a/quickstep/res/values/config.xml b/quickstep/res/values/config.xml
index 5d9a009..327bb14 100644
--- a/quickstep/res/values/config.xml
+++ b/quickstep/res/values/config.xml
@@ -19,8 +19,6 @@
<!-- Activity which blocks home gesture -->
<string name="gesture_blocking_activity" translatable="false"></string>
- <string name="user_event_dispatcher_class" translatable="false">com.android.quickstep.logging.UserEventDispatcherExtension</string>
-
<string name="stats_log_manager_class" translatable="false">com.android.quickstep.logging.StatsLogCompatManager</string>
<string name="test_information_handler_class" translatable="false">com.android.quickstep.QuickstepTestInformationHandler</string>
diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
index fc9cfcd..9ea13c6 100644
--- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
@@ -48,6 +48,7 @@
import com.android.quickstep.SysUINavigationMode.NavigationModeChangeListener;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.util.RemoteFadeOutAnimationListener;
+import com.android.quickstep.util.ShelfPeekAnim;
import java.util.stream.Stream;
@@ -64,6 +65,8 @@
(context, arg1, arg2) -> SystemUiProxy.INSTANCE.get(context).setBackButtonAlpha(
Float.intBitsToFloat(arg1), arg2 != 0);
+ private final ShelfPeekAnim mShelfPeekAnim = new ShelfPeekAnim(this);
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -270,4 +273,8 @@
return Stream.concat(super.getSupportedShortcuts(),
Stream.of(WellbeingModel.SHORTCUT_FACTORY));
}
+
+ public ShelfPeekAnim getShelfPeekAnim() {
+ return mShelfPeekAnim;
+ }
}
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index 86ffd22..fd55e07 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -32,6 +32,7 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.quickstep.util.ActivityInitListener;
+import com.android.quickstep.util.ShelfPeekAnim;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
@@ -113,16 +114,6 @@
interface AnimationFactory {
- enum ShelfAnimState {
- HIDE(true), PEEK(true), OVERVIEW(false), CANCEL(false);
-
- ShelfAnimState(boolean shouldPreformHaptic) {
- this.shouldPreformHaptic = shouldPreformHaptic;
- }
-
- public final boolean shouldPreformHaptic;
- }
-
default void onRemoteAnimationReceived(RemoteAnimationTargets targets) { }
void createActivityInterface(long transitionLength);
@@ -131,8 +122,8 @@
default void onTransitionCancelled() { }
- default void setShelfState(ShelfAnimState animState, Interpolator interpolator,
- long duration) { }
+ default void setShelfState(ShelfPeekAnim.ShelfAnimState animState,
+ Interpolator interpolator, long duration) { }
/**
* @param attached Whether to show RecentsView alongside the app window. If false, recents
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationController.java b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
index 333e179..46af8bf 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationController.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
@@ -18,6 +18,7 @@
import static android.view.MotionEvent.ACTION_CANCEL;
import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_UP;
+
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
@@ -185,6 +186,11 @@
mInputConsumerController.setInputListener(this::onInputConsumerEvent);
}
+ /** @return wrapper controller. */
+ public RecentsAnimationControllerCompat getController() {
+ return mController;
+ }
+
private void disableInputProxy() {
if (mInputConsumer != null && mTouchInProgress) {
long now = SystemClock.uptimeMillis();
diff --git a/quickstep/src/com/android/quickstep/logging/UserEventDispatcherExtension.java b/quickstep/src/com/android/quickstep/logging/UserEventDispatcherExtension.java
index 4a11601..9ca7f23 100644
--- a/quickstep/src/com/android/quickstep/logging/UserEventDispatcherExtension.java
+++ b/quickstep/src/com/android/quickstep/logging/UserEventDispatcherExtension.java
@@ -20,10 +20,10 @@
import static com.android.launcher3.logging.LoggerUtils.newLauncherEvent;
import static com.android.launcher3.userevent.nano.LauncherLogProto.ControlType.CANCEL_TARGET;
-import static com.android.systemui.shared.system.LauncherEventUtil.VISIBLE;
import static com.android.systemui.shared.system.LauncherEventUtil.DISMISS;
import static com.android.systemui.shared.system.LauncherEventUtil.RECENTS_QUICK_SCRUB_ONBOARDING_TIP;
import static com.android.systemui.shared.system.LauncherEventUtil.RECENTS_SWIPE_UP_ONBOARDING_TIP;
+import static com.android.systemui.shared.system.LauncherEventUtil.VISIBLE;
import com.android.launcher3.logging.UserEventDispatcher;
import com.android.launcher3.userevent.nano.LauncherLogProto;
diff --git a/quickstep/src/com/android/quickstep/util/LayoutUtils.java b/quickstep/src/com/android/quickstep/util/LayoutUtils.java
index 050bdff..2e118b4 100644
--- a/quickstep/src/com/android/quickstep/util/LayoutUtils.java
+++ b/quickstep/src/com/android/quickstep/util/LayoutUtils.java
@@ -26,7 +26,7 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
-import com.android.launcher3.config.FeatureFlags;
+import com.android.quickstep.SysUINavigationMode;
import java.lang.annotation.Retention;
@@ -39,12 +39,27 @@
@IntDef({MULTI_WINDOW_STRATEGY_HALF_SCREEN, MULTI_WINDOW_STRATEGY_DEVICE_PROFILE})
private @interface MultiWindowStrategy {}
+ /**
+ * The height for the swipe up motion
+ */
+ public static float getDefaultSwipeHeight(Context context, DeviceProfile dp) {
+ float swipeHeight = dp.allAppsCellHeightPx - dp.allAppsIconTextSizePx;
+ if (SysUINavigationMode.getMode(context) == SysUINavigationMode.Mode.NO_BUTTON) {
+ swipeHeight -= dp.getInsets().bottom;
+ }
+ return swipeHeight;
+ }
+
public static void calculateLauncherTaskSize(Context context, DeviceProfile dp, Rect outRect) {
float extraSpace;
if (dp.isVerticalBarLayout()) {
extraSpace = 0;
} else {
- extraSpace = dp.hotseatBarSizePx + dp.verticalDragHandleSizePx;
+ Resources res = context.getResources();
+
+ extraSpace = getDefaultSwipeHeight(context, dp) + dp.verticalDragHandleSizePx
+ + res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_extra_vertical_size)
+ + res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_bottom_padding);
}
calculateTaskSize(context, dp, extraSpace, MULTI_WINDOW_STRATEGY_HALF_SCREEN, outRect);
}
diff --git a/quickstep/src/com/android/quickstep/views/ShelfScrimView.java b/quickstep/src/com/android/quickstep/views/ShelfScrimView.java
index 26e9eaf..0e591ca 100644
--- a/quickstep/src/com/android/quickstep/views/ShelfScrimView.java
+++ b/quickstep/src/com/android/quickstep/views/ShelfScrimView.java
@@ -38,12 +38,12 @@
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.Interpolators;
-import com.android.launcher3.uioverrides.states.OverviewState;
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.ScrimView;
import com.android.quickstep.SysUINavigationMode;
import com.android.quickstep.SysUINavigationMode.Mode;
import com.android.quickstep.SysUINavigationMode.NavigationModeChangeListener;
+import com.android.quickstep.util.LayoutUtils;
/**
* Scrim used for all-apps and shelf in Overview
@@ -163,7 +163,7 @@
int hotseatSize = dp.hotseatBarSizePx + dp.getInsets().bottom
+ hotseatPadding.bottom + hotseatPadding.top;
float dragHandleTop =
- Math.min(hotseatSize, OverviewState.getDefaultSwipeHeight(context, dp));
+ Math.min(hotseatSize, LayoutUtils.getDefaultSwipeHeight(context, dp));
mDragHandleProgress = 1 - (dragHandleTop / mShiftRange);
}
mTopOffset = dp.getInsets().top - mShelfOffset;
diff --git a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
index ca81343..85cffaa 100644
--- a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
+++ b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
@@ -31,9 +31,6 @@
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.rule.ShellCommandRule.disableHeadsUpNotification;
import static com.android.launcher3.util.rule.ShellCommandRule.getLauncherCommand;
-import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_PRESUBMIT;
-import static com.android.launcher3.util.rule.TestStabilityRule.RUN_FLAFOR;
-import static com.android.launcher3.util.rule.TestStabilityRule.UNBUNDLED_PRESUBMIT;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@@ -63,6 +60,7 @@
import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
import com.android.quickstep.views.RecentsView;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.RuleChain;
@@ -132,12 +130,8 @@
@NavigationModeSwitch
@Test
+ @Ignore // b/143488140
public void goToOverviewFromHome() {
- // b/142828227
- if (android.os.Build.MODEL.contains("Cuttlefish") && TestHelpers.isInLauncherProcess() &&
- (RUN_FLAFOR & (PLATFORM_PRESUBMIT | UNBUNDLED_PRESUBMIT)) != 0) {
- return;
- }
mDevice.pressHome();
assertTrue("Fallback Launcher not visible", mDevice.wait(Until.hasObject(By.pkg(
mOtherLauncherActivity.packageName)), WAIT_TIME_MS));
@@ -147,12 +141,8 @@
@NavigationModeSwitch
@Test
+ @Ignore // b/143488140
public void goToOverviewFromApp() {
- // b/142828227
- if (android.os.Build.MODEL.contains("Cuttlefish") && TestHelpers.isInLauncherProcess() &&
- (RUN_FLAFOR & (PLATFORM_PRESUBMIT | UNBUNDLED_PRESUBMIT)) != 0) {
- return;
- }
startAppFastAndWaitForRecentTask(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
mLauncher.getBackground().switchToOverview();
@@ -186,12 +176,8 @@
@NavigationModeSwitch
@Test
+ @Ignore // b/143488140
public void testOverview() {
- // b/142828227
- if (android.os.Build.MODEL.contains("Cuttlefish") && TestHelpers.isInLauncherProcess() &&
- (RUN_FLAFOR & (PLATFORM_PRESUBMIT | UNBUNDLED_PRESUBMIT)) != 0) {
- return;
- }
startAppFastAndWaitForRecentTask(getAppPackageName());
startAppFastAndWaitForRecentTask(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
startTestActivity(2);
diff --git a/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java b/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java
index 50cab74..891bf24 100644
--- a/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java
+++ b/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java
@@ -95,11 +95,6 @@
@Test
@NavigationModeSwitch
public void testStressSwipeToOverview() {
- // b/142828227
- if (android.os.Build.MODEL.contains("Cuttlefish") && TestHelpers.isInLauncherProcess() &&
- (RUN_FLAFOR & (PLATFORM_PRESUBMIT | UNBUNDLED_PRESUBMIT)) != 0) {
- return;
- }
for (int i = 0; i < STRESS_REPEAT_COUNT; ++i) {
// Destroy Launcher activity.
closeLauncherActivity();
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 339aef5..80c791c 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -130,6 +130,10 @@
<item name="widgetsTheme">@style/WidgetContainerTheme</item>
</style>
+ <style name="HomeSettingsTheme" parent="@android:style/Theme.DeviceDefault.Settings">
+ <item name="android:navigationBarColor">@android:color/transparent</item>
+ </style>
+
<!--
Theme overrides to element on homescreen, i.e., which are drawn on top on wallpaper.
Various foreground colors are overridden to be workspaceTextColor so that they are properly
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 01e9b6e..e6f8a85 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -216,6 +216,7 @@
cancelDotScaleAnim();
mDotParams.scale = 0f;
mForceHideDot = false;
+ setBackground(null);
}
private void cancelDotScaleAnim() {
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index a35f598..bc6fa6e 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -403,14 +403,15 @@
Point totalWorkspacePadding = getTotalWorkspacePadding();
// Check if the icons fit within the available height.
- float usedHeight = folderCellHeightPx * inv.numFolderRows + folderBottomPanelSize;
- int maxHeight = availableHeightPx - totalWorkspacePadding.y - folderMargin;
- float scaleY = maxHeight / usedHeight;
+ float contentUsedHeight = folderCellHeightPx * inv.numFolderRows;
+ int contentMaxHeight = availableHeightPx - totalWorkspacePadding.y - folderBottomPanelSize
+ - folderMargin;
+ float scaleY = contentMaxHeight / contentUsedHeight;
// Check if the icons fit within the available width.
- float usedWidth = folderCellWidthPx * inv.numFolderColumns;
- int maxWidth = availableWidthPx - totalWorkspacePadding.x - folderMargin;
- float scaleX = maxWidth / usedWidth;
+ float contentUsedWidth = folderCellWidthPx * inv.numFolderColumns;
+ int contentMaxWidth = availableWidthPx - totalWorkspacePadding.x - folderMargin;
+ float scaleX = contentMaxWidth / contentUsedWidth;
float scale = Math.min(scaleX, scaleY);
if (scale < 1f) {
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 4811b48..b3b2df6 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -103,6 +103,7 @@
import com.android.launcher3.dragndrop.DragView;
import com.android.launcher3.folder.FolderGridOrganizer;
import com.android.launcher3.folder.FolderIcon;
+import com.android.launcher3.folder.FolderNameProvider;
import com.android.launcher3.graphics.RotationMode;
import com.android.launcher3.icons.IconCache;
import com.android.launcher3.keyboard.CustomActionsPopup;
@@ -615,6 +616,10 @@
return mStateManager;
}
+ public FolderNameProvider getFolderNameProvider() {
+ return new FolderNameProvider();
+ }
+
@Override
public <T extends View> T findViewById(int id) {
return mLauncherView.findViewById(id);
diff --git a/src/com/android/launcher3/SessionCommitReceiver.java b/src/com/android/launcher3/SessionCommitReceiver.java
index 8dedc6c..e0c50e2 100644
--- a/src/com/android/launcher3/SessionCommitReceiver.java
+++ b/src/com/android/launcher3/SessionCommitReceiver.java
@@ -71,8 +71,13 @@
SessionInfo info = intent.getParcelableExtra(PackageInstaller.EXTRA_SESSION);
UserHandle user = intent.getParcelableExtra(Intent.EXTRA_USER);
- PackageInstallerCompat packageInstallerCompat = PackageInstallerCompat.getInstance(context);
+ if (!PackageInstaller.ACTION_SESSION_COMMITTED.equals(intent.getAction())
+ || info == null || user == null) {
+ // Invalid intent.
+ return;
+ }
+ PackageInstallerCompat packageInstallerCompat = PackageInstallerCompat.getInstance(context);
if (TextUtils.isEmpty(info.getAppPackageName())
|| info.getInstallReason() != PackageManager.INSTALL_REASON_USER
|| packageInstallerCompat.promiseIconAddedForId(info.getSessionId())) {
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 431a149..d445bc9 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -1278,6 +1278,10 @@
return !mLauncher.isInState(NORMAL);
}
+ private boolean workspaceInScrollableState() {
+ return mLauncher.isInState(SPRING_LOADED) || !workspaceInModalState();
+ }
+
/** Returns whether a drag should be allowed to be started from the current workspace state. */
public boolean workspaceIconsCanBeDragged() {
return mLauncher.getStateManager().getState().workspaceIconsCanBeDragged;
@@ -2879,7 +2883,7 @@
@Override
public boolean scrollLeft() {
boolean result = false;
- if (!workspaceInModalState() && !mIsSwitchingState) {
+ if (!mIsSwitchingState && workspaceInScrollableState()) {
result = super.scrollLeft();
}
Folder openFolder = Folder.getOpen(mLauncher);
@@ -2892,7 +2896,7 @@
@Override
public boolean scrollRight() {
boolean result = false;
- if (!workspaceInModalState() && !mIsSwitchingState) {
+ if (!mIsSwitchingState && workspaceInScrollableState()) {
result = super.scrollRight();
}
Folder openFolder = Folder.getOpen(mLauncher);
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index 40c6b5f..7a7e1fe 100644
--- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -38,7 +38,6 @@
import com.android.launcher3.LauncherStateManager.AnimationConfig;
import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.anim.PropertySetter;
-import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.graphics.WorkspaceAndHotseatScrim;
/**
@@ -96,14 +95,13 @@
propertySetter.setFloat(mWorkspace, SCALE_PROPERTY, mNewScale, scaleInterpolator);
if (!hotseat.getRotationMode().isTransposed) {
- // Set the hotseat's pivot point to match the workspace's, so that it scales together.
- DragLayer dragLayer = mLauncher.getDragLayer();
- float[] workspacePivot =
- new float[]{ mWorkspace.getPivotX(), mWorkspace.getPivotY() };
- dragLayer.getDescendantCoordRelativeToSelf(mWorkspace, workspacePivot);
- dragLayer.mapCoordInSelfToDescendant(hotseat, workspacePivot);
- hotseat.setPivotX(workspacePivot[0]);
- hotseat.setPivotY(workspacePivot[1]);
+ // Set the hotseat's pivot point to match the workspace's, so that it scales
+ // together. Since both hotseat and workspace can move, transform the point
+ // manually instead of using dragLayer.getDescendantCoordRelativeToSelf and
+ // related methods.
+ hotseat.setPivotY(mWorkspace.getPivotY() + mWorkspace.getTop() - hotseat.getTop());
+ hotseat.setPivotX(mWorkspace.getPivotX()
+ + mWorkspace.getLeft() - hotseat.getLeft());
}
float hotseatScale = hotseatScaleAndTranslation.scale;
Interpolator hotseatScaleInterpolator = builder.getInterpolator(ANIM_HOTSEAT_SCALE,
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 3836c9f..08ce9c2 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -2,8 +2,6 @@
import static com.android.launcher3.LauncherState.ALL_APPS_CONTENT;
import static com.android.launcher3.LauncherState.ALL_APPS_HEADER_EXTRA;
-import static com.android.launcher3.LauncherState.BACKGROUND_APP;
-import static com.android.launcher3.LauncherState.HOTSEAT_ICONS;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.LauncherState.VERTICAL_SWIPE_INDICATOR;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_ALL_APPS_FADE;
@@ -134,15 +132,6 @@
} else {
mLauncher.getSystemUiController().updateUiState(UI_STATE_ALL_APPS, 0);
}
-
- if ((OVERVIEW.getVisibleElements(mLauncher) & HOTSEAT_ICONS) != 0) {
- // Translate hotseat with the shelf until reaching overview.
- float overviewProgress = OVERVIEW.getVerticalProgress(mLauncher);
- if (progress >= overviewProgress || mLauncher.isInState(BACKGROUND_APP)) {
- float hotseatShift = (progress - overviewProgress) * mShiftRange;
- mLauncher.getHotseat().setTranslationY(hotseatShift);
- }
- }
}
public float getProgress() {
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index d622037..f4b705e 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -110,6 +110,10 @@
"FAKE_LANDSCAPE_UI", false,
"Rotate launcher UI instead of using transposed layout");
+ public static final TogglableFlag FOLDER_NAME_SUGGEST = new TogglableFlag(
+ "FOLDER_NAME_SUGGEST", true,
+ "Suggests folder names instead of blank text.");
+
public static final TogglableFlag APP_SEARCH_IMPROVEMENTS = new TogglableFlag(
"APP_SEARCH_IMPROVEMENTS", false,
"Adds localized title and keyword search and ranking");
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index 65d593c..6b9e205 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -74,7 +74,10 @@
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.logging.LoggerUtils;
import com.android.launcher3.pageindicators.PageIndicatorDots;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
+import com.android.launcher3.userevent.nano.LauncherLogProto.ItemType;
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
import com.android.launcher3.util.Thunk;
import com.android.launcher3.views.ClipPathView;
@@ -401,7 +404,6 @@
mFolderName.setText("");
mFolderName.setHint(R.string.folder_hint_text);
}
-
// In case any children didn't come across during loading, clean up the folder accordingly
mFolderIcon.post(() -> {
if (getItemCount() <= 1) {
@@ -410,6 +412,22 @@
});
}
+
+ /**
+ * Show suggested folder title.
+ */
+ public void showSuggestedTitle(CharSequence suggestName) {
+ if (FeatureFlags.FOLDER_NAME_SUGGEST.get() && mInfo.contents.size() == 2) {
+ if (!TextUtils.isEmpty(suggestName)) {
+ mFolderName.setHint(suggestName);
+ mFolderName.setText(suggestName);
+ mFolderName.showKeyboard();
+ mInfo.title = suggestName;
+ }
+ animateOpen();
+ }
+ }
+
/**
* Creates a new UserFolder, inflated from R.layout.user_folder.
*
@@ -532,8 +550,6 @@
// dropping. One resulting issue is that replaceFolderWithFinalItem() can be called twice.
mDeleteFolderOnDropCompleted = false;
- centerAboutIcon();
-
AnimatorSet anim = new FolderAnimationManager(this, true /* isOpening */).getAnimator();
anim.addListener(new AnimatorListenerAdapter() {
@Override
@@ -546,7 +562,11 @@
mState = STATE_OPEN;
announceAccessibilityChanges();
- mLauncher.getUserEventDispatcher().resetElapsedContainerMillis("folder opened");
+ mLauncher.getUserEventDispatcher().logActionOnItem(
+ Touch.TAP,
+ Direction.NONE,
+ ItemType.FOLDER_ICON, mInfo.cellX, mInfo.cellY);
+
mContent.setFocusOnFirstChild();
}
});
@@ -592,7 +612,6 @@
if (mDragController.isDragging()) {
mDragController.forceTouchMove();
}
-
mContent.verifyVisibleHighResIcons(mContent.getNextPage());
}
@@ -877,7 +896,6 @@
// Reordering may have occured, and we need to save the new item locations. We do this once
// at the end to prevent unnecessary database operations.
updateItemLocationsInDatabaseBatch();
-
// Use the item count to check for multi-page as the folder UI may not have
// been refreshed yet.
if (getItemCount() <= mContent.itemsPerPage()) {
@@ -975,8 +993,8 @@
private int getContentAreaHeight() {
DeviceProfile grid = mLauncher.getDeviceProfile();
- int maxContentAreaHeight = grid.availableHeightPx
- - grid.getTotalWorkspacePadding().y - mFooterHeight;
+ int maxContentAreaHeight = grid.availableHeightPx - grid.getTotalWorkspacePadding().y
+ - mFooterHeight;
int height = Math.min(maxContentAreaHeight,
mContent.getDesiredHeight());
return Math.max(height, MIN_CONTENT_DIMEN);
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index 3840639..fd6d1e3 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -58,12 +58,14 @@
import com.android.launcher3.Workspace;
import com.android.launcher3.WorkspaceItemInfo;
import com.android.launcher3.anim.Interpolators;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dot.FolderDotInfo;
import com.android.launcher3.dragndrop.BaseItemDragListener;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.dragndrop.DragView;
import com.android.launcher3.icons.DotRenderer;
import com.android.launcher3.touch.ItemClickHandler;
+import com.android.launcher3.util.Executors;
import com.android.launcher3.util.Thunk;
import com.android.launcher3.views.IconLabelDotView;
import com.android.launcher3.widget.PendingAddShortcutInfo;
@@ -368,12 +370,17 @@
if (!itemAdded) mPreviewItemManager.hidePreviewItem(index, true);
final int finalIndex = index;
- postDelayed(new Runnable() {
- public void run() {
- mPreviewItemManager.hidePreviewItem(finalIndex, false);
- mFolder.showItem(item);
- invalidate();
- }
+
+ String[] suggestedNameOut = new String[1];
+ if (FeatureFlags.FOLDER_NAME_SUGGEST.get()) {
+ Executors.UI_HELPER_EXECUTOR.post(() -> mLauncher.getFolderNameProvider()
+ .getSuggestedFolderName(getContext(), mInfo.contents, suggestedNameOut));
+ }
+ postDelayed(() -> {
+ mPreviewItemManager.hidePreviewItem(finalIndex, false);
+ mFolder.showItem(item);
+ invalidate();
+ mFolder.showSuggestedTitle(suggestedNameOut[0]);
}, DROP_IN_ANIMATION_DURATION);
} else {
addItem(item);
diff --git a/src/com/android/launcher3/folder/FolderNameProvider.java b/src/com/android/launcher3/folder/FolderNameProvider.java
new file mode 100644
index 0000000..0a1221e
--- /dev/null
+++ b/src/com/android/launcher3/folder/FolderNameProvider.java
@@ -0,0 +1,61 @@
+/*
+ * 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.folder;
+
+import android.content.ComponentName;
+import android.content.Context;
+
+import com.android.launcher3.LauncherSettings.Favorites;
+import com.android.launcher3.WorkspaceItemInfo;
+
+import java.util.ArrayList;
+
+/**
+ * Locates provider for the folder name.
+ */
+public class FolderNameProvider {
+
+ /**
+ * Returns suggested folder name.
+ */
+ public CharSequence getSuggestedFolderName(Context context,
+ ArrayList<WorkspaceItemInfo> workspaceItemInfos, CharSequence[] suggestName) {
+ // Currently only run the algorithm on initial folder creation.
+ // For more than 2 items in the folder, the ranking algorithm for finding
+ // candidate folder name should be rewritten.
+ if (workspaceItemInfos.size() == 2) {
+ ComponentName cmp1 = workspaceItemInfos.get(0).getTargetComponent();
+ ComponentName cmp2 = workspaceItemInfos.get(1).getTargetComponent();
+
+ String pkgName0 = cmp1 == null ? "" : cmp1.getPackageName();
+ String pkgName1 = cmp2 == null ? "" : cmp2.getPackageName();
+ // If the two icons are from the same package,
+ // then assign the main icon's name
+ if (pkgName0.equals(pkgName1)) {
+ WorkspaceItemInfo wInfo0 = workspaceItemInfos.get(0);
+ WorkspaceItemInfo wInfo1 = workspaceItemInfos.get(1);
+ if (workspaceItemInfos.get(0).itemType == Favorites.ITEM_TYPE_APPLICATION) {
+ suggestName[0] = wInfo0.title;
+ } else if (wInfo1.itemType == Favorites.ITEM_TYPE_APPLICATION) {
+ suggestName[0] = wInfo1.title;
+ }
+ return suggestName[0];
+ // two icons are all shortcuts. Don't assign title
+ }
+ }
+ return suggestName[0];
+ }
+}
diff --git a/src/com/android/launcher3/logging/LoggerUtils.java b/src/com/android/launcher3/logging/LoggerUtils.java
index 9b75b43..598792a 100644
--- a/src/com/android/launcher3/logging/LoggerUtils.java
+++ b/src/com/android/launcher3/logging/LoggerUtils.java
@@ -44,6 +44,7 @@
public class LoggerUtils {
private static final ArrayMap<Class, SparseArray<String>> sNameCache = new ArrayMap<>();
private static final String UNKNOWN = "UNKNOWN";
+ private static final int DEFAULT_PREDICTED_RANK = -100;
public static String getFieldName(int value, Class c) {
SparseArray<String> cache;
@@ -90,7 +91,7 @@
}
public static String getTargetStr(Target t) {
- if (t == null){
+ if (t == null) {
return "";
}
String str = "";
@@ -137,17 +138,16 @@
if (t.intentHash != 0) {
typeStr += ", intentHash=" + t.intentHash;
}
- if ((t.packageNameHash != 0 || t.componentHash != 0 || t.intentHash != 0) &&
- t.itemType != ItemType.TASK) {
+ if (t.itemType == ItemType.FOLDER_ICON) {
+ typeStr += ", grid(" + t.gridX + "," + t.gridY + ")";
+ } else if ((t.packageNameHash != 0 || t.componentHash != 0 || t.intentHash != 0)
+ && t.itemType != ItemType.TASK) {
typeStr += ", predictiveRank=" + t.predictedRank + ", grid(" + t.gridX + "," + t.gridY
- + "), span(" + t.spanX + "," + t.spanY
- + "), pageIdx=" + t.pageIndex;
-
+ + "), span(" + t.spanX + "," + t.spanY + "), pageIdx=" + t.pageIndex;
}
if (t.searchQueryLength != 0) {
typeStr += ", searchQueryLength=" + t.searchQueryLength;
}
-
if (t.itemType == ItemType.TASK) {
typeStr += ", pageIdx=" + t.pageIndex;
}
@@ -168,17 +168,17 @@
public static Target newItemTarget(ItemInfo info, InstantAppResolver instantAppResolver) {
Target t = newTarget(Target.Type.ITEM);
-
switch (info.itemType) {
case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
t.itemType = (instantAppResolver != null && info instanceof AppInfo
- && instantAppResolver.isInstantApp(((AppInfo) info)) )
+ && instantAppResolver.isInstantApp(((AppInfo) info)))
? ItemType.WEB_APP
: ItemType.APP_ICON;
- t.predictedRank = -100; // Never assigned
+ t.predictedRank = DEFAULT_PREDICTED_RANK;
break;
case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
t.itemType = ItemType.SHORTCUT;
+ t.predictedRank = DEFAULT_PREDICTED_RANK;
break;
case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
t.itemType = ItemType.FOLDER_ICON;
@@ -188,6 +188,7 @@
break;
case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT:
t.itemType = ItemType.DEEPSHORTCUT;
+ t.predictedRank = DEFAULT_PREDICTED_RANK;
break;
}
return t;
diff --git a/src/com/android/launcher3/logging/UserEventDispatcher.java b/src/com/android/launcher3/logging/UserEventDispatcher.java
index 21ca74e..99906fe 100644
--- a/src/com/android/launcher3/logging/UserEventDispatcher.java
+++ b/src/com/android/launcher3/logging/UserEventDispatcher.java
@@ -26,6 +26,8 @@
import static com.android.launcher3.logging.LoggerUtils.newTarget;
import static com.android.launcher3.logging.LoggerUtils.newTouchAction;
+import static java.util.Optional.ofNullable;
+
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
@@ -35,6 +37,7 @@
import android.util.Log;
import android.view.View;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.launcher3.DropTarget;
@@ -58,7 +61,7 @@
/**
* Manages the creation of {@link LauncherEvent}.
* To debug this class, execute following command before side loading a new apk.
- *
+ * <p>
* $ adb shell setprop log.tag.UserEvent VERBOSE
*/
public class UserEventDispatcher implements ResourceBasedOverride {
@@ -94,19 +97,26 @@
/**
* Fills in the container data on the given event if the given view is not null.
+ *
* @return whether container data was added.
*/
- public static boolean fillInLogContainerData(LauncherLogProto.LauncherEvent event, @Nullable View v) {
+ public boolean fillInLogContainerData(LauncherLogProto.LauncherEvent event, @Nullable View v) {
// Fill in grid(x,y), pageIndex of the child and container type of the parent
LogContainerProvider provider = StatsLogUtils.getLaunchProviderRecursive(v);
if (v == null || !(v.getTag() instanceof ItemInfo) || provider == null) {
return false;
}
- ItemInfo itemInfo = (ItemInfo) v.getTag();
- provider.fillInLogContainerData(v, itemInfo, event.srcTarget[0], event.srcTarget[1]);
+ final ItemInfo itemInfo = (ItemInfo) v.getTag();
+ final Target target = event.srcTarget[0];
+ final Target targetParent = event.srcTarget[1];
+ onFillInLogContainerData(itemInfo, target, targetParent);
+ provider.fillInLogContainerData(v, itemInfo, target, targetParent);
return true;
}
+ protected void onFillInLogContainerData(
+ @NonNull ItemInfo itemInfo, @NonNull Target target, @NonNull Target targetParent) { }
+
private boolean mSessionStarted;
private long mElapsedContainerMillis;
private long mElapsedSessionMillis;
@@ -139,7 +149,11 @@
mAppOrTaskLaunch = true;
}
- public void logActionTip(int actionType, int viewType) { }
+ /**
+ * Dummy method.
+ */
+ public void logActionTip(int actionType, int viewType) {
+ }
@Deprecated
public void logTaskLaunchOrDismiss(int action, int direction, int taskIndex,
@@ -184,15 +198,15 @@
public void logActionCommand(int command, int srcContainerType, int dstContainerType) {
logActionCommand(command, newContainerTarget(srcContainerType),
- dstContainerType >=0 ? newContainerTarget(dstContainerType) : null);
+ dstContainerType >= 0 ? newContainerTarget(dstContainerType) : null);
}
public void logActionCommand(int command, int srcContainerType, int dstContainerType,
- int pageIndex) {
+ int pageIndex) {
Target srcTarget = newContainerTarget(srcContainerType);
srcTarget.pageIndex = pageIndex;
logActionCommand(command, srcTarget,
- dstContainerType >=0 ? newContainerTarget(dstContainerType) : null);
+ dstContainerType >= 0 ? newContainerTarget(dstContainerType) : null);
}
public void logActionCommand(int command, Target srcTarget, Target dstTarget) {
@@ -241,7 +255,7 @@
}
public void logActionOnControl(int action, int controlType, int parentContainer,
- int grandParentContainer){
+ int grandParentContainer) {
LauncherEvent event = newLauncherEvent(newTouchAction(action),
newControlTarget(controlType),
newContainerTarget(parentContainer),
@@ -250,11 +264,11 @@
}
public void logActionOnControl(int action, int controlType, @Nullable View controlInContainer,
- int parentContainerType) {
+ int parentContainerType) {
final LauncherEvent event = (controlInContainer == null && parentContainerType < 0)
? newLauncherEvent(newTouchAction(action), newTarget(Target.Type.CONTROL))
: newLauncherEvent(newTouchAction(action), newTarget(Target.Type.CONTROL),
- newTarget(Target.Type.CONTAINER));
+ newTarget(Target.Type.CONTAINER));
event.srcTarget[0].controlType = controlType;
if (controlInContainer != null) {
fillInLogContainerData(event, controlInContainer);
@@ -301,9 +315,9 @@
* (1) WORKSPACE: if the launcher is the foreground activity
* (2) APP: if another app was the foreground activity
*/
- public void logStateChangeAction(int action, int dir, int downX, int downY, int srcChildTargetType,
- int srcParentContainerType, int dstContainerType,
- int pageIndex) {
+ public void logStateChangeAction(int action, int dir, int downX, int downY,
+ int srcChildTargetType, int srcParentContainerType, int dstContainerType,
+ int pageIndex) {
LauncherEvent event;
if (srcChildTargetType == LauncherLogProto.ItemType.TASK) {
event = newLauncherEvent(newTouchAction(action),
@@ -326,9 +340,25 @@
}
public void logActionOnItem(int action, int dir, int itemType) {
+ logActionOnItem(action, dir, itemType, null, null);
+ }
+
+ /**
+ * Creates new {@link LauncherEvent} of ITEM target type with input arguments and dispatches it.
+ *
+ * @param touchAction ENUM value of {@link LauncherLogProto.Action.Touch} Action
+ * @param dir ENUM value of {@link LauncherLogProto.Action.Direction} Action
+ * @param itemType ENUM value of {@link LauncherLogProto.ItemType}
+ * @param gridX Nullable X coordinate of item's position on the workspace grid
+ * @param gridY Nullable Y coordinate of item's position on the workspace grid
+ */
+ public void logActionOnItem(int touchAction, int dir, int itemType,
+ @Nullable Integer gridX, @Nullable Integer gridY) {
Target itemTarget = newTarget(Target.Type.ITEM);
itemTarget.itemType = itemType;
- LauncherEvent event = newLauncherEvent(newTouchAction(action), itemTarget);
+ ofNullable(gridX).ifPresent(value -> itemTarget.gridX = value);
+ ofNullable(gridY).ifPresent(value -> itemTarget.gridY = value);
+ LauncherEvent event = newLauncherEvent(newTouchAction(touchAction), itemTarget);
event.action.dir = dir;
dispatchUserEvent(event, null);
}
@@ -351,7 +381,7 @@
LauncherEvent event = newLauncherEvent(newTouchAction(Action.Touch.DRAGDROP),
newItemTarget(dragObj.originalDragInfo, mInstantAppResolver),
newTarget(Target.Type.CONTAINER));
- event.destTarget = new Target[] {
+ event.destTarget = new Target[]{
newItemTarget(dragObj.originalDragInfo, mInstantAppResolver),
newDropTarget(dropTargetAsView)
};
@@ -373,14 +403,10 @@
int actionTouch = isButton ? Action.Touch.TAP : Action.Touch.SWIPE;
Action action = newCommandAction(actionTouch);
action.command = Action.Command.BACK;
- action.dir = isButton
- ? Action.Direction.NONE
- : gestureSwipeLeft
- ? Action.Direction.LEFT
- : Action.Direction.RIGHT;
- Target target = newControlTarget(isButton
- ? LauncherLogProto.ControlType.BACK_BUTTON
- : LauncherLogProto.ControlType.BACK_GESTURE);
+ action.dir = isButton ? Action.Direction.NONE :
+ gestureSwipeLeft ? Action.Direction.LEFT : Action.Direction.RIGHT;
+ Target target = newControlTarget(isButton ? LauncherLogProto.ControlType.BACK_BUTTON :
+ LauncherLogProto.ControlType.BACK_GESTURE);
target.spanX = downX;
target.spanY = downY;
target.cardinality = completed ? 1 : 0;
@@ -391,6 +417,7 @@
/**
* Currently logs following containers: workspace, allapps, widget tray.
+ *
* @param reason
*/
public final void resetElapsedContainerMillis(String reason) {
diff --git a/src/com/android/launcher3/notification/NotificationListener.java b/src/com/android/launcher3/notification/NotificationListener.java
index 0e73829..059ad18 100644
--- a/src/com/android/launcher3/notification/NotificationListener.java
+++ b/src/com/android/launcher3/notification/NotificationListener.java
@@ -115,8 +115,8 @@
switch (message.what) {
case MSG_NOTIFICATION_POSTED: {
StatusBarNotification sbn = (StatusBarNotification) message.obj;
- mUiHandler.obtainMessage(shouldBeFilteredOut(sbn)
- ? MSG_NOTIFICATION_REMOVED : MSG_NOTIFICATION_POSTED,
+ mUiHandler.obtainMessage(notificationIsValidForUI(sbn)
+ ? MSG_NOTIFICATION_POSTED : MSG_NOTIFICATION_REMOVED,
toKeyPair(sbn)).sendToTarget();
return true;
}
@@ -148,7 +148,7 @@
if (sIsConnected) {
try {
activeNotifications = Arrays.stream(getActiveNotifications())
- .filter(this::shouldBeFilteredOut)
+ .filter(this::notificationIsValidForUI)
.collect(Collectors.toList());
} catch (SecurityException ex) {
Log.e(TAG, "SecurityException: failed to fetch notifications");
@@ -305,22 +305,22 @@
}
/**
- * Returns true for notifications that don't have an intent
- * or are headers for grouped notifications and should be filtered out.
+ * Returns true for notifications that have an intent and are not headers for grouped
+ * notifications and should be shown in the notification popup.
*/
@WorkerThread
- private boolean shouldBeFilteredOut(StatusBarNotification sbn) {
+ private boolean notificationIsValidForUI(StatusBarNotification sbn) {
Notification notification = sbn.getNotification();
updateGroupKeyIfNecessary(sbn);
getCurrentRanking().getRanking(sbn.getKey(), mTempRanking);
if (!mTempRanking.canShowBadge()) {
- return true;
+ return false;
}
if (mTempRanking.getChannel().getId().equals(NotificationChannel.DEFAULT_CHANNEL_ID)) {
// Special filtering for the default, legacy "Miscellaneous" channel.
if ((notification.flags & Notification.FLAG_ONGOING_EVENT) != 0) {
- return true;
+ return false;
}
}
@@ -328,7 +328,7 @@
CharSequence text = notification.extras.getCharSequence(Notification.EXTRA_TEXT);
boolean missingTitleAndText = TextUtils.isEmpty(title) && TextUtils.isEmpty(text);
boolean isGroupHeader = (notification.flags & Notification.FLAG_GROUP_SUMMARY) != 0;
- return (isGroupHeader || missingTitleAndText);
+ return !isGroupHeader && !missingTitleAndText;
}
private static Pair<PackageUserKey, NotificationKeyData> toKeyPair(StatusBarNotification sbn) {
diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java
index 64df384..40e267b 100644
--- a/src/com/android/launcher3/testing/TestInformationHandler.java
+++ b/src/com/android/launcher3/testing/TestInformationHandler.java
@@ -173,6 +173,12 @@
mLeaks.add(new View(mContext));
break;
}
+
+ case TestProtocol.REQUEST_ICON_HEIGHT: {
+ response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD,
+ mDeviceProfile.allAppsCellHeightPx);
+ break;
+ }
}
return response;
}
diff --git a/src/com/android/launcher3/testing/TestProtocol.java b/src/com/android/launcher3/testing/TestProtocol.java
index 1cfa4af..832f7f0 100644
--- a/src/com/android/launcher3/testing/TestProtocol.java
+++ b/src/com/android/launcher3/testing/TestProtocol.java
@@ -63,6 +63,8 @@
"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 final String REQUEST_ICON_HEIGHT =
+ "icon-height";
public static final String REQUEST_HOTSEAT_TOP = "hotseat-top";
public static final String REQUEST_IS_LAUNCHER_INITIALIZED = "is-launcher-initialized";
public static final String REQUEST_FREEZE_APP_LIST = "freeze-app-list";
diff --git a/src/com/android/launcher3/util/ObjectWrapper.java b/src/com/android/launcher3/util/ObjectWrapper.java
index b692431..e5b4707 100644
--- a/src/com/android/launcher3/util/ObjectWrapper.java
+++ b/src/com/android/launcher3/util/ObjectWrapper.java
@@ -25,7 +25,7 @@
*/
public class ObjectWrapper<T> extends Binder {
- private final T mObject;
+ private T mObject;
public ObjectWrapper(T object) {
mObject = object;
@@ -35,6 +35,10 @@
return mObject;
}
+ public void clear() {
+ mObject = null;
+ }
+
public static IBinder wrap(Object obj) {
return new ObjectWrapper<>(obj);
}
diff --git a/src/com/android/launcher3/util/ViewPool.java b/src/com/android/launcher3/util/ViewPool.java
index 8af048d..5b33f18 100644
--- a/src/com/android/launcher3/util/ViewPool.java
+++ b/src/com/android/launcher3/util/ViewPool.java
@@ -21,12 +21,12 @@
import android.view.View;
import android.view.ViewGroup;
-import com.android.launcher3.util.ViewPool.Reusable;
-
import androidx.annotation.AnyThread;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
+import com.android.launcher3.util.ViewPool.Reusable;
+
/**
* Utility class to maintain a pool of reusable views.
* During initialization, views are inflated on the background thread.
@@ -58,14 +58,18 @@
Preconditions.assertUIThread();
Handler handler = new Handler();
+ // LayoutInflater is not thread save as it maintains a global variable 'mConstructorArgs'.
+ // Create a different copy to use on the background thread.
+ LayoutInflater inflater = mInflater.cloneInContext(mInflater.getContext());
+
// Inflate views on a non looper thread. This allows us to catch errors like calling
// "new Handler()" in constructor easily.
new Thread(() -> {
for (int i = 0; i < initialSize; i++) {
- T view = inflateNewView();
+ T view = inflateNewView(inflater);
handler.post(() -> addToPool(view));
}
- }).start();
+ }, "ViewPool-init").start();
}
@UiThread
@@ -94,12 +98,12 @@
mCurrentSize--;
return (T) mPool[mCurrentSize];
}
- return inflateNewView();
+ return inflateNewView(mInflater);
}
@AnyThread
- private T inflateNewView() {
- return (T) mInflater.inflate(mLayoutId, mParent, false);
+ private T inflateNewView(LayoutInflater inflater) {
+ return (T) inflater.inflate(mLayoutId, mParent, false);
}
/**
diff --git a/src_plugins/com/android/systemui/plugins/RecentsExtraCard.java b/src_plugins/com/android/systemui/plugins/RecentsExtraCard.java
index 0ebea3d..cd9f33d 100644
--- a/src_plugins/com/android/systemui/plugins/RecentsExtraCard.java
+++ b/src_plugins/com/android/systemui/plugins/RecentsExtraCard.java
@@ -34,9 +34,9 @@
/**
* Sets up the recents overview extra card and fills in data.
*
- * @param context Plugin context
+ * @param context Plugin context
* @param frameLayout PlaceholderView
- * @param activity Recents activity to hold extra view
+ * @param activity Recents activity to hold extra view
*/
void setupView(Context context, FrameLayout frameLayout, Activity activity);
}
diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml
index 24b5b02..5cf96c8 100644
--- a/tests/AndroidManifest.xml
+++ b/tests/AndroidManifest.xml
@@ -18,7 +18,7 @@
xmlns:tools="http://schemas.android.com/tools"
package="com.android.launcher3.tests">
- <uses-sdk android:targetSdkVersion="28" android:minSdkVersion="25"
+ <uses-sdk android:targetSdkVersion="29" android:minSdkVersion="25"
tools:overrideLibrary="android.support.test.uiautomator.v18"/>
<application android:debuggable="true">
diff --git a/tests/dummy_app/AndroidManifest.xml b/tests/dummy_app/AndroidManifest.xml
index 9d0a74a..f00138c 100644
--- a/tests/dummy_app/AndroidManifest.xml
+++ b/tests/dummy_app/AndroidManifest.xml
@@ -21,7 +21,7 @@
to come from a domain that you own or have control over. -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.android.aardwolf">
- <uses-sdk android:targetSdkVersion="28" android:minSdkVersion="21"/>
+ <uses-sdk android:targetSdkVersion="29" android:minSdkVersion="21"/>
<application android:label="Aardwolf">
<activity
android:name="Activity1"
diff --git a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
index 191b405..d7096b0 100644
--- a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
+++ b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
@@ -18,10 +18,6 @@
import static androidx.test.InstrumentationRegistry.getInstrumentation;
-import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_PRESUBMIT;
-import static com.android.launcher3.util.rule.TestStabilityRule.RUN_FLAFOR;
-import static com.android.launcher3.util.rule.TestStabilityRule.UNBUNDLED_PRESUBMIT;
-
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -38,7 +34,6 @@
import com.android.launcher3.tapl.AppIcon;
import com.android.launcher3.tapl.AppIconMenu;
import com.android.launcher3.tapl.AppIconMenuItem;
-import com.android.launcher3.tapl.TestHelpers;
import com.android.launcher3.tapl.Widgets;
import com.android.launcher3.tapl.Workspace;
import com.android.launcher3.views.OptionsPopupView;
@@ -177,11 +172,6 @@
@Test
public void testWorkspace() throws Exception {
- // b/142828227
- if (android.os.Build.MODEL.contains("Cuttlefish") && TestHelpers.isInLauncherProcess() &&
- (RUN_FLAFOR & (PLATFORM_PRESUBMIT | UNBUNDLED_PRESUBMIT)) != 0) {
- return;
- }
final Workspace workspace = mLauncher.getWorkspace();
// Test that ensureWorkspaceIsScrollable adds a page by dragging an icon there.
@@ -349,23 +339,6 @@
}
}
- /**
- * Test dragging a custom shortcut to the workspace and launch it.
- *
- * A custom shortcut is a 1x1 widget that launches a specific intent when user tap on it.
- * Custom shortcuts are replaced by deep shortcuts after api 25.
- */
- @Test
- @PortraitLandscape
- public void testDragCustomShortcut() {
- if (!TestHelpers.isInLauncherProcess()) return; // b/143725213
- mLauncher.getWorkspace().openAllWidgets()
- .getWidget("com.android.launcher3.testcomponent.CustomShortcutConfigActivity")
- .dragToWorkspace();
- mLauncher.getWorkspace().getWorkspaceAppIcon("Shortcut")
- .launch(getAppPackageName());
- }
-
public static String getAppPackageName() {
return getInstrumentation().getContext().getPackageName();
}
diff --git a/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java
index 259f9ed..f9d1d93 100644
--- a/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java
@@ -16,7 +16,6 @@
package com.android.launcher3.ui.widget;
import static com.android.launcher3.ui.TaplTestsLauncher3.getAppPackageName;
-import static com.android.launcher3.util.rule.TestStabilityRule.UNBUNDLED_POSTSUBMIT;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
@@ -30,7 +29,6 @@
import com.android.launcher3.ui.AbstractLauncherUiTest;
import com.android.launcher3.ui.TestViewHelpers;
import com.android.launcher3.util.rule.ShellCommandRule;
-import com.android.launcher3.util.rule.TestStabilityRule.Stability;
import org.junit.Rule;
import org.junit.Test;
@@ -71,4 +69,22 @@
assertNotNull("Widget not found on the workspace", widget);
widget.launch(getAppPackageName());
}
+
+ /**
+ * Test dragging a custom shortcut to the workspace and launch it.
+ *
+ * A custom shortcut is a 1x1 widget that launches a specific intent when user tap on it.
+ * Custom shortcuts are replaced by deep shortcuts after api 25.
+ */
+ @Test
+ @PortraitLandscape
+ public void testDragCustomShortcut() throws Throwable {
+ clearHomescreen();
+ mDevice.pressHome();
+ mLauncher.getWorkspace().openAllWidgets()
+ .getWidget("com.android.launcher3.testcomponent.CustomShortcutConfigActivity")
+ .dragToWorkspace();
+ mLauncher.getWorkspace().getWorkspaceAppIcon("Shortcut")
+ .launch(getAppPackageName());
+ }
}
diff --git a/tests/tapl/com/android/launcher3/tapl/AllApps.java b/tests/tapl/com/android/launcher3/tapl/AllApps.java
index cc92327..3bdeb14 100644
--- a/tests/tapl/com/android/launcher3/tapl/AllApps.java
+++ b/tests/tapl/com/android/launcher3/tapl/AllApps.java
@@ -29,6 +29,8 @@
import com.android.launcher3.ResourceUtils;
import com.android.launcher3.testing.TestProtocol;
+import java.util.stream.Collectors;
+
/**
* Operations on AllApps opened from Home. Also a parent for All Apps opened from Overview.
*/
@@ -36,6 +38,7 @@
private static final int MAX_SCROLL_ATTEMPTS = 40;
private final int mHeight;
+ private final int mIconHeight;
AllApps(LauncherInstrumentation launcher) {
super(launcher);
@@ -46,6 +49,9 @@
// Wait for the recycler to populate.
mLauncher.waitForObjectInContainer(appListRecycler, By.clazz(TextView.class));
verifyNotFrozen("All apps freeze flags upon opening all apps");
+ mIconHeight = mLauncher.getTestInfo(
+ TestProtocol.REQUEST_ICON_HEIGHT).
+ getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
}
@Override
@@ -62,12 +68,16 @@
}
final Rect iconBounds = icon.getVisibleBounds();
LauncherInstrumentation.log("hasClickableIcon: icon bounds: " + iconBounds);
+ if (iconBounds.height() < mIconHeight / 2) {
+ LauncherInstrumentation.log("hasClickableIcon: icon has insufficient height");
+ return false;
+ }
if (iconCenterInSearchBox(allAppsContainer, icon)) {
LauncherInstrumentation.log("hasClickableIcon: icon center is under search box");
return false;
}
if (iconBounds.bottom > displayBottom) {
- LauncherInstrumentation.log("hasClickableIcon: icon center bellow bottom offset");
+ LauncherInstrumentation.log("hasClickableIcon: icon bottom below bottom offset");
return false;
}
LauncherInstrumentation.log("hasClickableIcon: icon is clickable");
@@ -100,11 +110,6 @@
ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE, mLauncher.getResources()) + 1;
int deviceHeight = mLauncher.getDevice().getDisplayHeight();
int displayBottom = deviceHeight - bottomGestureMargin;
- allAppsContainer.setGestureMargins(
- 0,
- getSearchBox(allAppsContainer).getVisibleBounds().bottom + 1,
- 0,
- bottomGestureMargin);
final BySelector appIconSelector = AppIcon.getAppIconSelector(appName, mLauncher);
if (!hasClickableIcon(allAppsContainer, appListRecycler, appIconSelector,
displayBottom)) {
@@ -116,7 +121,12 @@
displayBottom)) {
mLauncher.scrollToLastVisibleRow(
allAppsContainer,
- mLauncher.getObjectsInContainer(allAppsContainer, "icon"),
+ mLauncher.getObjectsInContainer(allAppsContainer, "icon")
+ .stream()
+ .filter(icon ->
+ icon.getVisibleBounds().bottom
+ <= displayBottom)
+ .collect(Collectors.toList()),
searchBox.getVisibleBounds().bottom
- allAppsContainer.getVisibleBounds().top);
final int newScroll = getAllAppsScroll();
@@ -163,7 +173,8 @@
"Exceeded max scroll attempts: " + MAX_SCROLL_ATTEMPTS,
++attempts <= MAX_SCROLL_ATTEMPTS);
- mLauncher.scroll(allAppsContainer, Direction.UP, margins, 12);
+ mLauncher.scroll(
+ allAppsContainer, Direction.UP, margins, 12, false);
}
try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("scrolled up")) {
@@ -191,7 +202,7 @@
final UiObject2 allAppsContainer = verifyActiveContainer();
// Start the gesture in the center to avoid starting at elements near the top.
mLauncher.scroll(
- allAppsContainer, Direction.DOWN, new Rect(0, 0, 0, mHeight / 2), 10);
+ allAppsContainer, Direction.DOWN, new Rect(0, 0, 0, mHeight / 2), 10, false);
verifyActiveContainer();
}
}
@@ -205,7 +216,7 @@
final UiObject2 allAppsContainer = verifyActiveContainer();
// Start the gesture in the center, for symmetry with forward.
mLauncher.scroll(
- allAppsContainer, Direction.UP, new Rect(0, mHeight / 2, 0, 0), 10);
+ allAppsContainer, Direction.UP, new Rect(0, mHeight / 2, 0, 0), 10, false);
verifyActiveContainer();
}
}
diff --git a/tests/tapl/com/android/launcher3/tapl/Background.java b/tests/tapl/com/android/launcher3/tapl/Background.java
index 0d9038f..6583d32 100644
--- a/tests/tapl/com/android/launcher3/tapl/Background.java
+++ b/tests/tapl/com/android/launcher3/tapl/Background.java
@@ -106,7 +106,7 @@
}
if (mLauncher.isFallbackOverview()) {
- mLauncher.linearGesture(startX, startY, endX, endY, 10);
+ mLauncher.linearGesture(startX, startY, endX, endY, 10, false);
new BaseOverview(mLauncher);
} else {
mLauncher.swipeToState(startX, startY, endX, endY, 10, expectedState);
diff --git a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
index 8ccfc05..339e14f 100644
--- a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
+++ b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
@@ -55,7 +55,8 @@
final int leftMargin = mLauncher.getTestInfo(
TestProtocol.REQUEST_OVERVIEW_LEFT_GESTURE_MARGIN).
getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
- mLauncher.scroll(overview, Direction.LEFT, new Rect(leftMargin + 1, 0, 0, 0), 20);
+ mLauncher.scroll(
+ overview, Direction.LEFT, new Rect(leftMargin + 1, 0, 0, 0), 20, false);
verifyActiveContainer();
}
}
@@ -89,7 +90,8 @@
final int rightMargin = mLauncher.getTestInfo(
TestProtocol.REQUEST_OVERVIEW_RIGHT_GESTURE_MARGIN).
getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
- mLauncher.scroll(overview, Direction.RIGHT, new Rect(0, 0, rightMargin + 1, 0), 20);
+ mLauncher.scroll(
+ overview, Direction.RIGHT, new Rect(0, 0, rightMargin + 1, 0), 20, false);
verifyActiveContainer();
}
}
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 1c851f4..4024ff0 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -544,7 +544,8 @@
linearGesture(
displaySize.x / 2, displaySize.y - 1,
displaySize.x / 2, 0,
- ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME);
+ ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME,
+ false);
try (LauncherInstrumentation.Closable c = addContextLayer(
"Swiped up from context menu to home")) {
waitUntilGone("deep_shortcuts_container");
@@ -696,8 +697,8 @@
final UiObject2 object = container.wait(
Until.findObject(getLauncherObjectSelector(resName)),
WAIT_TIME_MS);
- assertNotNull("Can't find a launcher object id: " + resName + " in container: " +
- container.getResourceName(), object);
+ assertNotNull("Can't find a view in Launcher, id: " + resName + " in container: "
+ + container.getResourceName(), object);
return object;
}
@@ -706,8 +707,8 @@
final UiObject2 object = container.wait(
Until.findObject(selector),
WAIT_TIME_MS);
- assertNotNull("Can't find a launcher object id: " + selector + " in container: " +
- container.getResourceName(), object);
+ assertNotNull("Can't find a view in Launcher, id: " + selector + " in container: "
+ + container.getResourceName(), object);
return object;
}
@@ -738,7 +739,7 @@
private UiObject2 waitForObjectBySelector(BySelector selector) {
final UiObject2 object = mDevice.wait(Until.findObject(selector), WAIT_TIME_MS);
- assertNotNull("Can't find a launcher object; selector: " + selector, object);
+ assertNotNull("Can't find a view in Launcher, selector: " + selector, object);
return object;
}
@@ -769,7 +770,7 @@
void swipeToState(int startX, int startY, int endX, int endY, int steps, int expectedState) {
final Bundle parcel = (Bundle) executeAndWaitForEvent(
- () -> linearGesture(startX, startY, endX, endY, steps),
+ () -> linearGesture(startX, startY, endX, endY, steps, false),
event -> TestProtocol.SWITCHED_TO_STATE_MESSAGE.equals(event.getClassName()),
"Swipe failed to receive an event for the swipe end");
assertEquals("Swipe switched launcher to a wrong state;",
@@ -782,33 +783,38 @@
ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE, getResources()) + 1;
}
- int getBottomGestureMargin(UiObject2 container) {
- return container.getVisibleBounds().bottom - getRealDisplaySize().y
- + getBottomGestureSize();
+ int getBottomGestureMarginInContainer(UiObject2 container) {
+ final int bottomGestureStartOnScreen = getRealDisplaySize().y - getBottomGestureSize();
+ return container.getVisibleBounds().bottom - bottomGestureStartOnScreen;
}
- void scrollToLastVisibleRow(UiObject2 container, Collection<UiObject2> items, int topPadding) {
+ void scrollToLastVisibleRow(
+ UiObject2 container,
+ Collection<UiObject2> items,
+ int topPaddingInContainer) {
final UiObject2 lowestItem = Collections.max(items, (i1, i2) ->
Integer.compare(i1.getVisibleBounds().top, i2.getVisibleBounds().top));
- final int gestureStart = lowestItem.getVisibleBounds().top + getTouchSlop();
- final int distance = gestureStart - container.getVisibleBounds().top - topPadding;
- final int bottomMargin = container.getVisibleBounds().height() - distance;
+ final int itemRowCurrentTopOnScreen = lowestItem.getVisibleBounds().top;
+ final Rect containerRect = container.getVisibleBounds();
+ final int itemRowNewTopOnScreen = containerRect.top + topPaddingInContainer;
+ final int distance = itemRowCurrentTopOnScreen - itemRowNewTopOnScreen + getTouchSlop();
- // TODO: Make the gesture steps dependent on the distance so that it can run for various
- // screen sizes
+ final int bottomGestureMarginInContainer = getBottomGestureMarginInContainer(container);
scroll(
container,
Direction.DOWN,
new Rect(
0,
+ containerRect.height() - distance - bottomGestureMarginInContainer,
0,
- 0,
- Math.max(bottomMargin, getBottomGestureMargin(container))),
- 80);
+ bottomGestureMarginInContainer),
+ 10,
+ true);
}
- void scroll(UiObject2 container, Direction direction, Rect margins, int steps) {
+ void scroll(
+ UiObject2 container, Direction direction, Rect margins, int steps, boolean slowDown) {
final Rect rect = container.getVisibleBounds();
if (margins != null) {
rect.left += margins.left;
@@ -853,7 +859,7 @@
}
executeAndWaitForEvent(
- () -> linearGesture(startX, startY, endX, endY, steps),
+ () -> linearGesture(startX, startY, endX, endY, steps, slowDown),
event -> TestProtocol.SCROLL_FINISHED_MESSAGE.equals(event.getClassName()),
"Didn't receive a scroll end message: " + startX + ", " + startY
+ ", " + endX + ", " + endY);
@@ -861,13 +867,17 @@
// Inject a swipe gesture. Inject exactly 'steps' motion points, incrementing event time by a
// fixed interval each time.
- void linearGesture(int startX, int startY, int endX, int endY, int steps) {
+ void linearGesture(int startX, int startY, int endX, int endY, int steps, boolean slowDown) {
log("linearGesture: " + startX + ", " + startY + " -> " + endX + ", " + endY);
final long downTime = SystemClock.uptimeMillis();
final Point start = new Point(startX, startY);
final Point end = new Point(endX, endY);
sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN, start);
- final long endTime = movePointer(downTime, downTime, steps * GESTURE_STEP_MS, start, end);
+ long endTime = movePointer(downTime, downTime, steps * GESTURE_STEP_MS, start, end);
+ if (slowDown) {
+ endTime = movePointer(downTime, endTime + GESTURE_STEP_MS, 5 * GESTURE_STEP_MS, end,
+ end);
+ }
sendPointer(downTime, endTime, MotionEvent.ACTION_UP, end);
}
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
index 91f0fc4..2ee424b 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
@@ -52,7 +52,7 @@
final Rect taskBounds = mTask.getVisibleBounds();
final int centerX = taskBounds.centerX();
final int centerY = taskBounds.centerY();
- mLauncher.linearGesture(centerX, centerY, centerX, 0, 10);
+ mLauncher.linearGesture(centerX, centerY, centerX, 0, 10, false);
mLauncher.waitForIdle();
}
}
diff --git a/tests/tapl/com/android/launcher3/tapl/Widgets.java b/tests/tapl/com/android/launcher3/tapl/Widgets.java
index 5fcaa55..d208c66 100644
--- a/tests/tapl/com/android/launcher3/tapl/Widgets.java
+++ b/tests/tapl/com/android/launcher3/tapl/Widgets.java
@@ -48,8 +48,9 @@
mLauncher.scroll(
widgetsContainer,
Direction.DOWN,
- new Rect(0, 0, 0, mLauncher.getBottomGestureMargin(widgetsContainer) + 1),
- FLING_STEPS);
+ new Rect(0, 0, 0,
+ mLauncher.getBottomGestureMarginInContainer(widgetsContainer) + 1),
+ FLING_STEPS, false);
try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("flung forward")) {
verifyActiveContainer();
}
@@ -69,7 +70,7 @@
widgetsContainer,
Direction.UP,
new Rect(0, 0, widgetsContainer.getVisibleBounds().width(), 0),
- FLING_STEPS);
+ FLING_STEPS, false);
try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("flung back")) {
verifyActiveContainer();
}
diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java
index db3314e..a0d1a5e 100644
--- a/tests/tapl/com/android/launcher3/tapl/Workspace.java
+++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java
@@ -182,7 +182,7 @@
final UiObject2 workspace = verifyActiveContainer();
mLauncher.scroll(workspace, Direction.RIGHT,
new Rect(0, 0, mLauncher.getEdgeSensitivityWidth() + 1, 0),
- FLING_STEPS);
+ FLING_STEPS, false);
verifyActiveContainer();
}
@@ -194,7 +194,7 @@
final UiObject2 workspace = verifyActiveContainer();
mLauncher.scroll(workspace, Direction.LEFT,
new Rect(mLauncher.getEdgeSensitivityWidth() + 1, 0, 0, 0),
- FLING_STEPS);
+ FLING_STEPS, false);
verifyActiveContainer();
}