Merge "Fade in grid preview" into ub-launcher3-rvc-dev
diff --git a/Android.mk b/Android.mk
index 9cfcf17..fcd4a94 100644
--- a/Android.mk
+++ b/Android.mk
@@ -129,6 +129,7 @@
LOCAL_MODULE_TAGS := optional
LOCAL_STATIC_JAVA_LIBRARIES := \
+ SystemUI-statsd \
SystemUISharedLib \
launcherprotosnano \
launcher_log_protos_lite
@@ -201,6 +202,7 @@
LOCAL_MODULE_TAGS := optional
LOCAL_STATIC_JAVA_LIBRARIES := \
+ SystemUI-statsd \
SystemUISharedLib \
launcherprotosnano \
launcher_log_protos_lite
diff --git a/protos/launcher_atom.proto b/protos/launcher_atom.proto
index a89fe5c..cac2d8f 100644
--- a/protos/launcher_atom.proto
+++ b/protos/launcher_atom.proto
@@ -23,9 +23,10 @@
message ItemInfo {
oneof Item {
Application application = 1;
- Task task= 2;
+ Task task = 2;
Shortcut shortcut = 3;
Widget widget = 4;
+ FolderIcon folder_icon = 9;
}
// When used for launch event, stores the global predictive rank
optional int32 rank = 5;
@@ -34,13 +35,23 @@
optional bool is_work = 6;
// Item can be child node to parent container or parent containers (nested)
- oneof Container {
- WorkspaceContainer workspace = 7;
- HotseatContainer hotseat = 8;
- FolderContainer folder = 9;
- }
+ optional ContainerInfo container_info = 7;
+
// Stores the origin of the Item
- optional Origin source = 10;
+ optional Origin source = 8;
+}
+
+// Represents various launcher surface where items are placed.
+message ContainerInfo {
+ oneof Container {
+ WorkspaceContainer workspace = 1;
+ HotseatContainer hotseat = 2;
+ FolderContainer folder = 3;
+ AllAppsContainer all_apps_container = 4;
+ }
+}
+
+message AllAppsContainer {
}
enum Origin {
@@ -68,8 +79,8 @@
// AppWidgets handled by AppWidgetManager
message Widget {
- optional int32 span_x = 1;
- optional int32 span_y = 2;
+ optional int32 span_x = 1 [default = 1];
+ optional int32 span_y = 2 [default = 1];
optional int32 app_widget_id = 3;
optional string package_name = 4; // only populated during snapshot if from workspace
optional string component_name = 5; // only populated during snapshot if from workspace
@@ -82,13 +93,18 @@
optional int32 index = 3;
}
+// Represents folder in a closed state.
+message FolderIcon {
+ optional int32 cardinality = 1;
+}
+
//////////////////////////////////////////////
// Containers
message WorkspaceContainer {
- optional int32 page_index = 1; // range [-1, l], 0 is the index of the main homescreen
- optional int32 grid_x = 2; // [0, m], m varies based on the display density and resolution
- optional int32 grid_y = 3; // [0, n], n varies based on the display density and resolution
+ optional int32 page_index = 1 [default = -2]; // range [-1, l], 0 is the index of the main homescreen
+ optional int32 grid_x = 2 [default = -1]; // [0, m], m varies based on the display density and resolution
+ optional int32 grid_y = 3 [default = -1]; // [0, n], n varies based on the display density and resolution
}
message HotseatContainer {
@@ -96,13 +112,11 @@
}
message FolderContainer {
- optional int32 page_index = 1;
- optional int32 grid_x = 2;
- optional int32 grid_y = 3;
- oneof Container {
+ optional int32 page_index = 1 [default = -1];
+ optional int32 grid_x = 2 [default = -1];
+ optional int32 grid_y = 3 [default = -1];
+ oneof ParentContainer {
WorkspaceContainer workspace = 4;
HotseatContainer hotseat = 5;
}
}
-
-
diff --git a/quickstep/recents_ui_overrides/res/layout/predicted_hotseat_edu.xml b/quickstep/recents_ui_overrides/res/layout/predicted_hotseat_edu.xml
index c93cad6..b9621e4 100644
--- a/quickstep/recents_ui_overrides/res/layout/predicted_hotseat_edu.xml
+++ b/quickstep/recents_ui_overrides/res/layout/predicted_hotseat_edu.xml
@@ -24,13 +24,13 @@
<View
android:layout_width="match_parent"
android:layout_height="32dp"
- android:backgroundTint="?android:attr/colorAccent"
+ android:backgroundTint="?attr/eduHalfSheetBGColor"
android:background="@drawable/bottom_sheet_top_border" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:background="?android:attr/colorAccent"
+ android:background="?attr/eduHalfSheetBGColor"
android:orientation="vertical">
<TextView
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 79b4002..c037e44 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
@@ -16,40 +16,24 @@
package com.android.launcher3;
-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.DEACCEL_3;
import static com.android.launcher3.anim.Interpolators.LINEAR;
-import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2;
-import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE;
-import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_SCALE;
-import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_TRANSLATE;
-import static com.android.launcher3.states.StateAnimationConfig.ANIM_VERTICAL_PROGRESS;
import static com.android.quickstep.TaskViewUtils.findTaskViewToLaunch;
import static com.android.quickstep.TaskViewUtils.getRecentsWindowAnimator;
-import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_OFFSET;
import android.animation.Animator;
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;
-import com.android.launcher3.states.StateAnimationConfig;
-import com.android.quickstep.util.AppWindowAnimationHelper;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
@@ -60,13 +44,6 @@
*/
public final class LauncherAppTransitionManagerImpl extends QuickstepAppTransitionManagerImpl {
- public static final int INDEX_SHELF_ANIM = 0;
- public static final int INDEX_RECENTS_FADE_ANIM = 1;
- public static final int INDEX_RECENTS_TRANSLATE_X_ANIM = 2;
- public static final int INDEX_PAUSE_TO_OVERVIEW_ANIM = 3;
-
- public static final long ATOMIC_DURATION_FROM_PAUSED_TO_OVERVIEW = 300;
-
public LauncherAppTransitionManagerImpl(Context context) {
super(context);
}
@@ -86,11 +63,8 @@
boolean skipLauncherChanges = !launcherClosing;
TaskView taskView = findTaskViewToLaunch(mLauncher, v, appTargets);
-
- AppWindowAnimationHelper helper =
- new AppWindowAnimationHelper(recentsView.getPagedViewOrientedState(), mLauncher);
Animator recentsAnimator = getRecentsWindowAnimator(taskView, skipLauncherChanges,
- appTargets, wallpaperTargets, mLauncher.getDepthController(), helper);
+ appTargets, wallpaperTargets, mLauncher.getDepthController());
anim.play(recentsAnimator.setDuration(RECENTS_LAUNCH_DURATION));
Animator childStateAnimation = null;
@@ -98,7 +72,7 @@
Animator launcherAnim;
final AnimatorListenerAdapter windowAnimEndListener;
if (launcherClosing) {
- launcherAnim = recentsView.createAdjacentPageAnimForTaskLaunch(taskView, helper);
+ launcherAnim = recentsView.createAdjacentPageAnimForTaskLaunch(taskView);
launcherAnim.setInterpolator(Interpolators.TOUCH_RESPONSE_INTERPOLATOR);
launcherAnim.setDuration(RECENTS_LAUNCH_DURATION);
@@ -151,80 +125,8 @@
return () -> {
overview.setFreezeViewVisibility(false);
+ overview.setTranslationY(0);
mLauncher.getStateManager().reapplyState();
};
}
-
- @Override
- public int getStateElementAnimationsCount() {
- return 4;
- }
-
- @Override
- public Animator createStateElementAnimation(int index, float... values) {
- switch (index) {
- 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);
- case INDEX_RECENTS_TRANSLATE_X_ANIM: {
- RecentsView rv = mLauncher.getOverviewPanel();
- return new SpringAnimationBuilder(mLauncher)
- .setMinimumVisibleChange(1f / rv.getPageOffsetScale())
- .setDampingRatio(0.8f)
- .setStiffness(250)
- .setValues(values)
- .build(rv, ADJACENT_PAGE_OFFSET);
- }
- case INDEX_PAUSE_TO_OVERVIEW_ANIM: {
- StateAnimationConfig config = new StateAnimationConfig();
- config.duration = ATOMIC_DURATION_FROM_PAUSED_TO_OVERVIEW;
-
- config.setInterpolator(ANIM_VERTICAL_PROGRESS, OVERSHOOT_1_2);
- config.setInterpolator(ANIM_ALL_APPS_FADE, DEACCEL_3);
- if ((OVERVIEW.getVisibleElements(mLauncher) & HOTSEAT_ICONS) != 0) {
- config.setInterpolator(ANIM_HOTSEAT_SCALE, OVERSHOOT_1_2);
- config.setInterpolator(ANIM_HOTSEAT_TRANSLATE, OVERSHOOT_1_2);
- }
-
-
- LauncherStateManager stateManager = mLauncher.getStateManager();
- return stateManager.createAtomicAnimation(
- stateManager.getCurrentStableState(), OVERVIEW, config);
- }
-
- default:
- return super.createStateElementAnimation(index, values);
- }
- }
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/AllAppsTipView.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/AllAppsTipView.java
index d93aea4..8477b10 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/AllAppsTipView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/AllAppsTipView.java
@@ -26,10 +26,10 @@
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
-import com.android.launcher3.LauncherStateManager;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.allapps.FloatingHeaderView;
+import com.android.launcher3.statemanager.StateManager.StateListener;
import com.android.launcher3.views.ArrowTipView;
import com.android.systemui.shared.system.LauncherEventUtil;
@@ -71,17 +71,16 @@
public static void scheduleShowIfNeeded(Launcher launcher) {
if (!hasSeenAllAppsTip(launcher)) {
- launcher.getStateManager().addStateListener(
- new LauncherStateManager.StateListener() {
- @Override
- public void onStateTransitionComplete(LauncherState finalState) {
- if (finalState == ALL_APPS) {
- if (showAllAppsTipIfNecessary(launcher)) {
- launcher.getStateManager().removeStateListener(this);
- }
- }
+ launcher.getStateManager().addStateListener(new StateListener<LauncherState>() {
+ @Override
+ public void onStateTransitionComplete(LauncherState finalState) {
+ if (finalState == ALL_APPS) {
+ if (showAllAppsTipIfNecessary(launcher)) {
+ launcher.getStateManager().removeStateListener(this);
}
- });
+ }
+ }
+ });
}
}
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/AppsDividerView.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/AppsDividerView.java
index 81a6070..914d9e9 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/AppsDividerView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/AppsDividerView.java
@@ -38,18 +38,18 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
-import com.android.launcher3.LauncherStateManager;
import com.android.launcher3.R;
import com.android.launcher3.allapps.FloatingHeaderRow;
import com.android.launcher3.allapps.FloatingHeaderView;
import com.android.launcher3.anim.PropertySetter;
+import com.android.launcher3.statemanager.StateManager.StateListener;
import com.android.launcher3.util.Themes;
/**
* A view which shows a horizontal divider
*/
@TargetApi(Build.VERSION_CODES.O)
-public class AppsDividerView extends View implements LauncherStateManager.StateListener,
+public class AppsDividerView extends View implements StateListener<LauncherState>,
FloatingHeaderRow {
private static final String ALL_APPS_VISITED_COUNT = "launcher.all_apps_visited_count";
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 e68627a..ab3c71a 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
@@ -32,7 +32,6 @@
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;
import com.android.launcher3.allapps.AllAppsContainerView;
import com.android.launcher3.allapps.AllAppsStore.OnUpdateListener;
@@ -41,6 +40,7 @@
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.shortcuts.ShortcutKey;
+import com.android.launcher3.statemanager.StateManager.StateListener;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.MainThreadInitializedObject;
@@ -63,8 +63,8 @@
* 4) Maintains the current active client id (for the predictions) and all updates are performed on
* that client id.
*/
-public class PredictionUiStateManager implements StateListener, ItemInfoUpdateReceiver,
- OnIDPChangeListener, OnUpdateListener {
+public class PredictionUiStateManager implements StateListener<LauncherState>,
+ ItemInfoUpdateReceiver, OnIDPChangeListener, OnUpdateListener {
public static final String LAST_PREDICTION_ENABLED_STATE = "last_prediction_enabled_state";
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduController.java
index 78cc2dc..7f8f0a0 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduController.java
@@ -48,6 +48,7 @@
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.List;
+import java.util.stream.IntStream;
/**
* Controller class for managing user onboaridng flow for hybrid hotseat
@@ -110,7 +111,8 @@
ItemInfo info = (ItemInfo) view.getTag();
if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) {
folders.add((FolderInfo) info);
- } else if (info instanceof WorkspaceItemInfo) {
+ } else if (info instanceof WorkspaceItemInfo && info.container == LauncherSettings
+ .Favorites.CONTAINER_HOTSEAT) {
putIntoFolder.add((WorkspaceItemInfo) info);
}
}
@@ -206,6 +208,7 @@
View child = mHotseat.getChildAt(i, 0);
if (child == null || child.getTag() == null) continue;
ItemInfo tag = (ItemInfo) child.getTag();
+ if (tag.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION) continue;
mLauncher.getModelWriter().moveItemInDatabase(tag,
LauncherSettings.Favorites.CONTAINER_DESKTOP, pageId, i, toRow);
mNewItems.add(tag);
@@ -300,13 +303,23 @@
}
void showEdu() {
+ int childCount = mHotseat.getShortcutsAndWidgets().getChildCount();
+ CellLayout cellLayout = mLauncher.getWorkspace().getScreenWithId(Workspace.FIRST_SCREEN_ID);
// hotseat is already empty and does not require migration. show edu tip
- if (mHotseat.getShortcutsAndWidgets().getChildCount() == 0) {
- new ArrowTipView(mLauncher).show(mLauncher.getString(R.string.hotseat_auto_enrolled),
+ boolean requiresMigration = IntStream.range(0, childCount).anyMatch(i -> {
+ View v = mHotseat.getShortcutsAndWidgets().getChildAt(i);
+ return v != null && v.getTag() != null && ((ItemInfo) v.getTag()).container
+ != LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
+ });
+ boolean canMigrateToFirstPage = cellLayout.makeSpaceForHotseatMigration(false);
+ if (requiresMigration && canMigrateToFirstPage) {
+ showDialog();
+ } else {
+ new ArrowTipView(mLauncher).show(mLauncher.getString(
+ requiresMigration ? R.string.hotseat_tip_no_empty_slots
+ : R.string.hotseat_auto_enrolled),
mHotseat.getTop());
finishOnboarding();
- } else {
- showDialog();
}
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
index 1aff8e9..e9f3534 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
@@ -16,9 +16,6 @@
package com.android.launcher3.hybridhotseat;
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
-import static com.android.launcher3.logging.LoggerUtils.newAction;
-import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
-import static com.android.launcher3.logging.LoggerUtils.newLauncherEvent;
import android.animation.Animator;
import android.animation.AnimatorSet;
@@ -32,7 +29,6 @@
import android.content.ComponentName;
import android.os.Bundle;
import android.os.Process;
-import android.provider.DeviceConfig;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
@@ -47,6 +43,7 @@
import com.android.launcher3.Hotseat;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.LauncherState;
import com.android.launcher3.R;
@@ -60,7 +57,7 @@
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.icons.IconCache;
import com.android.launcher3.logging.FileLog;
-import com.android.launcher3.logging.UserEventDispatcher;
+import com.android.launcher3.model.PredictionModel;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
@@ -70,12 +67,13 @@
import com.android.launcher3.popup.SystemShortcut;
import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.touch.ItemLongClickListener;
-import com.android.launcher3.uioverrides.DeviceFlag;
import com.android.launcher3.uioverrides.PredictedAppIcon;
import com.android.launcher3.uioverrides.QuickstepLauncher;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.util.ComponentKey;
+import com.android.launcher3.util.IntArray;
+import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -98,8 +96,6 @@
//TODO: replace this with AppTargetEvent.ACTION_UNPIN (b/144119543)
private static final int APPTARGET_ACTION_UNPIN = 4;
- private static final String PREDICTED_ITEMS_CACHE_KEY = "predicted_item_keys";
-
private static final String APP_LOCATION_HOTSEAT = "hotseat";
private static final String APP_LOCATION_WORKSPACE = "workspace";
@@ -120,11 +116,13 @@
private DynamicItemCache mDynamicItemCache;
+ private final PredictionModel mPredictionModel;
private AppPredictor mAppPredictor;
private AllAppsStore mAllAppsStore;
private AnimatorSet mIconRemoveAnimators;
private boolean mUIUpdatePaused = false;
- private boolean mRequiresCacheUpdate = false;
+ private boolean mRequiresCacheUpdate = true;
+ private boolean mIsCacheEmpty;
private HotseatEduController mHotseatEduController;
@@ -143,21 +141,22 @@
mLauncher = launcher;
mHotseat = launcher.getHotseat();
mAllAppsStore = mLauncher.getAppsView().getAppsStore();
+ mPredictionModel = LauncherAppState.INSTANCE.get(launcher).getPredictionModel();
mAllAppsStore.addUpdateListener(this);
mDynamicItemCache = new DynamicItemCache(mLauncher, this::fillGapsWithPrediction);
mHotSeatItemsCount = mLauncher.getDeviceProfile().inv.numHotseatIcons;
launcher.getDeviceProfile().inv.addOnChangeListener(this);
mHotseat.addOnAttachStateChangeListener(this);
+ mIsCacheEmpty = mPredictionModel.getPredictionComponentKeys().isEmpty();
if (mHotseat.isAttachedToWindow()) {
onViewAttachedToWindow(mHotseat);
}
- showCachedItems();
}
/**
- * Returns whether or not the prediction controller is ready to show predictions
+ * Returns whether or not user has seen hybrid hotseat education
*/
- public boolean isReady() {
+ public boolean isEduSeen() {
return mLauncher.getSharedPrefs().getBoolean(HotseatEduController.KEY_HOTSEAT_EDU_SEEN,
false);
}
@@ -186,10 +185,15 @@
}
private void fillGapsWithPrediction(boolean animate, Runnable callback) {
- if (!isReady() || mUIUpdatePaused || mDragObject != null) {
+ if (mUIUpdatePaused || mDragObject != null) {
return;
}
List<WorkspaceItemInfo> predictedApps = mapToWorkspaceItemInfo(mComponentKeyMappers);
+ if (mComponentKeyMappers.isEmpty() != predictedApps.isEmpty()) {
+ // Safely ignore update as AppsList is not ready yet. This will called again once
+ // apps are ready (HotseatPredictionController#onAppsUpdated)
+ return;
+ }
int predictionIndex = 0;
ArrayList<WorkspaceItemInfo> newItems = new ArrayList<>();
// make sure predicted icon removal and filling predictions don't step on each other
@@ -262,6 +266,10 @@
if (mAppPredictor != null) {
mAppPredictor.destroy();
}
+ if (mHotseatEduController != null) {
+ mHotseatEduController.destroy();
+ mHotseatEduController = null;
+ }
}
/**
@@ -291,24 +299,38 @@
.setPredictedTargetCount(mHotSeatItemsCount)
.setExtras(getAppPredictionContextExtra())
.build());
- mAppPredictor.registerPredictionUpdates(mLauncher.getMainExecutor(),
- this::setPredictedApps);
+ WeakReference<HotseatPredictionController> controllerRef = new WeakReference<>(this);
+ mAppPredictor.registerPredictionUpdates(mLauncher.getApplicationContext().getMainExecutor(),
+ list -> {
+ if (controllerRef.get() != null) {
+ controllerRef.get().setPredictedApps(list);
+ }
+ });
+
setPauseUIUpdate(false);
- performBetaCheck();
- if (!isReady()) {
+ if (!isEduSeen()) {
mHotseatEduController = new HotseatEduController(mLauncher, this::createPredictor);
}
mAppPredictor.requestPredictionUpdate();
}
- private void showCachedItems() {
- ArrayList<ComponentKey> componentKeys = getCachedComponentKeys();
+ /**
+ * Create WorkspaceItemInfo objects and binds PredictedAppIcon views for cached predicted items.
+ */
+ public void showCachedItems(List<AppInfo> apps, IntArray ranks) {
+ int count = Math.min(ranks.size(), apps.size());
+ List<WorkspaceItemInfo> items = new ArrayList<>(count);
+ for (int i = 0; i < count; i++) {
+ WorkspaceItemInfo item = new WorkspaceItemInfo(apps.get(i));
+ preparePredictionInfo(item, ranks.get(i));
+ items.add(item);
+ }
mComponentKeyMappers.clear();
- for (ComponentKey key : componentKeys) {
+ for (ComponentKey key : mPredictionModel.getPredictionComponentKeys()) {
mComponentKeyMappers.add(new ComponentKeyMapper(key, mDynamicItemCache));
}
updateDependencies();
- fillGapsWithPrediction();
+ bindItems(items, false, null);
}
private Bundle getAppPredictionContextExtra() {
@@ -386,42 +408,20 @@
predictionLog.append("]");
if (Utilities.IS_DEBUG_DEVICE) FileLog.d(TAG, predictionLog.toString());
updateDependencies();
- if (isReady()) {
- fillGapsWithPrediction();
- } else if (mHotseatEduController != null) {
+ fillGapsWithPrediction();
+ if (!isEduSeen() && mHotseatEduController != null) {
mHotseatEduController.setPredictedApps(mapToWorkspaceItemInfo(mComponentKeyMappers));
}
- // should invalidate cache if AiAi sends empty list of AppTargets
- if (appTargets.isEmpty()) {
- mRequiresCacheUpdate = true;
- }
- cachePredictionComponentKeys(componentKeys);
+ cachePredictionComponentKeysIfNecessary(componentKeys);
}
- private void cachePredictionComponentKeys(ArrayList<ComponentKey> componentKeys) {
- if (!mRequiresCacheUpdate) return;
- StringBuilder builder = new StringBuilder();
- for (ComponentKey componentKey : componentKeys) {
- builder.append(componentKey);
- builder.append("\n");
- }
- mLauncher.getDevicePrefs().edit().putString(PREDICTED_ITEMS_CACHE_KEY,
- builder.toString()).apply();
+ private void cachePredictionComponentKeysIfNecessary(ArrayList<ComponentKey> componentKeys) {
+ if (!mRequiresCacheUpdate && componentKeys.isEmpty() == mIsCacheEmpty) return;
+ mPredictionModel.cachePredictionComponentKeys(componentKeys);
+ mIsCacheEmpty = componentKeys.isEmpty();
mRequiresCacheUpdate = false;
}
- private ArrayList<ComponentKey> getCachedComponentKeys() {
- String cachedBlob = mLauncher.getDevicePrefs().getString(PREDICTED_ITEMS_CACHE_KEY, "");
- ArrayList<ComponentKey> results = new ArrayList<>();
- for (String line : cachedBlob.split("\n")) {
- ComponentKey key = ComponentKey.fromString(line);
- if (key != null) {
- results.add(key);
- }
- }
- return results;
- }
-
private void updateDependencies() {
mDynamicItemCache.updateDependencies(mComponentKeyMappers, mAllAppsStore, this,
mHotSeatItemsCount);
@@ -682,42 +682,6 @@
}
}
- private void performBetaCheck() {
- if (isReady()) return;
- int hotseatItemsCount = mHotseat.getShortcutsAndWidgets().getChildCount();
-
- int maxItems = DeviceConfig.getInt(
- DeviceFlag.NAMESPACE_LAUNCHER, "max_homepage_items_for_migration", 5);
-
- // -1 to exclude smart space
- int workspaceItemCount = mLauncher.getWorkspace().getScreenWithId(
- Workspace.FIRST_SCREEN_ID).getShortcutsAndWidgets().getChildCount() - 1;
-
- // opt user into the feature without onboarding tip or migration if they don't have any
- // open spots in their hotseat and have more than maxItems in their hotseat + workspace
-
- if (hotseatItemsCount == mHotSeatItemsCount && workspaceItemCount + hotseatItemsCount
- > maxItems) {
- mLauncher.getSharedPrefs().edit().putBoolean(HotseatEduController.KEY_HOTSEAT_EDU_SEEN,
- true).apply();
-
- LauncherLogProto.Action action = newAction(LauncherLogProto.Action.Type.TOUCH);
- LauncherLogProto.Target target = newContainerTarget(LauncherLogProto.ContainerType.TIP);
- action.touch = LauncherLogProto.Action.Touch.TAP;
- target.tipType = LauncherLogProto.TipType.HYBRID_HOTSEAT;
- target.controlType = LauncherLogProto.ControlType.HYBRID_HOTSEAT_CANCELED;
-
- // temporarily encode details in log target (go/hotseat_migration)
- target.rank = 2;
- target.cardinality = (workspaceItemCount * 1000) + hotseatItemsCount;
- target.pageIndex = maxItems;
- LauncherLogProto.LauncherEvent event = newLauncherEvent(action, target);
- UserEventDispatcher.newInstance(mLauncher).dispatchUserEvent(event, null);
-
-
- }
- }
-
/**
* Fill in predicted_rank field based on app prediction.
* Only applicable when {@link ItemInfo#itemType} is PREDICTED_HOTSEAT
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 e074b03..6cfc846 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
@@ -15,14 +15,22 @@
*/
package com.android.launcher3.uioverrides;
+import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_FOCUSED;
+
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.LauncherState.OVERVIEW_MODAL_TASK;
+import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent;
+import static com.android.launcher3.testing.TestProtocol.HINT_STATE_ORDINAL;
+import static com.android.launcher3.testing.TestProtocol.OVERVIEW_STATE_ORDINAL;
+import static com.android.launcher3.testing.TestProtocol.QUICK_SWITCH_STATE_ORDINAL;
+import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle;
+import android.util.Log;
import android.view.View;
import androidx.annotation.Nullable;
@@ -31,13 +39,19 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
+import com.android.launcher3.Workspace;
+import com.android.launcher3.allapps.DiscoveryBounce;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.folder.Folder;
import com.android.launcher3.hybridhotseat.HotseatPredictionController;
+import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.popup.SystemShortcut;
+import com.android.launcher3.statemanager.StateManager.AtomicAnimationFactory;
+import com.android.launcher3.testing.TestProtocol;
+import com.android.launcher3.uioverrides.states.QuickstepAtomicAnimationFactory;
import com.android.launcher3.uioverrides.touchcontrollers.FlingAndHoldTouchController;
import com.android.launcher3.uioverrides.touchcontrollers.LandscapeEdgeSwipeController;
import com.android.launcher3.uioverrides.touchcontrollers.NavBarToHomeTouchController;
@@ -49,6 +63,7 @@
import com.android.launcher3.uioverrides.touchcontrollers.StatusBarTouchController;
import com.android.launcher3.uioverrides.touchcontrollers.TaskViewTouchController;
import com.android.launcher3.uioverrides.touchcontrollers.TransposedQuickSwitchTouchController;
+import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.TouchController;
import com.android.launcher3.util.UiThreadHelper;
import com.android.launcher3.util.UiThreadHelper.AsyncCommand;
@@ -56,8 +71,12 @@
import com.android.quickstep.SysUINavigationMode.Mode;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.views.RecentsView;
+import com.android.quickstep.views.TaskView;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.List;
import java.util.stream.Stream;
public class QuickstepLauncher extends BaseQuickstepLauncher {
@@ -166,15 +185,70 @@
}
@Override
+ public void bindPredictedItems(List<AppInfo> appInfos, IntArray ranks) {
+ super.bindPredictedItems(appInfos, ranks);
+ if (mHotseatPredictionController != null) {
+ mHotseatPredictionController.showCachedItems(appInfos, ranks);
+ }
+ }
+
+ @Override
public void onDestroy() {
super.onDestroy();
if (mHotseatPredictionController != null) {
mHotseatPredictionController.destroy();
+ mHotseatPredictionController = null;
+ }
+ }
+
+ @Override
+ public void onStateSetEnd(LauncherState state) {
+ super.onStateSetEnd(state);
+
+ switch (state.ordinal) {
+ case HINT_STATE_ORDINAL: {
+ Workspace workspace = getWorkspace();
+ boolean willMoveScreens = workspace.getNextPage() != Workspace.DEFAULT_PAGE;
+ getStateManager().goToState(NORMAL, true,
+ willMoveScreens ? null : getScrimView()::startDragHandleEducationAnim);
+ if (willMoveScreens) {
+ workspace.post(workspace::moveToDefaultScreen);
+ }
+ break;
+ }
+ case OVERVIEW_STATE_ORDINAL: {
+ DiscoveryBounce.showForOverviewIfNeeded(this);
+ RecentsView rv = getOverviewPanel();
+ sendCustomAccessibilityEvent(
+ rv.getPageAt(rv.getCurrentPage()), TYPE_VIEW_FOCUSED, null);
+ break;
+ }
+ case QUICK_SWITCH_STATE_ORDINAL: {
+ RecentsView rv = getOverviewPanel();
+ TaskView tasktolaunch = rv.getTaskViewAt(0);
+ if (tasktolaunch != null) {
+ tasktolaunch.launchTask(false, success -> {
+ if (!success) {
+ getStateManager().goToState(OVERVIEW);
+ tasktolaunch.notifyTaskLaunchFailed(TAG);
+ } else {
+ getStateManager().moveToRestState();
+ }
+ }, MAIN_EXECUTOR.getHandler());
+ } else {
+ getStateManager().goToState(NORMAL);
+ }
+ break;
+ }
+
}
}
@Override
public TouchController[] createTouchControllers() {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.PAUSE_NOT_DETECTED, "createTouchControllers.1");
+ }
Mode mode = SysUINavigationMode.getMode(this);
ArrayList<TouchController> list = new ArrayList<>();
@@ -182,7 +256,13 @@
if (mode == NO_BUTTON) {
list.add(new NoButtonQuickSwitchTouchController(this));
list.add(new NavBarToHomeTouchController(this));
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.PAUSE_NOT_DETECTED, "createTouchControllers.2");
+ }
if (FeatureFlags.ENABLE_OVERVIEW_ACTIONS.get()) {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.PAUSE_NOT_DETECTED, "createTouchControllers.3");
+ }
list.add(new NoButtonNavbarToOverviewTouchController(this));
} else {
list.add(new FlingAndHoldTouchController(this));
@@ -211,6 +291,11 @@
return list.toArray(new TouchController[list.size()]);
}
+ @Override
+ public AtomicAnimationFactory createAtomicAnimationFactory() {
+ return new QuickstepAtomicAnimationFactory(this);
+ }
+
private static final class LauncherTaskViewController extends
TaskViewTouchController<Launcher> {
@@ -233,4 +318,13 @@
mActivity.getStateManager().setCurrentUserControlledAnimation(animController);
}
}
+
+ @Override
+ public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
+ super.dump(prefix, fd, writer, args);
+ RecentsView recentsView = getOverviewPanel();
+ writer.println("\nQuickstepLauncher:");
+ writer.println(prefix + "\tmOrientationState: " + (recentsView == null ? "recentsNull" :
+ recentsView.getPagedViewOrientedState()));
+ }
}
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 e57e841..fa0d3f3 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
@@ -17,22 +17,20 @@
import android.content.Context;
-import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.Launcher;
import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.quickstep.util.LayoutUtils;
import com.android.quickstep.views.RecentsView;
-import com.android.quickstep.views.TaskView;
/**
* State indicating that the Launcher is behind an app
*/
public class BackgroundAppState extends OverviewState {
- private static final int STATE_FLAGS =
- FLAG_DISABLE_RESTORE | FLAG_OVERVIEW_UI | FLAG_DISABLE_ACCESSIBILITY
- | FLAG_DISABLE_INTERACTION;
+ private static final int STATE_FLAGS = FLAG_DISABLE_RESTORE | FLAG_OVERVIEW_UI
+ | FLAG_WORKSPACE_INACCESSIBLE | FLAG_NON_INTERACTIVE | FLAG_CLOSE_POPUPS;
public BackgroundAppState(int id) {
this(id, LauncherLogProto.ContainerType.TASKSWITCHER);
@@ -43,11 +41,6 @@
}
@Override
- public void onStateEnabled(Launcher launcher) {
- AbstractFloatingView.closeAllOpenViews(launcher, false);
- }
-
- @Override
public float getVerticalProgress(Launcher launcher) {
if (launcher.getDeviceProfile().isVerticalBarLayout()) {
return super.getVerticalProgress(launcher);
@@ -62,27 +55,7 @@
@Override
public float[] getOverviewScaleAndOffset(Launcher launcher) {
- return new float[] {getOverviewScale(launcher), NO_OFFSET};
- }
-
- private float getOverviewScale(Launcher launcher) {
- // Initialize the recents view scale to what it would be when starting swipe up
- RecentsView recentsView = launcher.getOverviewPanel();
- int taskCount = recentsView.getTaskViewCount();
- if (taskCount == 0) return 1;
-
- TaskView dummyTask;
- if (recentsView.getCurrentPage() >= recentsView.getTaskViewStartIndex()) {
- if (recentsView.getCurrentPage() <= taskCount - 1) {
- dummyTask = recentsView.getCurrentPageTaskView();
- } else {
- dummyTask = recentsView.getTaskViewAt(taskCount - 1);
- }
- } else {
- dummyTask = recentsView.getTaskViewAt(0);
- }
- return recentsView.getTempAppWindowAnimationHelper()
- .updateForFullscreenOverview(dummyTask).getSrcToTargetScale();
+ return getOverviewScaleAndOffsetForBackgroundState(launcher);
}
@Override
@@ -112,4 +85,11 @@
protected float getDepthUnchecked(Context context) {
return 1f;
}
+
+ public static float[] getOverviewScaleAndOffsetForBackgroundState(
+ BaseDraggingActivity activity) {
+ return new float[] {
+ ((RecentsView) activity.getOverviewPanel()).getMaxScaleForFullScreen(),
+ NO_OFFSET};
+ }
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java
index b238200..414d389 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java
@@ -15,9 +15,11 @@
*/
package com.android.launcher3.uioverrides.states;
+import android.content.Context;
import android.content.res.Resources;
import android.graphics.Rect;
+import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
@@ -30,15 +32,15 @@
public class OverviewModalTaskState extends OverviewState {
private static final int STATE_FLAGS =
- FLAG_DISABLE_RESTORE | FLAG_OVERVIEW_UI | FLAG_DISABLE_ACCESSIBILITY;
+ FLAG_DISABLE_RESTORE | FLAG_OVERVIEW_UI | FLAG_WORKSPACE_INACCESSIBLE;
public OverviewModalTaskState(int id) {
super(id, ContainerType.OVERVIEW, STATE_FLAGS);
}
@Override
- public int getTransitionDuration(Launcher launcher) {
- return 100;
+ public int getTransitionDuration(Context launcher) {
+ return 300;
}
@Override
@@ -48,22 +50,25 @@
@Override
public float[] getOverviewScaleAndOffset(Launcher launcher) {
- Resources res = launcher.getBaseContext().getResources();
-
- Rect out = new Rect();
- launcher.<RecentsView>getOverviewPanel().getTaskSize(out);
- int taskHeight = out.height();
-
- float topMargin = res.getDimension(R.dimen.task_thumbnail_top_margin);
- float bottomMargin = res.getDimension(R.dimen.task_thumbnail_bottom_margin_with_actions);
- float newHeight = taskHeight + topMargin + bottomMargin;
- float scale = newHeight / taskHeight;
-
- return new float[] {scale, 0};
+ return getOverviewScaleAndOffsetForModalState(launcher);
}
@Override
public float getOverviewModalness() {
return 1.0f;
}
+
+ public static float[] getOverviewScaleAndOffsetForModalState(BaseDraggingActivity activity) {
+ Resources res = activity.getResources();
+
+ Rect out = new Rect();
+ activity.<RecentsView>getOverviewPanel().getTaskSize(out);
+ int taskHeight = out.height();
+ float topMargin = res.getDimension(R.dimen.task_thumbnail_top_margin);
+ float bottomMargin = res.getDimension(R.dimen.overview_actions_top_margin);
+ float newHeight = taskHeight + topMargin + bottomMargin;
+ float scale = newHeight / taskHeight;
+
+ return new float[] {scale, NO_OFFSET};
+ }
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewPeekState.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewPeekState.java
index b27f16a..fc9a11b 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewPeekState.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewPeekState.java
@@ -15,16 +15,7 @@
*/
package com.android.launcher3.uioverrides.states;
-import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
-import static com.android.launcher3.anim.Interpolators.INSTANT;
-import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_7;
-import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_FADE;
-import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCRIM_FADE;
-import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_X;
-
import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherState;
-import com.android.launcher3.states.StateAnimationConfig;
public class OverviewPeekState extends OverviewState {
private static final float OVERVIEW_OFFSET = 0.7f;
@@ -37,14 +28,4 @@
public float[] getOverviewScaleAndOffset(Launcher launcher) {
return new float[] {NO_SCALE, OVERVIEW_OFFSET};
}
-
- @Override
- public void prepareForAtomicAnimation(Launcher launcher, LauncherState fromState,
- StateAnimationConfig config) {
- if (this == OVERVIEW_PEEK && fromState == NORMAL) {
- config.setInterpolator(ANIM_OVERVIEW_FADE, INSTANT);
- config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, OVERSHOOT_1_7);
- config.setInterpolator(ANIM_OVERVIEW_SCRIM_FADE, FAST_OUT_SLOW_IN);
- }
- }
}
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 fad9ea5..9f31608 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
@@ -15,40 +15,21 @@
*/
package com.android.launcher3.uioverrides.states;
-import static android.view.View.VISIBLE;
-
-import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
-import static com.android.launcher3.anim.Interpolators.ACCEL;
import static com.android.launcher3.anim.Interpolators.DEACCEL_2;
-import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2;
-import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_7;
import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS;
import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
-import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_FADE;
-import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE;
-import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_X;
-import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_Y;
-import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_FADE;
-import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_SCALE;
-import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_TRANSLATE;
import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview;
import android.content.Context;
import android.graphics.Rect;
import android.view.View;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.animation.Interpolator;
-import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.R;
import com.android.launcher3.Workspace;
-import com.android.launcher3.allapps.DiscoveryBounce;
-import com.android.launcher3.compat.AccessibilityManagerCompat;
-import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.quickstep.SysUINavigationMode;
@@ -61,13 +42,11 @@
*/
public class OverviewState extends LauncherState {
- // Scale recents takes before animating in
- private static final float RECENTS_PREPARE_SCALE = 1.33f;
-
protected static final Rect sTempRect = new Rect();
private static final int STATE_FLAGS = FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED
- | FLAG_DISABLE_RESTORE | FLAG_OVERVIEW_UI | FLAG_DISABLE_ACCESSIBILITY;
+ | FLAG_DISABLE_RESTORE | FLAG_OVERVIEW_UI | FLAG_WORKSPACE_INACCESSIBLE
+ | FLAG_CLOSE_POPUPS;
public OverviewState(int id) {
this(id, STATE_FLAGS);
@@ -82,9 +61,9 @@
}
@Override
- public int getTransitionDuration(Launcher launcher) {
+ public int getTransitionDuration(Context context) {
// In no-button mode, overview comes in all the way from the left, so give it more time.
- boolean isNoButtonMode = SysUINavigationMode.INSTANCE.get(launcher).getMode() == NO_BUTTON;
+ boolean isNoButtonMode = SysUINavigationMode.INSTANCE.get(context).getMode() == NO_BUTTON;
return isNoButtonMode && ENABLE_OVERVIEW_ACTIONS.get() ? 380 : 250;
}
@@ -137,20 +116,6 @@
}
@Override
- public void onStateEnabled(Launcher launcher) {
- AbstractFloatingView.closeAllOpenViews(launcher);
- }
-
- @Override
- public void onStateTransitionEnd(Launcher launcher) {
- DiscoveryBounce.showForOverviewIfNeeded(launcher);
- RecentsView recentsView = launcher.getOverviewPanel();
- AccessibilityManagerCompat.sendCustomAccessibilityEvent(
- recentsView.getPageAt(recentsView.getCurrentPage()),
- AccessibilityEvent.TYPE_VIEW_FOCUSED, null);
- }
-
- @Override
public PageAlphaProvider getWorkspacePageAlphaProvider(Launcher launcher) {
return new PageAlphaProvider(DEACCEL_2) {
@Override
@@ -219,35 +184,6 @@
}
}
- @Override
- public void prepareForAtomicAnimation(Launcher launcher, LauncherState fromState,
- StateAnimationConfig config) {
- if ((fromState == NORMAL || fromState == HINT_STATE) && this == OVERVIEW) {
- if (SysUINavigationMode.getMode(launcher) == NO_BUTTON) {
- config.setInterpolator(ANIM_WORKSPACE_SCALE,
- fromState == NORMAL ? ACCEL : OVERSHOOT_1_2);
- config.setInterpolator(ANIM_WORKSPACE_TRANSLATE, ACCEL);
- } else {
- config.setInterpolator(ANIM_WORKSPACE_SCALE, OVERSHOOT_1_2);
-
- // Scale up the recents, if it is not coming from the side
- RecentsView overview = launcher.getOverviewPanel();
- if (overview.getVisibility() != VISIBLE || overview.getContentAlpha() == 0) {
- SCALE_PROPERTY.set(overview, RECENTS_PREPARE_SCALE);
- }
- }
- config.setInterpolator(ANIM_WORKSPACE_FADE, OVERSHOOT_1_2);
- config.setInterpolator(ANIM_OVERVIEW_SCALE, OVERSHOOT_1_2);
- Interpolator translationInterpolator = ENABLE_OVERVIEW_ACTIONS.get()
- && removeShelfFromOverview(launcher)
- ? OVERSHOOT_1_2
- : OVERSHOOT_1_7;
- config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, translationInterpolator);
- config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, translationInterpolator);
- config.setInterpolator(ANIM_OVERVIEW_FADE, OVERSHOOT_1_2);
- }
- }
-
public static OverviewState newBackgroundState(int id) {
return new BackgroundAppState(id);
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java
index 7b4bb02..2c7373e 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java
@@ -15,24 +15,16 @@
*/
package com.android.launcher3.uioverrides.states;
-import android.os.Handler;
-import android.os.Looper;
-
import com.android.launcher3.Launcher;
import com.android.launcher3.userevent.nano.LauncherLogProto;
-import com.android.quickstep.GestureState;
-import com.android.quickstep.views.RecentsView;
-import com.android.quickstep.views.TaskView;
/**
* State to indicate we are about to launch a recent task. Note that this state is only used when
* quick switching from launcher; quick switching from an app uses LauncherSwipeHandler.
- * @see GestureState.GestureEndTarget#NEW_TASK
+ * @see com.android.quickstep.GestureState.GestureEndTarget#NEW_TASK
*/
public class QuickSwitchState extends BackgroundAppState {
- private static final String TAG = "QuickSwitchState";
-
public QuickSwitchState(int id) {
super(id, LauncherLogProto.ContainerType.APP);
}
@@ -49,21 +41,4 @@
public int getVisibleElements(Launcher launcher) {
return NONE;
}
-
- @Override
- public void onStateTransitionEnd(Launcher launcher) {
- TaskView tasktolaunch = launcher.<RecentsView>getOverviewPanel().getTaskViewAt(0);
- if (tasktolaunch != null) {
- tasktolaunch.launchTask(false, success -> {
- if (!success) {
- launcher.getStateManager().goToState(OVERVIEW);
- tasktolaunch.notifyTaskLaunchFailed(TAG);
- } else {
- launcher.getStateManager().moveToRestState();
- }
- }, new Handler(Looper.getMainLooper()));
- } else {
- launcher.getStateManager().goToState(NORMAL);
- }
- }
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
new file mode 100644
index 0000000..11593a1
--- /dev/null
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.uioverrides.states;
+
+import static android.view.View.VISIBLE;
+
+import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
+import static com.android.launcher3.LauncherState.BACKGROUND_APP;
+import static com.android.launcher3.LauncherState.HINT_STATE;
+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.LauncherState.OVERVIEW_PEEK;
+import static com.android.launcher3.anim.Interpolators.ACCEL;
+import static com.android.launcher3.anim.Interpolators.DEACCEL;
+import static com.android.launcher3.anim.Interpolators.DEACCEL_1_7;
+import static com.android.launcher3.anim.Interpolators.DEACCEL_3;
+import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
+import static com.android.launcher3.anim.Interpolators.INSTANT;
+import static com.android.launcher3.anim.Interpolators.LINEAR;
+import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2;
+import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_7;
+import static com.android.launcher3.anim.Interpolators.clampToProgress;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS;
+import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE;
+import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_SCALE;
+import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_TRANSLATE;
+import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_FADE;
+import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE;
+import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCRIM_FADE;
+import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_X;
+import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_Y;
+import static com.android.launcher3.states.StateAnimationConfig.ANIM_VERTICAL_PROGRESS;
+import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_FADE;
+import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_SCALE;
+import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_TRANSLATE;
+import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
+import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview;
+import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_OFFSET;
+
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.view.View;
+import android.view.animation.Interpolator;
+
+import com.android.launcher3.CellLayout;
+import com.android.launcher3.Hotseat;
+import com.android.launcher3.LauncherState;
+import com.android.launcher3.LauncherState.ScaleAndTranslation;
+import com.android.launcher3.Workspace;
+import com.android.launcher3.allapps.AllAppsContainerView;
+import com.android.launcher3.allapps.AllAppsTransitionController;
+import com.android.launcher3.anim.SpringAnimationBuilder;
+import com.android.launcher3.statemanager.StateManager;
+import com.android.launcher3.statemanager.StateManager.AtomicAnimationFactory;
+import com.android.launcher3.states.StateAnimationConfig;
+import com.android.launcher3.uioverrides.QuickstepLauncher;
+import com.android.quickstep.SysUINavigationMode;
+import com.android.quickstep.views.RecentsView;
+
+/**
+ * Animation factory for quickstep specific transitions
+ */
+public class QuickstepAtomicAnimationFactory extends AtomicAnimationFactory<LauncherState> {
+
+ // Scale recents takes before animating in
+ private static final float RECENTS_PREPARE_SCALE = 1.33f;
+
+ public static final int INDEX_SHELF_ANIM = 0;
+ public static final int INDEX_RECENTS_FADE_ANIM = 1;
+ public static final int INDEX_RECENTS_TRANSLATE_X_ANIM = 2;
+ public static final int INDEX_PAUSE_TO_OVERVIEW_ANIM = 3;
+ private static final int ANIM_COUNT = 4;
+
+ public static final long ATOMIC_DURATION_FROM_PAUSED_TO_OVERVIEW = 300;
+
+ private final QuickstepLauncher mLauncher;
+
+ public QuickstepAtomicAnimationFactory(QuickstepLauncher launcher) {
+ super(ANIM_COUNT);
+ mLauncher = launcher;
+ }
+
+ @Override
+ public Animator createStateElementAnimation(int index, float... values) {
+ switch (index) {
+ 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);
+ case INDEX_RECENTS_TRANSLATE_X_ANIM: {
+ RecentsView rv = mLauncher.getOverviewPanel();
+ return new SpringAnimationBuilder(mLauncher)
+ .setMinimumVisibleChange(1f / rv.getPageOffsetScale())
+ .setDampingRatio(0.8f)
+ .setStiffness(250)
+ .setValues(values)
+ .build(rv, ADJACENT_PAGE_OFFSET);
+ }
+ case INDEX_PAUSE_TO_OVERVIEW_ANIM: {
+ StateAnimationConfig config = new StateAnimationConfig();
+ config.duration = ATOMIC_DURATION_FROM_PAUSED_TO_OVERVIEW;
+
+ config.setInterpolator(ANIM_VERTICAL_PROGRESS, OVERSHOOT_1_2);
+ config.setInterpolator(ANIM_ALL_APPS_FADE, DEACCEL_3);
+ if ((OVERVIEW.getVisibleElements(mLauncher) & HOTSEAT_ICONS) != 0) {
+ config.setInterpolator(ANIM_HOTSEAT_SCALE, OVERSHOOT_1_2);
+ config.setInterpolator(ANIM_HOTSEAT_TRANSLATE, OVERSHOOT_1_2);
+ }
+
+ StateManager<LauncherState> stateManager = mLauncher.getStateManager();
+ return stateManager.createAtomicAnimation(
+ stateManager.getCurrentStableState(), OVERVIEW, config);
+ }
+
+ default:
+ return super.createStateElementAnimation(index, values);
+ }
+ }
+
+ @Override
+ public void prepareForAtomicAnimation(LauncherState fromState, LauncherState toState,
+ StateAnimationConfig config) {
+ if (toState == NORMAL && fromState == OVERVIEW) {
+ config.setInterpolator(ANIM_WORKSPACE_SCALE, DEACCEL);
+ config.setInterpolator(ANIM_WORKSPACE_FADE, ACCEL);
+ config.setInterpolator(ANIM_OVERVIEW_SCALE, clampToProgress(ACCEL, 0, 0.9f));
+ config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, ACCEL);
+ config.setInterpolator(ANIM_OVERVIEW_FADE, DEACCEL_1_7);
+ Workspace workspace = mLauncher.getWorkspace();
+
+ // Start from a higher workspace scale, but only if we're invisible so we don't jump.
+ boolean isWorkspaceVisible = workspace.getVisibility() == VISIBLE;
+ if (isWorkspaceVisible) {
+ CellLayout currentChild = (CellLayout) workspace.getChildAt(
+ workspace.getCurrentPage());
+ isWorkspaceVisible = currentChild.getVisibility() == VISIBLE
+ && currentChild.getShortcutsAndWidgets().getAlpha() > 0;
+ }
+ if (!isWorkspaceVisible) {
+ workspace.setScaleX(0.92f);
+ workspace.setScaleY(0.92f);
+ }
+ Hotseat hotseat = mLauncher.getHotseat();
+ boolean isHotseatVisible = hotseat.getVisibility() == VISIBLE && hotseat.getAlpha() > 0;
+ if (!isHotseatVisible) {
+ hotseat.setScaleX(0.92f);
+ hotseat.setScaleY(0.92f);
+ if (ENABLE_OVERVIEW_ACTIONS.get()) {
+ AllAppsContainerView qsbContainer = mLauncher.getAppsView();
+ View qsb = qsbContainer.getSearchView();
+ boolean qsbVisible = qsb.getVisibility() == VISIBLE && qsb.getAlpha() > 0;
+ if (!qsbVisible) {
+ qsbContainer.setScaleX(0.92f);
+ qsbContainer.setScaleY(0.92f);
+ }
+ }
+ }
+ } else if (toState == NORMAL && fromState == OVERVIEW_PEEK) {
+ // Keep fully visible until the very end (when overview is offscreen) to make invisible.
+ config.setInterpolator(ANIM_OVERVIEW_FADE, t -> t < 1 ? 0 : 1);
+ } else if (toState == OVERVIEW_PEEK && fromState == NORMAL) {
+ config.setInterpolator(ANIM_OVERVIEW_FADE, INSTANT);
+ config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, OVERSHOOT_1_7);
+ config.setInterpolator(ANIM_OVERVIEW_SCRIM_FADE, FAST_OUT_SLOW_IN);
+ } else if ((fromState == NORMAL || fromState == HINT_STATE) && toState == OVERVIEW) {
+ if (SysUINavigationMode.getMode(mLauncher) == NO_BUTTON) {
+ config.setInterpolator(ANIM_WORKSPACE_SCALE,
+ fromState == NORMAL ? ACCEL : OVERSHOOT_1_2);
+ config.setInterpolator(ANIM_WORKSPACE_TRANSLATE, ACCEL);
+ } else {
+ config.setInterpolator(ANIM_WORKSPACE_SCALE, OVERSHOOT_1_2);
+
+ // Scale up the recents, if it is not coming from the side
+ RecentsView overview = mLauncher.getOverviewPanel();
+ if (overview.getVisibility() != VISIBLE || overview.getContentAlpha() == 0) {
+ SCALE_PROPERTY.set(overview, RECENTS_PREPARE_SCALE);
+ }
+ }
+ config.setInterpolator(ANIM_WORKSPACE_FADE, OVERSHOOT_1_2);
+ config.setInterpolator(ANIM_OVERVIEW_SCALE, OVERSHOOT_1_2);
+ Interpolator translationInterpolator = ENABLE_OVERVIEW_ACTIONS.get()
+ && removeShelfFromOverview(mLauncher)
+ ? OVERSHOOT_1_2
+ : OVERSHOOT_1_7;
+ config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, translationInterpolator);
+ config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, translationInterpolator);
+ config.setInterpolator(ANIM_OVERVIEW_FADE, OVERSHOOT_1_2);
+ }
+ }
+}
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java
index 8af2747..fac478e 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java
@@ -16,7 +16,6 @@
package com.android.launcher3.uioverrides.touchcontrollers;
-import static com.android.launcher3.LauncherAppTransitionManagerImpl.INDEX_PAUSE_TO_OVERVIEW_ANIM;
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
@@ -31,23 +30,26 @@
import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_TRANSLATE;
import static com.android.launcher3.states.StateAnimationConfig.PLAY_ATOMIC_OVERVIEW_PEEK;
import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW;
+import static com.android.launcher3.uioverrides.states.QuickstepAtomicAnimationFactory.INDEX_PAUSE_TO_OVERVIEW_ANIM;
import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
+import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherAppTransitionManagerImpl;
import com.android.launcher3.LauncherState;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.states.StateAnimationConfig.AnimationFlags;
+import com.android.launcher3.testing.TestProtocol;
+import com.android.launcher3.uioverrides.states.QuickstepAtomicAnimationFactory;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
import com.android.launcher3.util.VibratorWrapper;
import com.android.quickstep.SystemUiProxy;
@@ -82,7 +84,7 @@
@Override
protected long getAtomicDuration() {
- return LauncherAppTransitionManagerImpl.ATOMIC_DURATION_FROM_PAUSED_TO_OVERVIEW;
+ return QuickstepAtomicAnimationFactory.ATOMIC_DURATION_FROM_PAUSED_TO_OVERVIEW;
}
@Override
@@ -178,6 +180,9 @@
@Override
public boolean onDrag(float displacement, MotionEvent event) {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.PAUSE_NOT_DETECTED, "FlingAndHoldTouchController");
+ }
float upDisplacement = -displacement;
mMotionPauseDetector.setDisallowPause(!handlingOverviewAnim()
|| upDisplacement < mMotionPauseMinDisplacement
@@ -206,8 +211,8 @@
mPeekAnim.cancel();
}
- Animator overviewAnim = mLauncher.getAppTransitionManager().createStateElementAnimation(
- INDEX_PAUSE_TO_OVERVIEW_ANIM);
+ Animator overviewAnim = mLauncher.createAtomicAnimationFactory()
+ .createStateElementAnimation(INDEX_PAUSE_TO_OVERVIEW_ANIM);
mAtomicAnim = new AnimatorSet();
mAtomicAnim.addListener(new AnimationSuccessListener() {
@Override
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
index 06a481b..bf0690c 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
@@ -25,6 +25,7 @@
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
import android.animation.ValueAnimator;
+import android.util.Log;
import android.view.MotionEvent;
import android.view.animation.Interpolator;
@@ -41,6 +42,7 @@
import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.states.StateAnimationConfig;
+import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.touch.SingleAxisSwipeDetector;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
@@ -94,18 +96,37 @@
}
private boolean canInterceptTouch(MotionEvent ev) {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.PAUSE_NOT_DETECTED, "NavBarToHomeTouchController.canInterceptTouch "
+ + ev);
+ }
boolean cameFromNavBar = (ev.getEdgeFlags() & Utilities.EDGE_NAV_BAR) != 0;
if (!cameFromNavBar) {
return false;
}
if (mStartState.overviewUi || mStartState == ALL_APPS) {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.PAUSE_NOT_DETECTED,
+ "NavBarToHomeTouchController.canInterceptTouch true 1 "
+ + mStartState.overviewUi + " " + (mStartState == ALL_APPS));
+ }
return true;
}
if (AbstractFloatingView.getTopOpenView(mLauncher) != null) {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.PAUSE_NOT_DETECTED,
+ "NavBarToHomeTouchController.canInterceptTouch true 2 "
+ + AbstractFloatingView.getTopOpenView(mLauncher).getClass()
+ .getSimpleName());
+ }
return true;
}
if (FeatureFlags.ASSISTANT_GIVES_LAUNCHER_FOCUS.get()
&& AssistantUtilities.isExcludedAssistantRunning()) {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.PAUSE_NOT_DETECTED,
+ "NavBarToHomeTouchController.canInterceptTouch true 3");
+ }
return true;
}
return false;
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
index 381ecf1..966e25b 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
@@ -27,14 +27,16 @@
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.graphics.PointF;
+import android.util.Log;
import android.view.MotionEvent;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
-import com.android.launcher3.LauncherStateManager;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimationSuccessListener;
+import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.states.StateAnimationConfig;
+import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
import com.android.launcher3.util.VibratorWrapper;
import com.android.quickstep.util.StaggeredWorkspaceAnim;
@@ -63,6 +65,9 @@
public NoButtonNavbarToOverviewTouchController(Launcher l) {
super(l);
mRecentsView = l.getOverviewPanel();
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.PAUSE_NOT_DETECTED, "NoButtonNavbarToOverviewTouchController.ctor");
+ }
}
@Override
@@ -146,6 +151,9 @@
@Override
public boolean onDrag(float yDisplacement, float xDisplacement, MotionEvent event) {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.PAUSE_NOT_DETECTED, "NoButtonNavbarToOverviewTouchController");
+ }
if (mMotionPauseDetector.isPaused()) {
if (!mReachedOverview) {
mStartDisplacement.set(xDisplacement, yDisplacement);
@@ -165,7 +173,7 @@
protected void goToOverviewOnDragEnd(float velocity) {
float velocityDp = dpiFromPx(velocity);
boolean isFling = Math.abs(velocityDp) > 1;
- LauncherStateManager stateManager = mLauncher.getStateManager();
+ StateManager<LauncherState> stateManager = mLauncher.getStateManager();
boolean goToHomeInsteadOfOverview = isFling;
if (goToHomeInsteadOfOverview) {
if (velocity > 0) {
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
index f4f8bc9..7385658 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
@@ -16,7 +16,6 @@
package com.android.launcher3.uioverrides.touchcontrollers;
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
-import static com.android.launcher3.LauncherAppTransitionManagerImpl.INDEX_PAUSE_TO_OVERVIEW_ANIM;
import static com.android.launcher3.LauncherState.HOTSEAT_ICONS;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
@@ -35,6 +34,7 @@
import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW;
import static com.android.launcher3.touch.BothAxesSwipeDetector.DIRECTION_RIGHT;
import static com.android.launcher3.touch.BothAxesSwipeDetector.DIRECTION_UP;
+import static com.android.launcher3.uioverrides.states.QuickstepAtomicAnimationFactory.INDEX_PAUSE_TO_OVERVIEW_ANIM;
import static com.android.launcher3.util.DefaultDisplay.getSingleFrameMs;
import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC;
import static com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState.CANCEL;
@@ -312,8 +312,8 @@
if (mMotionPauseDetector.isPaused() && noFling) {
cancelAnimations();
- Animator overviewAnim = mLauncher.getAppTransitionManager().createStateElementAnimation(
- INDEX_PAUSE_TO_OVERVIEW_ANIM);
+ Animator overviewAnim = mLauncher.createAtomicAnimationFactory()
+ .createStateElementAnimation(INDEX_PAUSE_TO_OVERVIEW_ANIM);
overviewAnim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
index 9e53959..c643858 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
@@ -35,8 +35,6 @@
import android.view.MotionEvent;
-import androidx.annotation.Nullable;
-
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.Utilities;
@@ -57,7 +55,7 @@
*/
public class QuickSwitchTouchController extends AbstractStateChangeTouchController {
- private @Nullable TaskView mTaskToLaunch;
+ protected final RecentsView mOverviewPanel;
public QuickSwitchTouchController(Launcher launcher) {
this(launcher, SingleAxisSwipeDetector.HORIZONTAL);
@@ -65,6 +63,7 @@
protected QuickSwitchTouchController(Launcher l, SingleAxisSwipeDetector.Direction dir) {
super(l, dir);
+ mOverviewPanel = l.getOverviewPanel();
}
@Override
@@ -94,7 +93,6 @@
public void onDragStart(boolean start, float startDisplacement) {
super.onDragStart(start, startDisplacement);
mStartContainerType = LauncherLogProto.ContainerType.NAVBAR;
- mTaskToLaunch = mLauncher.<RecentsView>getOverviewPanel().getTaskViewAt(0);
ActivityManagerWrapper.getInstance()
.closeSystemWindows(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
}
@@ -102,7 +100,6 @@
@Override
protected void onSwipeInteractionCompleted(LauncherState targetState, int logAction) {
super.onSwipeInteractionCompleted(targetState, logAction);
- mTaskToLaunch = null;
}
@Override
@@ -141,13 +138,15 @@
}
private void updateFullscreenProgress(float progress) {
- if (mTaskToLaunch != null) {
- mTaskToLaunch.setFullscreenProgress(progress);
- int sysuiFlags = progress > UPDATE_SYSUI_FLAGS_THRESHOLD
- ? mTaskToLaunch.getThumbnail().getSysUiStatusNavFlags()
- : 0;
- mLauncher.getSystemUiController().updateUiState(UI_STATE_OVERVIEW, sysuiFlags);
+ mOverviewPanel.setFullscreenProgress(progress);
+ int sysuiFlags = 0;
+ if (progress > UPDATE_SYSUI_FLAGS_THRESHOLD) {
+ TaskView tv = mOverviewPanel.getTaskViewAt(0);
+ if (tv != null) {
+ sysuiFlags = tv.getThumbnail().getSysUiStatusNavFlags();
+ }
}
+ mLauncher.getSystemUiController().updateUiState(UI_STATE_OVERVIEW, sysuiFlags);
}
@Override
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java
index e182c59..1dd5fb7 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java
@@ -17,7 +17,6 @@
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
import static com.android.launcher3.LauncherState.OVERVIEW;
-import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR;
import static com.android.launcher3.statehandlers.DepthController.DEPTH;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
@@ -36,8 +35,8 @@
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.statehandlers.DepthController;
import com.android.quickstep.util.AppWindowAnimationHelper;
-import com.android.quickstep.util.AppWindowAnimationHelper.TransformParams;
import com.android.quickstep.util.RemoteAnimationProvider;
+import com.android.quickstep.util.TransformParams;
import com.android.quickstep.views.RecentsView;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat;
@@ -75,14 +74,10 @@
boolean onActivityReady(T activity, Boolean wasVisible) {
activity.<RecentsView>getOverviewPanel().showCurrentTask(mTargetTaskId);
AbstractFloatingView.closeAllOpenViews(activity, wasVisible);
- BaseActivityInterface.AnimationFactory factory =
- mActivityInterface.prepareRecentsUI(wasVisible,
- false /* animate activity */, (controller) -> {
+ BaseActivityInterface.AnimationFactory factory = mActivityInterface.prepareRecentsUI(
+ wasVisible, (controller) -> {
controller.dispatchOnStart();
- ValueAnimator anim = controller.getAnimationPlayer()
- .setDuration(RECENTS_LAUNCH_DURATION);
- anim.setInterpolator(FAST_OUT_SLOW_IN);
- anim.start();
+ controller.getAnimationPlayer().end();
});
factory.onRemoteAnimationReceived(null);
factory.createActivityInterface(RECENTS_LAUNCH_DURATION);
@@ -156,7 +151,7 @@
mActivityInterface.getSwipeUpDestinationAndLength(mActivity.getDeviceProfile(), mActivity,
targetRect);
clipHelper.updateTargetRect(targetRect);
- clipHelper.prepareAnimation(mActivity.getDeviceProfile(), false /* isOpening */);
+ clipHelper.prepareAnimation(mActivity.getDeviceProfile());
TransformParams params = new TransformParams()
.setSyncTransactionApplier(new SyncRtSurfaceTransactionApplierCompat(rootView));
@@ -164,9 +159,7 @@
valueAnimator.setDuration(RECENTS_LAUNCH_DURATION);
valueAnimator.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR);
valueAnimator.addUpdateListener((v) -> {
- params.setProgress((float) v.getAnimatedValue())
- .setTargetSet(targets)
- .setLauncherOnTop(true);
+ params.setProgress((float) v.getAnimatedValue()).setTargetSet(targets);
clipHelper.applyTransform(params);
});
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 d22e5af..76c6060 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java
@@ -15,6 +15,8 @@
*/
package com.android.quickstep;
+import static com.android.launcher3.LauncherState.BACKGROUND_APP;
+import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.anim.Interpolators.ACCEL_1_5;
import static com.android.launcher3.anim.Interpolators.DEACCEL;
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
@@ -23,45 +25,49 @@
import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION;
import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
-import android.graphics.Point;
+import android.graphics.Matrix;
+import android.graphics.Matrix.ScaleToFit;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Build;
-import android.util.Pair;
import android.view.MotionEvent;
-import android.view.View;
import android.view.animation.Interpolator;
+import androidx.annotation.CallSuper;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.InvariantDeviceProfile;
-import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.touch.PagedOrientationHandler;
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.RecentsOrientedState;
import com.android.quickstep.util.RectFSpringAnim;
+import com.android.quickstep.util.TaskViewSimulator;
+import com.android.quickstep.util.TransformParams;
+import com.android.quickstep.util.TransformParams.BuilderProxy;
+import com.android.quickstep.util.WindowSizeStrategy;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.InputConsumerController;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat;
+import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams.Builder;
import java.util.ArrayList;
import java.util.function.Consumer;
@@ -94,7 +100,9 @@
protected final BaseActivityInterface<T> mActivityInterface;
protected final InputConsumerController mInputConsumer;
- protected AppWindowAnimationHelper mAppWindowAnimationHelper;
+ protected final TaskViewSimulator mTaskViewSimulator;
+ private AnimatorPlaybackController mWindowTransitionController;
+
protected final TransformParams mTransformParams = new TransformParams();
// Shift in the range of [0, 1].
@@ -114,27 +122,25 @@
protected T mActivity;
protected Q mRecentsView;
protected DeviceProfile mDp;
- private final int mPageSpacing;
protected Runnable mGestureEndCallback;
protected MultiStateCallback mStateCallback;
protected boolean mCanceled;
- protected int mFinishingRecentsAnimationForNewTaskId = -1;
- private RecentsOrientedState mOrientedState;
+ private boolean mRecentsViewScrollLinked = false;
protected BaseSwipeUpHandler(Context context, RecentsAnimationDeviceState deviceState,
- GestureState gestureState, InputConsumerController inputConsumer) {
+ GestureState gestureState, InputConsumerController inputConsumer,
+ WindowSizeStrategy windowSizeStrategy) {
mContext = context;
mDeviceState = deviceState;
mGestureState = gestureState;
mActivityInterface = gestureState.getActivityInterface();
mActivityInitListener = mActivityInterface.createActivityInitListener(this::onActivityInit);
mInputConsumer = inputConsumer;
- mAppWindowAnimationHelper = new AppWindowAnimationHelper(context);
- mPageSpacing = context.getResources().getDimensionPixelSize(R.dimen.recents_page_spacing);
+ mTaskViewSimulator = new TaskViewSimulator(context, windowSizeStrategy);
}
/**
@@ -194,13 +200,13 @@
updateFinalShift();
}
});
- mRecentsView.setAppWindowAnimationHelper(mAppWindowAnimationHelper);
runOnRecentsAnimationStart(() ->
mRecentsView.setRecentsAnimationTargets(mRecentsAnimationController,
mRecentsAnimationTargets));
+ mRecentsViewScrollLinked = true;
}
- protected void startNewTask(int successStateFlag, Consumer<Boolean> resultCallback) {
+ protected void startNewTask(Consumer<Boolean> resultCallback) {
// Launch the task user scrolled to (mRecentsView.getNextPage()).
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
// We finish recents animation inside launchTask() when live tile is enabled.
@@ -211,18 +217,22 @@
if (!mCanceled) {
TaskView nextTask = mRecentsView.getTaskView(taskId);
if (nextTask != null) {
+ mGestureState.updateLastStartedTaskId(taskId);
nextTask.launchTask(false /* animate */, true /* freezeTaskList */,
success -> {
resultCallback.accept(success);
- if (!success) {
+ if (success) {
+ if (mRecentsView.indexOfChild(nextTask)
+ == getLastAppearedTaskIndex()) {
+ onRestartLastAppearedTask();
+ }
+ } else {
mActivityInterface.onLaunchTaskFailed();
nextTask.notifyTaskLaunchFailed(TAG);
- } else {
- mActivityInterface.onLaunchTaskSuccess();
+ mRecentsAnimationController.finish(true /* toRecents */, null);
}
}, MAIN_EXECUTOR.getHandler());
}
- mStateCallback.setStateOnUiThread(successStateFlag);
}
mCanceled = false;
}
@@ -230,6 +240,19 @@
}
/**
+ * Called when we successfully startNewTask() on the task that was previously running. Normally
+ * we call resumeLastTask() when returning to the previously running task, but this handles a
+ * specific edge case: if we switch from A to B, and back to A before B appears, we need to
+ * start A again to ensure it stays on top.
+ */
+ @CallSuper
+ protected void onRestartLastAppearedTask() {
+ // Finish the controller here, since we won't get onTaskAppeared() for a task that already
+ // appeared.
+ mRecentsAnimationController.finish(false, null);
+ }
+
+ /**
* Runs the given {@param action} if the recents animation has already started, or queues it to
* be run when it is next started.
*/
@@ -242,43 +265,36 @@
}
/**
+ * TODO can we remove this now that we don't finish the controller until onTaskAppeared()?
* @return whether the recents animation has started and there are valid app targets.
*/
protected boolean hasTargets() {
return mRecentsAnimationTargets != null && mRecentsAnimationTargets.hasTargets();
}
- protected void updateSource(Rect stackBounds, RemoteAnimationTargetCompat runningTarget) {
- mAppWindowAnimationHelper.updateSource(stackBounds, runningTarget);
- }
-
@Override
public void onRecentsAnimationStart(RecentsAnimationController recentsAnimationController,
RecentsAnimationTargets targets) {
mRecentsAnimationController = recentsAnimationController;
mRecentsAnimationTargets = targets;
DeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(mContext).getDeviceProfile(mContext);
- final Rect overviewStackBounds;
RemoteAnimationTargetCompat runningTaskTarget = targets.findTask(
mGestureState.getRunningTaskId());
if (targets.minimizedHomeBounds != null && runningTaskTarget != null) {
- overviewStackBounds = mActivityInterface
+ Rect overviewStackBounds = mActivityInterface
.getOverviewWindowBounds(targets.minimizedHomeBounds, runningTaskTarget);
- dp = dp.getMultiWindowProfile(mContext, new Point(
- overviewStackBounds.width(), overviewStackBounds.height()));
+ dp = dp.getMultiWindowProfile(mContext, overviewStackBounds);
} else {
// If we are not in multi-window mode, home insets should be same as system insets.
dp = dp.copy(mContext);
- overviewStackBounds = getStackBounds(dp);
}
dp.updateInsets(targets.homeContentInsets);
dp.updateIsSeascape(mContext);
if (runningTaskTarget != null) {
- updateSource(overviewStackBounds, runningTaskTarget);
+ mTaskViewSimulator.setPreview(runningTaskTarget);
}
- mAppWindowAnimationHelper.prepareAnimation(dp, false /* isOpening */);
initTransitionEndpoints(dp);
// Notify when the animation starts
@@ -308,54 +324,73 @@
}
}
- private Rect getStackBounds(DeviceProfile dp) {
- if (mActivity != null) {
- int loc[] = new int[2];
- View rootView = mActivity.getRootView();
- rootView.getLocationOnScreen(loc);
- return new Rect(loc[0], loc[1], loc[0] + rootView.getWidth(),
- loc[1] + rootView.getHeight());
- } else {
- return new Rect(0, 0, dp.widthPx, dp.heightPx);
+ @Override
+ public void onTaskAppeared(RemoteAnimationTargetCompat appearedTaskTarget) {
+ if (mRecentsAnimationController != null) {
+ if (handleTaskAppeared(appearedTaskTarget)) {
+ mRecentsAnimationController.finish(false /* toRecents */,
+ null /* onFinishComplete */);
+ mActivityInterface.onLaunchTaskSuccess();
+ }
}
}
+ /** @return Whether this was the task we were waiting to appear, and thus handled it. */
+ protected abstract boolean handleTaskAppeared(RemoteAnimationTargetCompat appearedTaskTarget);
+
+ /**
+ * @return The index of the TaskView in RecentsView whose taskId matches the task that will
+ * resume if we finish the controller.
+ */
+ protected int getLastAppearedTaskIndex() {
+ return mGestureState.getLastAppearedTaskId() != -1
+ ? mRecentsView.getTaskIndexForId(mGestureState.getLastAppearedTaskId())
+ : mRecentsView.getRunningTaskIndex();
+ }
+
+ /**
+ * @return Whether we are continuing a gesture that already landed on a new task,
+ * but before that task appeared.
+ */
+ protected boolean hasStartedNewTask() {
+ return mGestureState.getLastStartedTaskId() != -1;
+ }
+
protected void initTransitionEndpoints(DeviceProfile dp) {
mDp = dp;
mTransitionDragLength = mActivityInterface.getSwipeUpDestinationAndLength(
dp, mContext, TEMP_RECT);
+ mTaskViewSimulator.setDp(dp);
+ mTaskViewSimulator.setLayoutRotation(
+ mDeviceState.getCurrentActiveRotation(),
+ mDeviceState.getDisplayRotation());
- if (!dp.isMultiWindowMode) {
- // When updating the target rect, also update the home bounds since the location on
- // screen of the launcher window may be stale (position is not updated until first
- // traversal after the window is resized). We only do this for non-multiwindow because
- // we otherwise use the minimized home bounds provided by the system.
- mAppWindowAnimationHelper.updateHomeBounds(getStackBounds(dp));
- }
- int displayRotation = 0;
- if (mOrientedState != null && mOrientedState.isMultipleOrientationSupportedByDevice()) {
- // TODO(b/150300347): The first recents animation after launcher is started with the
- // foreground app not in landscape will look funky until that bug is fixed
- displayRotation = mOrientedState.getDisplayRotation();
-
- RectF tempRectF = new RectF(TEMP_RECT);
- mOrientedState.mapRectFromRotation(displayRotation,
- tempRectF, dp.widthPx, dp.heightPx);
- tempRectF.roundOut(TEMP_RECT);
- }
- mAppWindowAnimationHelper.updateTargetRect(TEMP_RECT);
if (mDeviceState.isFullyGesturalNavMode()) {
// We can drag all the way to the top of the screen.
- // TODO(b/149609070): Landscape apps are currently limited in
- // their ability to scale past the target rect.
- float dragFactor = (float) dp.heightPx / mTransitionDragLength;
- mDragLengthFactor = displayRotation == 0 ? dragFactor : Math.min(1.0f, dragFactor);
- Pair<Float, Float> dragFactorStartAndMaxProgress =
- mActivityInterface.getSwipeUpPullbackStartAndMaxProgress();
- mDragLengthFactorStartPullback = dragFactorStartAndMaxProgress.first;
- mDragLengthFactorMaxPullback = dragFactorStartAndMaxProgress.second;
+ mDragLengthFactor = (float) dp.heightPx / mTransitionDragLength;
+
+ float startScale = mTaskViewSimulator.getFullScreenScale();
+ // Start pulling back when RecentsView scale is 0.75f, and let it go down to 0.5f.
+ mDragLengthFactorStartPullback = (0.75f - startScale) / (1 - startScale);
+ mDragLengthFactorMaxPullback = (0.5f - startScale) / (1 - startScale);
+ } else {
+ mDragLengthFactor = 1;
+ mDragLengthFactorStartPullback = mDragLengthFactorMaxPullback = 1;
}
+
+ AnimatorSet anim = new AnimatorSet();
+ anim.setDuration(mTransitionDragLength * 2);
+ anim.setInterpolator(t -> t * mDragLengthFactor);
+ anim.play(ObjectAnimator.ofFloat(mTaskViewSimulator.recentsViewScale,
+ AnimatedFloat.VALUE,
+ mTaskViewSimulator.getFullScreenScale(), 1));
+ anim.play(ObjectAnimator.ofFloat(mTaskViewSimulator.fullScreenProgress,
+ AnimatedFloat.VALUE,
+ BACKGROUND_APP.getOverviewFullscreenProgress(),
+ OVERVIEW.getOverviewFullscreenProgress()));
+ mWindowTransitionController =
+ AnimatorPlaybackController.wrap(anim, mTransitionDragLength * 2);
}
/**
@@ -366,9 +401,6 @@
protected boolean onActivityInit(Boolean alreadyOnHome) {
T createdActivity = mActivityInterface.getCreatedActivity();
if (createdActivity != null) {
- mOrientedState = ((RecentsView) createdActivity.getOverviewPanel())
- .getPagedViewOrientedState();
- mAppWindowAnimationHelper = new AppWindowAnimationHelper(mOrientedState, mContext);
initTransitionEndpoints(InvariantDeviceProfile.INSTANCE.get(mContext)
.getDeviceProfile(mContext));
}
@@ -417,35 +449,23 @@
}
/**
- * Applies the transform on the recents animation without any additional null checks
+ * Applies the transform on the recents animation
*/
- protected void applyTransformUnchecked() {
- float shift = mCurrentShift.value;
- float offset = mRecentsView == null ? 0 : mRecentsView.getScrollOffsetScaled();
- float taskSize = getOrientationHandler()
- .getPrimarySize(mAppWindowAnimationHelper.getTargetRect());
- float offsetScale = getTaskCurveScaleForOffset(offset, taskSize);
- mTransformParams
- .setProgress(shift)
- .setOffset(offset)
- .setOffsetScale(offsetScale)
- .setTargetSet(mRecentsAnimationTargets)
- .setLauncherOnTop(true);
- mAppWindowAnimationHelper.applyTransform(mTransformParams);
- }
+ protected void applyWindowTransform() {
+ if (mWindowTransitionController != null) {
+ float progress = mCurrentShift.value / mDragLengthFactor;
+ mWindowTransitionController.setPlayFraction(progress);
+ mTransformParams.setTargetSet(mRecentsAnimationTargets);
- private float getTaskCurveScaleForOffset(float offset, float taskSize) {
- int dpPixel = getOrientationHandler().getShortEdgeLength(mDp);
- float distanceToReachEdge = dpPixel / 2 + taskSize / 2 + mPageSpacing;
- float interpolation = Math.min(1, offset / distanceToReachEdge);
- return TaskView.getCurveScaleForInterpolation(interpolation);
+ if (mRecentsViewScrollLinked) {
+ mTaskViewSimulator.setScroll(mRecentsView.getScrollOffset());
+ }
+ mTaskViewSimulator.apply(mTransformParams);
+ }
}
protected PagedOrientationHandler getOrientationHandler() {
- if (mOrientedState == null) {
- return PagedOrientationHandler.PORTRAIT;
- }
- return mOrientedState.getOrientationHandler();
+ return mTaskViewSimulator.getOrientationState().getOrientationHandler();
}
/**
@@ -456,104 +476,40 @@
protected RectFSpringAnim createWindowAnimationToHome(float startProgress,
HomeAnimationFactory homeAnimationFactory) {
final RectF targetRect = homeAnimationFactory.getWindowTargetRect();
- final View floatingView = homeAnimationFactory.getFloatingView();
- final boolean isFloatingIconView = floatingView instanceof FloatingIconView;
- final RectF startRect = new RectF(
- mAppWindowAnimationHelper.applyTransform(
- mTransformParams.setProgress(startProgress)
- .setTargetSet(mRecentsAnimationTargets)
- .setLauncherOnTop(false)));
- if (isFloatingIconView) {
- mOrientedState.mapInverseRectFromNormalOrientation(
- startRect, mDp.widthPx, mDp.heightPx);
- }
+ final FloatingIconView fiv = homeAnimationFactory.mIconView;
+ final boolean isFloatingIconView = fiv != null;
+
+ mWindowTransitionController.setPlayFraction(startProgress / mDragLengthFactor);
+ mTaskViewSimulator.apply(mTransformParams
+ .setProgress(startProgress)
+ .setTargetSet(mRecentsAnimationTargets));
+ RectF cropRectF = new RectF(mTaskViewSimulator.getCurrentCropRect());
+
+ // Matrix to map a rect in Launcher space to window space
+ Matrix homeToWindowPositionMap = new Matrix();
+ mTaskViewSimulator.applyWindowToHomeRotation(homeToWindowPositionMap);
+
+ final RectF startRect = new RectF(cropRectF);
+ mTaskViewSimulator.getCurrentMatrix().mapRect(startRect);
+ // Move the startRect to Launcher space as floatingIconView runs in Launcher
+ Matrix windowToHomePositionMap = new Matrix();
+ homeToWindowPositionMap.invert(windowToHomePositionMap);
+ windowToHomePositionMap.mapRect(startRect);
+
RectFSpringAnim anim = new RectFSpringAnim(startRect, targetRect, mContext);
if (isFloatingIconView) {
- FloatingIconView fiv = (FloatingIconView) floatingView;
anim.addAnimatorListener(fiv);
fiv.setOnTargetChangeListener(anim::onTargetPositionChanged);
fiv.setFastFinishRunnable(anim::end);
}
- AnimatorPlaybackController homeAnim = homeAnimationFactory.createActivityAnimationToHome();
-
- // End on a "round-enough" radius so that the shape reveal doesn't have to do too much
- // rounding at the end of the animation.
- float startRadius = mAppWindowAnimationHelper.getCurrentCornerRadius();
- float endRadius = startRect.width() / 6f;
-
- float startTransformProgress = mTransformParams.getProgress();
- float endTransformProgress = 1;
-
- // We want the window alpha to be 0 once this threshold is met, so that the
- // FolderIconView can be seen morphing into the icon shape.
- final float windowAlphaThreshold = isFloatingIconView ? 1f - SHAPE_PROGRESS_DURATION : 1f;
- final RectF rotatedRect = new RectF();
- anim.addOnUpdateListener(new RectFSpringAnim.OnUpdateListener() {
-
- @Override
- public void onUpdate(RectF currentRect, float progress) {
- homeAnim.setPlayFraction(progress);
-
- rotatedRect.set(currentRect);
- if (isFloatingIconView) {
- mOrientedState.mapRectFromNormalOrientation(
- rotatedRect, mDp.widthPx, mDp.heightPx);
- mTransformParams.setCornerRadius(endRadius * progress + startRadius
- * (1f - progress));
- }
- mTransformParams.setProgress(
- Utilities.mapRange(progress, startTransformProgress, endTransformProgress))
- .setCurrentRect(rotatedRect)
- .setTargetAlpha(getWindowAlpha(progress));
- mAppWindowAnimationHelper.applyTransform(mTransformParams);
-
- if (isFloatingIconView) {
- ((FloatingIconView) floatingView).update(currentRect, 1f, progress,
- windowAlphaThreshold, mAppWindowAnimationHelper.getCurrentCornerRadius(),
- false);
- }
- }
-
- @Override
- public void onCancel() {
- if (isFloatingIconView) {
- ((FloatingIconView) floatingView).fastFinish();
- }
- }
- });
- anim.addAnimatorListener(new AnimationSuccessListener() {
- @Override
- public void onAnimationStart(Animator animation) {
- homeAnim.dispatchOnStart();
- }
-
- @Override
- public void onAnimationSuccess(Animator animator) {
- homeAnim.getAnimationPlayer().end();
- }
- });
+ SpringAnimationRunner runner = new SpringAnimationRunner(
+ homeAnimationFactory, cropRectF, homeToWindowPositionMap);
+ anim.addOnUpdateListener(runner);
+ anim.addAnimatorListener(runner);
return anim;
}
- /**
- * @param progress The progress of the animation to the home screen.
- * @return The current alpha to set on the animating app window.
- */
- protected float getWindowAlpha(float progress) {
- // Alpha interpolates between [1, 0] between progress values [start, end]
- final float start = 0f;
- final float end = 0.85f;
-
- if (progress <= start) {
- return 1f;
- }
- if (progress >= end) {
- return 0f;
- }
- return Utilities.mapToRange(progress, start, end, 1, 0, ACCEL_1_5);
- }
-
public interface Factory {
BaseSwipeUpHandler newHandler(GestureState gestureState, long touchTimeMs,
@@ -593,4 +549,135 @@
};
}
}
+
+ /**
+ * @param progress The progress of the animation to the home screen.
+ * @return The current alpha to set on the animating app window.
+ */
+ protected float getWindowAlpha(float progress) {
+ // Alpha interpolates between [1, 0] between progress values [start, end]
+ final float start = 0f;
+ final float end = 0.85f;
+
+ if (progress <= start) {
+ return 1f;
+ }
+ if (progress >= end) {
+ return 0f;
+ }
+ return Utilities.mapToRange(progress, start, end, 1, 0, ACCEL_1_5);
+ }
+
+ protected abstract class HomeAnimationFactory {
+
+ private FloatingIconView mIconView;
+
+ public HomeAnimationFactory(@Nullable FloatingIconView iconView) {
+ mIconView = iconView;
+ }
+
+ public @NonNull RectF getWindowTargetRect() {
+ PagedOrientationHandler orientationHandler = getOrientationHandler();
+ DeviceProfile dp = mDp;
+ final int halfIconSize = dp.iconSizePx / 2;
+ float primaryDimension = orientationHandler
+ .getPrimaryValue(dp.availableWidthPx, dp.availableHeightPx);
+ float secondaryDimension = orientationHandler
+ .getSecondaryValue(dp.availableWidthPx, dp.availableHeightPx);
+ final float targetX = primaryDimension / 2f;
+ final float targetY = secondaryDimension - dp.hotseatBarSizePx;
+ // Fallback to animate to center of screen.
+ return new RectF(targetX - halfIconSize, targetY - halfIconSize,
+ targetX + halfIconSize, targetY + halfIconSize);
+ }
+
+ public abstract @NonNull AnimatorPlaybackController createActivityAnimationToHome();
+
+ public void playAtomicAnimation(float velocity) {
+ // No-op
+ }
+ }
+
+ private class SpringAnimationRunner extends AnimationSuccessListener
+ implements RectFSpringAnim.OnUpdateListener, BuilderProxy {
+
+ final Rect mCropRect = new Rect();
+ final Matrix mMatrix = new Matrix();
+
+ final RectF mWindowCurrentRect = new RectF();
+ final Matrix mHomeToWindowPositionMap;
+
+ final FloatingIconView mFIV;
+ final AnimatorPlaybackController mHomeAnim;
+ final RectF mCropRectF;
+
+ final float mStartRadius;
+ final float mEndRadius;
+ final float mWindowAlphaThreshold;
+
+ SpringAnimationRunner(HomeAnimationFactory factory, RectF cropRectF,
+ Matrix homeToWindowPositionMap) {
+ mHomeAnim = factory.createActivityAnimationToHome();
+ mCropRectF = cropRectF;
+ mHomeToWindowPositionMap = homeToWindowPositionMap;
+
+ cropRectF.roundOut(mCropRect);
+ mFIV = factory.mIconView;
+
+ // End on a "round-enough" radius so that the shape reveal doesn't have to do too much
+ // rounding at the end of the animation.
+ mStartRadius = mTaskViewSimulator.getCurrentCornerRadius();
+ mEndRadius = cropRectF.width() / 2f;
+
+ // We want the window alpha to be 0 once this threshold is met, so that the
+ // FolderIconView can be seen morphing into the icon shape.
+ mWindowAlphaThreshold = mFIV != null ? 1f - SHAPE_PROGRESS_DURATION : 1f;
+ }
+
+ @Override
+ public void onUpdate(RectF currentRect, float progress) {
+ mHomeAnim.setPlayFraction(progress);
+ mHomeToWindowPositionMap.mapRect(mWindowCurrentRect, currentRect);
+
+ mMatrix.setRectToRect(mCropRectF, mWindowCurrentRect, ScaleToFit.FILL);
+ float cornerRadius = Utilities.mapRange(progress, mStartRadius, mEndRadius);
+ mTransformParams
+ .setTargetAlpha(getWindowAlpha(progress))
+ .setCornerRadius(cornerRadius);
+
+ mTransformParams.applySurfaceParams(mTransformParams.createSurfaceParams(this));
+ if (mFIV != null) {
+ mFIV.update(currentRect, 1f, progress,
+ mWindowAlphaThreshold, mMatrix.mapRadius(cornerRadius), false);
+ }
+ }
+
+ @Override
+ public void onBuildParams(Builder builder, RemoteAnimationTargetCompat app, int targetMode,
+ TransformParams params) {
+ if (app.mode == targetMode
+ && app.activityType != RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) {
+ builder.withMatrix(mMatrix)
+ .withWindowCrop(mCropRect)
+ .withCornerRadius(params.getCornerRadius());
+ }
+ }
+
+ @Override
+ public void onCancel() {
+ if (mFIV != null) {
+ mFIV.fastFinish();
+ }
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mHomeAnim.dispatchOnStart();
+ }
+
+ @Override
+ public void onAnimationSuccess(Animator animator) {
+ mHomeAnim.getAnimationPlayer().end();
+ }
+ }
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityInterface.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityInterface.java
index 2214dd0..cd546e2 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityInterface.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityInterface.java
@@ -15,28 +15,26 @@
*/
package com.android.quickstep;
+import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
-import static com.android.quickstep.fallback.FallbackRecentsView.ZOOM_PROGRESS;
+import static com.android.quickstep.fallback.RecentsState.BACKGROUND_APP;
+import static com.android.quickstep.fallback.RecentsState.DEFAULT;
+import static com.android.quickstep.util.WindowSizeStrategy.FALLBACK_RECENTS_SIZE_STRATEGY;
import static com.android.quickstep.views.RecentsView.CONTENT_ALPHA;
+import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS;
-import android.animation.Animator;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Rect;
-import android.graphics.RectF;
-import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
+import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.quickstep.fallback.FallbackRecentsView;
import com.android.quickstep.util.ActivityInitListener;
-import com.android.quickstep.util.LayoutUtils;
import com.android.quickstep.views.RecentsView;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
@@ -60,7 +58,7 @@
@Override
public int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context, Rect outRect) {
- LayoutUtils.calculateFallbackTaskSize(context, dp, outRect);
+ FALLBACK_RECENTS_SIZE_STRATEGY.calculateTaskSize(context, dp, outRect);
if (dp.isVerticalBarLayout()
&& SysUINavigationMode.INSTANCE.get(context).getMode() != NO_BUTTON) {
Rect targetInsets = dp.getInsets();
@@ -89,54 +87,17 @@
// set to zero prior to this class becoming active.
}
- @NonNull
@Override
- public HomeAnimationFactory prepareHomeUI() {
+ public AnimationFactory prepareRecentsUI(
+ boolean activityVisible, Consumer<AnimatorPlaybackController> callback) {
RecentsActivity activity = getCreatedActivity();
- RecentsView recentsView = activity.getOverviewPanel();
-
- return new HomeAnimationFactory() {
- @NonNull
- @Override
- public RectF getWindowTargetRect() {
- float centerX = recentsView.getPivotX();
- float centerY = recentsView.getPivotY();
- return new RectF(centerX, centerY, centerX, centerY);
- }
-
- @NonNull
- @Override
- public AnimatorPlaybackController createActivityAnimationToHome() {
- Animator anim = ObjectAnimator.ofFloat(recentsView, CONTENT_ALPHA, 0);
- anim.addListener(new AnimationSuccessListener() {
- @Override
- public void onAnimationSuccess(Animator animator) {
- recentsView.startHome();
- }
- });
- AnimatorSet animatorSet = new AnimatorSet();
- animatorSet.play(anim);
- long accuracy = 2 * Math.max(recentsView.getWidth(), recentsView.getHeight());
- return AnimatorPlaybackController.wrap(animatorSet, accuracy);
- }
- };
- }
-
- @Override
- public AnimationFactory prepareRecentsUI(boolean activityVisible,
- boolean animateActivity, Consumer<AnimatorPlaybackController> callback) {
- RecentsActivity activity = getCreatedActivity();
- if (activityVisible) {
+ if (activity == null) {
return (transitionLength) -> { };
}
+ activity.getStateManager().goToState(BACKGROUND_APP);
FallbackRecentsView rv = activity.getOverviewPanel();
rv.setContentAlpha(0);
- rv.getClearAllButton().setVisibilityAlpha(0);
- rv.setDisallowScrollToClearAll(true);
-
- boolean fromState = !animateActivity;
- rv.setInOverviewState(fromState);
return new AnimationFactory() {
@@ -154,27 +115,19 @@
@Override
public void createActivityInterface(long transitionLength) {
- AnimatorSet animatorSet = new AnimatorSet();
+ PendingAnimation pa = new PendingAnimation(transitionLength * 2);
+
if (isAnimatingToRecents) {
- ObjectAnimator anim = ObjectAnimator.ofFloat(rv, CONTENT_ALPHA, 0, 1);
- anim.setDuration(transitionLength).setInterpolator(LINEAR);
- animatorSet.play(anim);
+ pa.addFloat(rv, CONTENT_ALPHA, 0, 1, LINEAR);
}
- ObjectAnimator anim = ObjectAnimator.ofFloat(rv, ZOOM_PROGRESS, 1, 0);
- anim.setDuration(transitionLength).setInterpolator(LINEAR);
- animatorSet.play(anim);
-
- AnimatorPlaybackController controller =
- AnimatorPlaybackController.wrap(animatorSet, transitionLength);
+ pa.addFloat(rv, SCALE_PROPERTY, rv.getMaxScaleForFullScreen(), 1, LINEAR);
+ pa.addFloat(rv, FULLSCREEN_PROGRESS, 1, 0, LINEAR);
+ AnimatorPlaybackController controller = pa.createPlaybackController();
// Since we are changing the start position of the UI, reapply the state, at the end
- controller.setEndAction(() -> {
- boolean endState = true;
- rv.setInOverviewState(controller.getInterpolatedProgress() > 0.5 ?
- endState : fromState);
- });
-
+ controller.setEndAction(() -> activity.getStateManager().goToState(
+ controller.getInterpolatedProgress() > 0.5 ? DEFAULT : BACKGROUND_APP));
callback.accept(controller);
}
};
@@ -190,7 +143,7 @@
@Nullable
@Override
public RecentsActivity getCreatedActivity() {
- return BaseRecentsActivity.ACTIVITY_TRACKER.getCreatedActivity();
+ return RecentsActivity.ACTIVITY_TRACKER.getCreatedActivity();
}
@Nullable
@@ -215,7 +168,7 @@
}
@Override
- public boolean shouldMinimizeSplitScreen() {
+ public boolean allowMinimizeSplitScreen() {
// TODO: Remove this once b/77875376 is fixed
return false;
}
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 1b2979b..77e50ca 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackSwipeHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackSwipeHandler.java
@@ -24,6 +24,7 @@
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.util.WindowSizeStrategy.FALLBACK_RECENTS_SIZE_STRATEGY;
import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD;
import android.animation.Animator;
@@ -32,25 +33,24 @@
import android.content.Context;
import android.content.Intent;
import android.graphics.PointF;
-import android.graphics.RectF;
import android.os.Bundle;
import android.util.ArrayMap;
import android.view.MotionEvent;
+import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
-import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.util.ObjectWrapper;
-import com.android.quickstep.BaseActivityInterface.HomeAnimationFactory;
+import com.android.quickstep.BaseActivityInterface.AnimationFactory;
import com.android.quickstep.GestureState.GestureEndTarget;
import com.android.quickstep.fallback.FallbackRecentsView;
import com.android.quickstep.util.RectFSpringAnim;
-import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.ActivityOptionsCompat;
import com.android.systemui.shared.system.InputConsumerController;
+import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
/**
* Handles the navigation gestures when a 3rd party launcher is the default home activity.
@@ -105,10 +105,16 @@
private final PointF mEndVelocityPxPerMs = new PointF(0, 0.5f);
private RunningWindowAnim mFinishAnimation;
+ // Used to control Recents components throughout the swipe gesture.
+ private AnimatorPlaybackController mLauncherTransitionController;
+ private boolean mHasLauncherTransitionControllerStarted;
+
+ private AnimationFactory mAnimationFactory = (t) -> { };
+
public FallbackSwipeHandler(Context context, RecentsAnimationDeviceState deviceState,
GestureState gestureState, InputConsumerController inputConsumer,
boolean isLikelyToStartNewTask, boolean continuingLastGesture) {
- super(context, deviceState, gestureState, inputConsumer);
+ super(context, deviceState, gestureState, inputConsumer, FALLBACK_RECENTS_SIZE_STRATEGY);
mInQuickSwitchMode = isLikelyToStartNewTask || continuingLastGesture;
mContinuingLastGesture = continuingLastGesture;
@@ -118,9 +124,9 @@
// Keep the home launcher invisible until we decide to land there.
mLauncherAlpha.value = mRunningOverHome ? 1 : 0;
if (mSwipeUpOverHome) {
- mAppWindowAnimationHelper.setBaseAlphaCallback((t, a) -> 1 - mLauncherAlpha.value);
+ mTransformParams.setBaseAlphaCallback((t, a) -> 1 - mLauncherAlpha.value);
} else {
- mAppWindowAnimationHelper.setBaseAlphaCallback((t, a) -> mLauncherAlpha.value);
+ mTransformParams.setBaseAlphaCallback((t, a) -> mLauncherAlpha.value);
}
// Going home has an extra long progress to ensure that it animates into the screen
@@ -156,7 +162,7 @@
private void onLauncherAlphaChanged() {
if (mRecentsAnimationTargets != null && mGestureState.getEndTarget() == null) {
- applyTransformUnchecked();
+ applyWindowTransform();
}
}
@@ -167,10 +173,6 @@
mRecentsView = mActivity.getOverviewPanel();
mRecentsView.setOnPageTransitionEndCallback(null);
linkRecentsViewScroll();
- mRecentsView.setDisallowScrollToClearAll(true);
- mRecentsView.getClearAllButton().setVisibilityAlpha(0);
- mRecentsView.setZoomProgress(1);
-
if (!mContinuingLastGesture) {
if (mRunningOverHome) {
mRecentsView.onGestureAnimationStart(mGestureState.getRunningTask());
@@ -180,10 +182,49 @@
}
mStateCallback.setStateOnUiThread(STATE_RECENTS_PRESENT);
mDeviceState.enableMultipleRegions(false);
+
+ mAnimationFactory = mActivityInterface.prepareRecentsUI(alreadyOnHome,
+ this::onAnimatorPlaybackControllerCreated);
+ mAnimationFactory.createActivityInterface(mTransitionDragLength);
return true;
}
@Override
+ protected void initTransitionEndpoints(DeviceProfile dp) {
+ super.initTransitionEndpoints(dp);
+ if (canCreateNewOrUpdateExistingLauncherTransitionController()) {
+ mAnimationFactory.createActivityInterface(mTransitionDragLength);
+ }
+ }
+
+ private void onAnimatorPlaybackControllerCreated(AnimatorPlaybackController anim) {
+ mLauncherTransitionController = anim;
+ mLauncherTransitionController.dispatchSetInterpolator(t -> t * mDragLengthFactor);
+ mLauncherTransitionController.dispatchOnStart();
+ updateLauncherTransitionProgress();
+ }
+
+ private void updateLauncherTransitionProgress() {
+ if (mLauncherTransitionController == null
+ || !canCreateNewOrUpdateExistingLauncherTransitionController()) {
+ return;
+ }
+ // Normalize the progress to 0 to 1, as the animation controller will clamp it to that
+ // anyway. The controller mimics the drag length factor by applying it to its interpolators.
+ float progress = mCurrentShift.value / mDragLengthFactor;
+ mLauncherTransitionController.setPlayFraction(progress);
+ }
+
+ /**
+ * We don't want to change mLauncherTransitionController if mGestureState.getEndTarget() == HOME
+ * (it has its own animation) or if we're already animating the current controller.
+ * @return Whether we can create the launcher controller or update its progress.
+ */
+ private boolean canCreateNewOrUpdateExistingLauncherTransitionController() {
+ return mGestureState.getEndTarget() != HOME && !mHasLauncherTransitionControllerStarted;
+ }
+
+ @Override
protected boolean moveWindowWithRecentsScroll() {
return mInQuickSwitchMode;
}
@@ -250,17 +291,19 @@
public void updateFinalShift() {
mTransformParams.setProgress(mCurrentShift.value);
if (mRecentsAnimationController != null) {
- mRecentsAnimationController.setWindowThresholdCrossed(!mInQuickSwitchMode
- && (mCurrentShift.value > 1 - UPDATE_SYSUI_FLAGS_THRESHOLD));
+ boolean swipeUpThresholdPassed = mCurrentShift.value > 1 - UPDATE_SYSUI_FLAGS_THRESHOLD;
+ mRecentsAnimationController.setUseLauncherSystemBarFlags(mInQuickSwitchMode
+ || swipeUpThresholdPassed);
+ mRecentsAnimationController.setSplitScreenMinimized(!mInQuickSwitchMode
+ && swipeUpThresholdPassed);
}
if (!mInQuickSwitchMode && !mDeviceState.isFullyGesturalNavMode()) {
updateOverviewThresholdPassed(mCurrentShift.value >= MIN_PROGRESS_FOR_OVERVIEW);
}
- if (mRecentsAnimationTargets != null) {
- applyTransformUnchecked();
- }
+ applyWindowTransform();
+ updateLauncherTransitionProgress();
}
@Override
@@ -317,15 +360,6 @@
}
if (mRecentsView != null) {
- if (mFinishingRecentsAnimationForNewTaskId != -1) {
- TaskView newRunningTaskView = mRecentsView.getTaskView(
- mFinishingRecentsAnimationForNewTaskId);
- int newRunningTaskId = newRunningTaskView != null
- ? newRunningTaskView.getTask().key.id
- : -1;
- mRecentsView.setCurrentTask(newRunningTaskId);
- mGestureState.setFinishingRecentsAnimationTaskId(newRunningTaskId);
- }
mRecentsView.setOnScrollChangeListener(null);
}
} else {
@@ -398,7 +432,7 @@
break;
}
case NEW_TASK: {
- startNewTask(STATE_HANDLER_INVALIDATED, b -> {});
+ startNewTask(success -> { });
break;
}
}
@@ -413,7 +447,7 @@
if (mRecentsView == null || !hasTargets()) {
mGestureState.setEndTarget(LAST_TASK);
} else {
- final int runningTaskIndex = mRecentsView.getRunningTaskIndex();
+ final int runningTaskIndex = getLastAppearedTaskIndex();
final int taskToLaunch = mRecentsView.getNextPage();
mGestureState.setEndTarget(
(runningTaskIndex >= 0 && taskToLaunch != runningTaskIndex)
@@ -474,11 +508,7 @@
RecentsAnimationTargets targets) {
super.onRecentsAnimationStart(controller, targets);
mRecentsAnimationController.enableInputConsumer();
-
- if (mRunningOverHome) {
- mAppWindowAnimationHelper.prepareAnimation(mDp, true);
- }
- applyTransformUnchecked();
+ applyWindowTransform();
mStateCallback.setStateOnUiThread(STATE_APP_CONTROLLER_RECEIVED);
}
@@ -491,23 +521,17 @@
super.onRecentsAnimationCanceled(thumbnailData);
}
+ @Override
+ protected boolean handleTaskAppeared(RemoteAnimationTargetCompat appearedTaskTarget) {
+ return true;
+ }
+
/**
* Creates an animation that transforms the current app window into the home app.
* @param startProgress The progress of {@link #mCurrentShift} to start the window from.
*/
private RectFSpringAnim createWindowAnimationToHome(float startProgress, long duration) {
- HomeAnimationFactory factory = new HomeAnimationFactory() {
- @Override
- public RectF getWindowTargetRect() {
- PagedOrientationHandler orientationHandler = mRecentsView != null
- ? mRecentsView.getPagedOrientationHandler()
- : (mDp.isLandscape
- ? PagedOrientationHandler.LANDSCAPE
- : PagedOrientationHandler.PORTRAIT);
- return HomeAnimationFactory
- .getDefaultWindowTargetRect(orientationHandler, mDp);
- }
-
+ HomeAnimationFactory factory = new HomeAnimationFactory(null) {
@Override
public AnimatorPlaybackController createActivityAnimationToHome() {
AnimatorSet anim = new AnimatorSet();
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 b4764dc..9ff5d942 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java
@@ -16,31 +16,26 @@
package com.android.quickstep;
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
-import static com.android.launcher3.LauncherAppTransitionManagerImpl.INDEX_RECENTS_FADE_ANIM;
-import static com.android.launcher3.LauncherAppTransitionManagerImpl.INDEX_RECENTS_TRANSLATE_X_ANIM;
-import static com.android.launcher3.LauncherAppTransitionManagerImpl.INDEX_SHELF_ANIM;
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
-import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.anim.Interpolators.ACCEL_2;
import static com.android.launcher3.anim.Interpolators.INSTANT;
import static com.android.launcher3.anim.Interpolators.LINEAR;
+import static com.android.launcher3.uioverrides.states.QuickstepAtomicAnimationFactory.INDEX_RECENTS_FADE_ANIM;
+import static com.android.launcher3.uioverrides.states.QuickstepAtomicAnimationFactory.INDEX_RECENTS_TRANSLATE_X_ANIM;
+import static com.android.launcher3.uioverrides.states.QuickstepAtomicAnimationFactory.INDEX_SHELF_ANIM;
import static com.android.quickstep.LauncherSwipeHandler.RECENTS_ATTACH_DURATION;
+import static com.android.quickstep.util.WindowSizeStrategy.LAUNCHER_ACTIVITY_SIZE_STRATEGY;
import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_OFFSET;
+import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS;
import android.animation.Animator;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Rect;
-import android.graphics.RectF;
-import android.os.UserHandle;
-import android.util.Pair;
+import android.util.Log;
import android.view.MotionEvent;
-import android.view.View;
import android.view.animation.Interpolator;
-import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
@@ -51,20 +46,19 @@
import com.android.launcher3.LauncherState;
import com.android.launcher3.allapps.DiscoveryBounce;
import com.android.launcher3.anim.AnimatorPlaybackController;
+import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.appprediction.PredictionUiStateManager;
import com.android.launcher3.statehandlers.DepthController;
import com.android.launcher3.statehandlers.DepthController.ClampedDepthProperty;
+import com.android.launcher3.testing.TestProtocol;
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;
-import com.android.quickstep.views.TaskView;
import com.android.systemui.plugins.shared.LauncherOverlayManager;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
@@ -77,12 +71,9 @@
*/
public final class LauncherActivityInterface implements BaseActivityInterface<Launcher> {
- private Pair<Float, Float> mSwipeUpPullbackStartAndMaxProgress =
- BaseActivityInterface.super.getSwipeUpPullbackStartAndMaxProgress();
-
@Override
public int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context, Rect outRect) {
- LayoutUtils.calculateLauncherTaskSize(context, dp, outRect);
+ LAUNCHER_ACTIVITY_SIZE_STRATEGY.calculateTaskSize(context, dp, outRect);
if (dp.isVerticalBarLayout() && SysUINavigationMode.getMode(context) != Mode.NO_BUTTON) {
Rect targetInsets = dp.getInsets();
int hotseatInset = dp.isSeascape() ? targetInsets.left : targetInsets.right;
@@ -93,11 +84,6 @@
}
@Override
- public Pair<Float, Float> getSwipeUpPullbackStartAndMaxProgress() {
- return mSwipeUpPullbackStartAndMaxProgress;
- }
-
- @Override
public void onTransitionCancelled(boolean activityVisible) {
Launcher launcher = getCreatedActivity();
if (launcher == null) {
@@ -147,77 +133,19 @@
launcher.onAssistantVisibilityChanged(visibility);
}
- @NonNull
@Override
- public HomeAnimationFactory prepareHomeUI() {
- Launcher launcher = getCreatedActivity();
- final DeviceProfile dp = launcher.getDeviceProfile();
- final RecentsView recentsView = launcher.getOverviewPanel();
- final TaskView runningTaskView = recentsView.getRunningTaskView();
- final View workspaceView;
- if (runningTaskView != null && runningTaskView.getTask().key.getComponent() != null) {
- workspaceView = launcher.getWorkspace().getFirstMatchForAppClose(
- runningTaskView.getTask().key.getComponent().getPackageName(),
- UserHandle.of(runningTaskView.getTask().key.userId));
- } else {
- workspaceView = null;
- }
- final RectF iconLocation = new RectF();
- boolean canUseWorkspaceView = workspaceView != null && workspaceView.isAttachedToWindow();
- FloatingIconView floatingIconView = canUseWorkspaceView
- ? FloatingIconView.getFloatingIconView(launcher, workspaceView,
- true /* hideOriginal */, iconLocation, false /* isOpening */)
- : null;
- setLauncherHideBackArrow(true);
- return new HomeAnimationFactory() {
- @Nullable
- @Override
- public View getFloatingView() {
- return floatingIconView;
- }
-
- @NonNull
- @Override
- public RectF getWindowTargetRect() {
- if (canUseWorkspaceView) {
- return iconLocation;
- } else {
- return HomeAnimationFactory
- .getDefaultWindowTargetRect(recentsView.getPagedOrientationHandler(), dp);
- }
- }
-
- @NonNull
- @Override
- public AnimatorPlaybackController createActivityAnimationToHome() {
- // Return an empty APC here since we have an non-user controlled animation to home.
- long accuracy = 2 * Math.max(dp.widthPx, dp.heightPx);
- return launcher.getStateManager().createAnimationToNewWorkspace(NORMAL, accuracy,
- 0 /* animComponents */);
- }
-
- @Override
- public void playAtomicAnimation(float velocity) {
- new StaggeredWorkspaceAnim(launcher, velocity, true /* animateOverviewScrim */)
- .start();
- }
- };
- }
-
- @Override
- public AnimationFactory prepareRecentsUI(boolean activityVisible,
- boolean animateActivity, Consumer<AnimatorPlaybackController> callback) {
+ public AnimationFactory prepareRecentsUI(
+ boolean activityVisible, Consumer<AnimatorPlaybackController> callback) {
BaseQuickstepLauncher launcher = getCreatedActivity();
final LauncherState startState = launcher.getStateManager().getState();
LauncherState resetState = startState;
- if (startState.disableRestore) {
+ if (startState.shouldDisableRestore()) {
resetState = launcher.getStateManager().getRestState();
}
launcher.getStateManager().setRestState(resetState);
- final LauncherState fromState = animateActivity ? BACKGROUND_APP : OVERVIEW;
- launcher.getStateManager().goToState(fromState, false);
+ launcher.getStateManager().goToState(BACKGROUND_APP, false);
// Since all apps is not visible, we can safely reset the scroll position.
// This ensures then the next swipe up to all-apps starts from scroll 0.
launcher.getAppsView().reset(false /* animate */);
@@ -228,7 +156,7 @@
@Override
public void createActivityInterface(long transitionLength) {
- createActivityInterfaceInternal(launcher, fromState, transitionLength, callback);
+ callback.accept(createBackgroundToOverviewAnim(launcher, transitionLength));
// Creating the activity controller animation sometimes reapplies the launcher state
// (because we set the animation as the current state animation), so we reapply the
// attached state here as well to ensure recents is shown/hidden appropriately.
@@ -282,74 +210,45 @@
};
}
- private void createActivityInterfaceInternal(Launcher activity, LauncherState fromState,
- long transitionLength, Consumer<AnimatorPlaybackController> callback) {
- LauncherState endState = OVERVIEW;
- if (fromState == endState) {
- return;
- }
+ private AnimatorPlaybackController createBackgroundToOverviewAnim(
+ Launcher activity, long transitionLength) {
- AnimatorSet anim = new AnimatorSet();
+ PendingAnimation pa = new PendingAnimation(transitionLength * 2);
+
if (!activity.getDeviceProfile().isVerticalBarLayout()
&& SysUINavigationMode.getMode(activity) != Mode.NO_BUTTON) {
// Don't animate the shelf when the mode is NO_BUTTON, because we update it atomically.
- anim.play(activity.getStateManager().createStateElementAnimation(
+ pa.add(activity.getStateManager().createStateElementAnimation(
INDEX_SHELF_ANIM,
- fromState.getVerticalProgress(activity),
- endState.getVerticalProgress(activity)));
+ BACKGROUND_APP.getVerticalProgress(activity),
+ OVERVIEW.getVerticalProgress(activity)));
}
// Animate the blur and wallpaper zoom
- DepthController depthController = getDepthController();
- float fromDepthRatio = fromState.getDepth(activity);
- float toDepthRatio = endState.getDepth(activity);
- Animator depthAnimator = ObjectAnimator.ofFloat(depthController,
- new ClampedDepthProperty(fromDepthRatio, toDepthRatio),
- fromDepthRatio, toDepthRatio);
- anim.play(depthAnimator);
+ float fromDepthRatio = BACKGROUND_APP.getDepth(activity);
+ float toDepthRatio = OVERVIEW.getDepth(activity);
+ pa.addFloat(getDepthController(), new ClampedDepthProperty(fromDepthRatio, toDepthRatio),
+ fromDepthRatio, toDepthRatio, LINEAR);
- playScaleDownAnim(anim, activity, fromState, endState);
- anim.setDuration(transitionLength * 2);
- anim.setInterpolator(LINEAR);
- AnimatorPlaybackController controller =
- AnimatorPlaybackController.wrap(anim, transitionLength * 2);
+ // Scale down recents from being full screen to being in overview.
+ RecentsView recentsView = activity.getOverviewPanel();
+ pa.addFloat(recentsView, SCALE_PROPERTY,
+ BACKGROUND_APP.getOverviewScaleAndOffset(activity)[0],
+ OVERVIEW.getOverviewScaleAndOffset(activity)[0],
+ LINEAR);
+ pa.addFloat(recentsView, FULLSCREEN_PROGRESS,
+ BACKGROUND_APP.getOverviewFullscreenProgress(),
+ OVERVIEW.getOverviewFullscreenProgress(),
+ LINEAR);
+
+ AnimatorPlaybackController controller = pa.createPlaybackController();
activity.getStateManager().setCurrentUserControlledAnimation(controller);
// Since we are changing the start position of the UI, reapply the state, at the end
- controller.setEndAction(() -> {
- activity.getStateManager().goToState(
- controller.getInterpolatedProgress() > 0.5 ? endState : fromState, false);
- });
- callback.accept(controller);
- }
-
- /**
- * Scale down recents from the center task being full screen to being in overview.
- */
- private void playScaleDownAnim(AnimatorSet anim, Launcher launcher, LauncherState fromState,
- LauncherState endState) {
- RecentsView recentsView = launcher.getOverviewPanel();
- if (recentsView.getCurrentPageTaskView() == null) {
- return;
- }
-
- float fromFullscreenProgress = fromState.getOverviewFullscreenProgress();
- float endFullscreenProgress = endState.getOverviewFullscreenProgress();
-
- float fromScale = fromState.getOverviewScaleAndOffset(launcher)[0];
- float endScale = endState.getOverviewScaleAndOffset(launcher)[0];
-
- Animator scale = ObjectAnimator.ofFloat(recentsView, SCALE_PROPERTY, fromScale, endScale);
- Animator applyFullscreenProgress = ObjectAnimator.ofFloat(recentsView,
- RecentsView.FULLSCREEN_PROGRESS, fromFullscreenProgress, endFullscreenProgress);
- anim.playTogether(scale, applyFullscreenProgress);
-
- // Start pulling back when RecentsView scale is 0.75f, and let it go down to 0.5f.
- float pullbackStartProgress = (0.75f - fromScale) / (endScale - fromScale);
- float pullbackMaxProgress = (0.5f - fromScale) / (endScale - fromScale);
- mSwipeUpPullbackStartAndMaxProgress = new Pair<>(
- pullbackStartProgress, pullbackMaxProgress);
+ controller.setEndAction(() -> activity.getStateManager().goToState(
+ controller.getInterpolatedProgress() > 0.5 ? OVERVIEW : BACKGROUND_APP, false));
+ return controller;
}
@Override
@@ -382,6 +281,9 @@
@Override
public boolean switchToRecentsIfVisible(Runnable onCompleteCallback) {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.OVERIEW_NOT_ALLAPPS, "switchToRecentsIfVisible");
+ }
Launcher launcher = getVisibleLauncher();
if (launcher == null) {
return false;
@@ -407,7 +309,7 @@
}
@Override
- public boolean shouldMinimizeSplitScreen() {
+ public boolean allowMinimizeSplitScreen() {
return true;
}
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 52b40a9..e7fe142 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandler.java
@@ -17,8 +17,7 @@
import static com.android.launcher3.BaseActivity.INVISIBLE_BY_STATE_HANDLER;
import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAGS;
-import static com.android.launcher3.LauncherState.BACKGROUND_APP;
-import static com.android.launcher3.LauncherState.OVERVIEW;
+import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.anim.Interpolators.DEACCEL;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2;
@@ -32,26 +31,25 @@
import static com.android.quickstep.GestureState.GestureEndTarget.RECENTS;
import static com.android.quickstep.GestureState.STATE_END_TARGET_ANIMATION_FINISHED;
import static com.android.quickstep.GestureState.STATE_RECENTS_SCROLLING_FINISHED;
-import static com.android.quickstep.GestureState.STATE_TASK_APPEARED_DURING_SWITCH;
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.util.WindowSizeStrategy.LAUNCHER_ACTIVITY_SIZE_STRATEGY;
import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD;
import android.animation.Animator;
import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
import android.graphics.PointF;
-import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Build;
import android.os.SystemClock;
+import android.os.UserHandle;
import android.view.View;
import android.view.View.OnApplyWindowInsetsListener;
import android.view.ViewTreeObserver.OnDrawListener;
@@ -64,6 +62,7 @@
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimationSuccessListener;
@@ -74,17 +73,16 @@
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.launcher3.util.TraceHelper;
+import com.android.launcher3.views.FloatingIconView;
import com.android.quickstep.BaseActivityInterface.AnimationFactory;
-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.LayoutUtils;
import com.android.quickstep.util.RectFSpringAnim;
import com.android.quickstep.util.ShelfPeekAnim;
import com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState;
-import com.android.quickstep.util.TaskViewSimulator;
+import com.android.quickstep.util.StaggeredWorkspaceAnim;
+import com.android.quickstep.util.TransformParams.TargetAlphaProvider;
import com.android.quickstep.views.LiveTileOverlay;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
@@ -97,8 +95,8 @@
* Handles the navigation gestures when Launcher is the default home activity.
*/
@TargetApi(Build.VERSION_CODES.O)
-public class LauncherSwipeHandler<T extends BaseDraggingActivity>
- extends BaseSwipeUpHandler<T, RecentsView> implements OnApplyWindowInsetsListener {
+public class LauncherSwipeHandler extends BaseSwipeUpHandler<Launcher, RecentsView>
+ implements OnApplyWindowInsetsListener {
private static final String TAG = LauncherSwipeHandler.class.getSimpleName();
private static final String[] STATE_NAMES = DEBUG_STATES ? new String[16] : null;
@@ -152,7 +150,6 @@
STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_DRAWN | STATE_LAUNCHER_STARTED;
public static final long MAX_SWIPE_DURATION = 350;
- public static final long MIN_SWIPE_DURATION = 80;
public static final long MIN_OVERSHOOT_DURATION = 120;
public static final float MIN_PROGRESS_FOR_OVERVIEW = 0.7f;
@@ -181,9 +178,6 @@
private AnimatorPlaybackController mLauncherTransitionController;
private boolean mHasLauncherTransitionControllerStarted;
- private final TaskViewSimulator mTaskViewSimulator;
- private AnimatorPlaybackController mWindowTransitionController;
-
private AnimationFactory mAnimationFactory = (t) -> { };
private boolean mWasLauncherAlreadyVisible;
@@ -204,12 +198,10 @@
TaskAnimationManager taskAnimationManager, GestureState gestureState,
long touchTimeMs, boolean continuingLastGesture,
InputConsumerController inputConsumer) {
- super(context, deviceState, gestureState, inputConsumer);
+ super(context, deviceState, gestureState, inputConsumer, LAUNCHER_ACTIVITY_SIZE_STRATEGY);
mTaskAnimationManager = taskAnimationManager;
mTouchTimeMs = touchTimeMs;
mContinuingLastGesture = continuingLastGesture;
- mTaskViewSimulator = new TaskViewSimulator(
- context, LayoutUtils::calculateLauncherTaskSize, true);
initAfterSubclassConstructor();
initStateCallbacks();
@@ -265,8 +257,6 @@
| STATE_RECENTS_SCROLLING_FINISHED,
this::onSettledOnEndTarget);
- mGestureState.runOnceAtState(STATE_TASK_APPEARED_DURING_SWITCH, this::onTaskAppeared);
-
mStateCallback.runOnceAtState(STATE_HANDLER_INVALIDATED, this::invalidateHandler);
mStateCallback.runOnceAtState(STATE_LAUNCHER_PRESENT | STATE_HANDLER_INVALIDATED,
this::invalidateHandlerWithLauncher);
@@ -283,7 +273,7 @@
@Override
protected boolean onActivityInit(Boolean alreadyOnHome) {
super.onActivityInit(alreadyOnHome);
- final T activity = mActivityInterface.getCreatedActivity();
+ final Launcher activity = mActivityInterface.getCreatedActivity();
if (mActivity == activity) {
return true;
}
@@ -305,7 +295,6 @@
mRecentsView = activity.getOverviewPanel();
mRecentsView.setOnPageTransitionEndCallback(null);
- linkRecentsViewScroll();
addLiveTileOverlay();
mStateCallback.setState(STATE_LAUNCHER_PRESENT);
@@ -322,6 +311,8 @@
// so we need to kick off switching to the overview predictions as soon as possible
mActivityInterface.updateOverviewPredictionState();
}
+ linkRecentsViewScroll();
+
return true;
}
@@ -331,7 +322,7 @@
}
private void onLauncherStart() {
- final T activity = mActivityInterface.getCreatedActivity();
+ final Launcher activity = mActivityInterface.getCreatedActivity();
if (mActivity != activity) {
return;
}
@@ -344,8 +335,7 @@
if (mGestureState.getEndTarget() != HOME) {
Runnable initAnimFactory = () -> {
mAnimationFactory = mActivityInterface.prepareRecentsUI(
- mWasLauncherAlreadyVisible, true,
- this::onAnimatorPlaybackControllerCreated);
+ mWasLauncherAlreadyVisible, this::onAnimatorPlaybackControllerCreated);
maybeUpdateRecentsAttachedState(false /* animate */);
};
if (mWasLauncherAlreadyVisible) {
@@ -522,34 +512,6 @@
mAnimationFactory.createActivityInterface(mTransitionDragLength);
}
- @Override
- protected void updateSource(Rect stackBounds, RemoteAnimationTargetCompat runningTarget) {
- super.updateSource(stackBounds, runningTarget);
- mTaskViewSimulator.setPreview(runningTarget, mRecentsAnimationTargets);
- }
-
- @Override
- protected void initTransitionEndpoints(DeviceProfile dp) {
- super.initTransitionEndpoints(dp);
- mTaskViewSimulator.setDp(dp, false /* isOpening */);
- mTaskViewSimulator.setLayoutRotation(
- mDeviceState.getCurrentActiveRotation(),
- mDeviceState.getDisplayRotation());
-
- AnimatorSet anim = new AnimatorSet();
- anim.setDuration(mTransitionDragLength * 2);
- anim.setInterpolator(t -> t * mDragLengthFactor);
- anim.play(ObjectAnimator.ofFloat(mTaskViewSimulator.recentsViewScale,
- AnimatedFloat.VALUE,
- mTaskViewSimulator.getFullScreenScale(), 1));
- anim.play(ObjectAnimator.ofFloat(mTaskViewSimulator.fullScreenProgress,
- AnimatedFloat.VALUE,
- BACKGROUND_APP.getOverviewFullscreenProgress(),
- OVERVIEW.getOverviewFullscreenProgress()));
- mWindowTransitionController =
- AnimatorPlaybackController.wrap(anim, mTransitionDragLength * 2);
- }
-
/**
* We don't want to change mLauncherTransitionController if mGestureState.getEndTarget() == HOME
* (it has its own animation) or if we're already animating the current controller.
@@ -580,18 +542,11 @@
@Override
public void updateFinalShift() {
- if (mRecentsAnimationTargets != null) {
- // Base class expects applyTransformUnchecked to be called here.
- // TODO: Remove this dependency for swipe-up animation.
- // applyTransformUnchecked();
- updateSysUiFlags(mCurrentShift.value);
- }
-
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
if (mRecentsAnimationTargets != null) {
LiveTileOverlay.INSTANCE.update(
- mAppWindowAnimationHelper.getCurrentRectWithInsets(),
- mAppWindowAnimationHelper.getCurrentCornerRadius());
+ mTaskViewSimulator.getCurrentCropRect(),
+ mTaskViewSimulator.getCurrentCornerRadius());
}
}
@@ -603,16 +558,8 @@
}
}
- if (mWindowTransitionController != null) {
- float progress = mCurrentShift.value / mDragLengthFactor;
- mWindowTransitionController.setPlayFraction(progress);
- mTransformParams
- .setTargetSet(mRecentsAnimationTargets)
- .setLauncherOnTop(true);
-
- mTaskViewSimulator.setScroll(mRecentsView == null ? 0 : mRecentsView.getScrollOffset());
- mTaskViewSimulator.apply(mTransformParams);
- }
+ updateSysUiFlags(mCurrentShift.value);
+ applyWindowTransform();
updateLauncherTransitionProgress();
}
@@ -631,17 +578,21 @@
* @param windowProgress 0 == app, 1 == overview
*/
private void updateSysUiFlags(float windowProgress) {
- if (mRecentsView != null) {
+ if (mRecentsAnimationController != null && mRecentsView != null) {
+ TaskView runningTask = mRecentsView.getRunningTaskView();
TaskView centermostTask = mRecentsView.getTaskViewNearestToCenterOfScreen();
int centermostTaskFlags = centermostTask == null ? 0
: centermostTask.getThumbnail().getSysUiStatusNavFlags();
- boolean useHomeScreenFlags = windowProgress > 1 - UPDATE_SYSUI_FLAGS_THRESHOLD;
+ boolean swipeUpThresholdPassed = windowProgress > 1 - UPDATE_SYSUI_FLAGS_THRESHOLD;
+ boolean quickswitchThresholdPassed = centermostTask != runningTask;
+
// We will handle the sysui flags based on the centermost task view.
- if (mRecentsAnimationController != null) {
- mRecentsAnimationController.setWindowThresholdCrossed(centermostTaskFlags != 0
- && useHomeScreenFlags);
- }
- int sysuiFlags = useHomeScreenFlags ? 0 : centermostTaskFlags;
+ mRecentsAnimationController.setUseLauncherSystemBarFlags(
+ (swipeUpThresholdPassed || quickswitchThresholdPassed)
+ && centermostTaskFlags != 0);
+ mRecentsAnimationController.setSplitScreenMinimized(swipeUpThresholdPassed);
+
+ int sysuiFlags = swipeUpThresholdPassed ? 0 : centermostTaskFlags;
mActivity.getSystemUiController().updateUiState(UI_STATE_OVERVIEW, sysuiFlags);
}
}
@@ -682,7 +633,7 @@
*/
@UiThread
private void notifyGestureStartedAsync() {
- final T curActivity = mActivity;
+ final Launcher curActivity = mActivity;
if (curActivity != null) {
// Once the gesture starts, we can no longer transition home through the button, so
// reset the force override of the activity visibility
@@ -768,20 +719,17 @@
}
}
- private void onTaskAppeared() {
- RemoteAnimationTargetCompat app = mGestureState.getAnimationTarget();
- if (mRecentsAnimationController != null && app != null) {
-
- // TODO(b/152480470): Update Task target animation after onTaskAppeared holistically.
- /* android.util.Log.d("LauncherSwipeHandler", "onTaskAppeared");
-
- final boolean result = mRecentsAnimationController.removeTaskTarget(app);
- mGestureState.setAnimationTarget(null);
- android.util.Log.d("LauncherSwipeHandler", "removeTask, result=" + result); */
-
- mRecentsAnimationController.finish(false /* toRecents */,
- null /* onFinishComplete */);
+ @Override
+ protected boolean handleTaskAppeared(RemoteAnimationTargetCompat appearedTaskTarget) {
+ if (mStateCallback.hasStates(STATE_HANDLER_INVALIDATED)) {
+ return false;
}
+ if (mGestureState.getEndTarget() == NEW_TASK
+ && appearedTaskTarget.taskId == mGestureState.getLastStartedTaskId()) {
+ reset();
+ return true;
+ }
+ return false;
}
private GestureEndTarget calculateEndTarget(PointF velocity, float endVelocity, boolean isFling,
@@ -968,26 +916,63 @@
Interpolator interpolator, GestureEndTarget target, PointF velocityPxPerMs) {
// Set the state, but don't notify until the animation completes
mGestureState.setEndTarget(target, false /* isAtomic */);
-
maybeUpdateRecentsAttachedState();
if (mGestureState.getEndTarget() == HOME) {
HomeAnimationFactory homeAnimFactory;
if (mActivity != null) {
- homeAnimFactory = mActivityInterface.prepareHomeUI();
- } else {
- homeAnimFactory = new HomeAnimationFactory() {
- @NonNull
+ final TaskView runningTaskView = mRecentsView.getRunningTaskView();
+ final View workspaceView;
+ if (runningTaskView != null
+ && runningTaskView.getTask().key.getComponent() != null) {
+ workspaceView = mActivity.getWorkspace().getFirstMatchForAppClose(
+ runningTaskView.getTask().key.getComponent().getPackageName(),
+ UserHandle.of(runningTaskView.getTask().key.userId));
+ } else {
+ workspaceView = null;
+ }
+ final RectF iconLocation = new RectF();
+ boolean canUseWorkspaceView =
+ workspaceView != null && workspaceView.isAttachedToWindow();
+ FloatingIconView floatingIconView = canUseWorkspaceView
+ ? FloatingIconView.getFloatingIconView(mActivity, workspaceView,
+ true /* hideOriginal */, iconLocation, false /* isOpening */)
+ : null;
+
+ mActivity.getRootView().setForceHideBackArrow(true);
+
+ homeAnimFactory = new HomeAnimationFactory(floatingIconView) {
+
@Override
public RectF getWindowTargetRect() {
- RectF fallbackTarget = new RectF(mAppWindowAnimationHelper.getTargetRect());
- Utilities.scaleRectFAboutCenter(fallbackTarget, 0.25f);
- return fallbackTarget;
+ if (canUseWorkspaceView) {
+ return iconLocation;
+ } else {
+ return super.getWindowTargetRect();
+ }
}
@NonNull
@Override
public AnimatorPlaybackController createActivityAnimationToHome() {
+ // Return an empty APC here since we have an non-user controlled animation
+ // to home.
+ long accuracy = 2 * Math.max(mDp.widthPx, mDp.heightPx);
+ return mActivity.getStateManager().createAnimationToNewWorkspace(
+ NORMAL, accuracy, 0 /* animComponents */);
+ }
+
+ @Override
+ public void playAtomicAnimation(float velocity) {
+ new StaggeredWorkspaceAnim(mActivity, velocity,
+ true /* animateOverviewScrim */).start();
+ }
+ };
+
+ } else {
+ homeAnimFactory = new HomeAnimationFactory(null) {
+ @Override
+ public AnimatorPlaybackController createActivityAnimationToHome() {
return AnimatorPlaybackController.wrap(new AnimatorSet(), duration);
}
};
@@ -1028,12 +1013,24 @@
// skip doing any future work here for the current gesture.
return;
}
- if (target == NEW_TASK && mRecentsView != null
- && mRecentsView.getNextPage() == mRecentsView.getRunningTaskIndex()) {
- // We are about to launch the current running task, so use LAST_TASK state
- // instead of NEW_TASK. This could happen, for example, if our scroll is
- // aborted after we determined the target to be NEW_TASK.
- mGestureState.setEndTarget(LAST_TASK);
+ if (mRecentsView != null) {
+ int taskToLaunch = mRecentsView.getNextPage();
+ int runningTask = getLastAppearedTaskIndex();
+ boolean hasStartedNewTask = hasStartedNewTask();
+ if (target == NEW_TASK && taskToLaunch == runningTask
+ && !hasStartedNewTask) {
+ // We are about to launch the current running task, so use LAST_TASK
+ // state instead of NEW_TASK. This could happen, for example, if our
+ // scroll is aborted after we determined the target to be NEW_TASK.
+ mGestureState.setEndTarget(LAST_TASK);
+ } else if (target == LAST_TASK && hasStartedNewTask) {
+ // We are about to re-launch the previously running task, but we can't
+ // just finish the controller like we normally would because that would
+ // instead resume the last task that appeared, and not ensure that this
+ // task is restored to the top. To address this, re-launch the task as
+ // if it were a new task.
+ mGestureState.setEndTarget(NEW_TASK);
+ }
}
mGestureState.setState(STATE_END_TARGET_ANIMATION_FINISHED);
}
@@ -1078,9 +1075,10 @@
private void continueComputingRecentsScrollIfNecessary() {
if (!mGestureState.hasState(STATE_RECENTS_SCROLLING_FINISHED)
- && !mStateCallback.hasStates(STATE_HANDLER_INVALIDATED)) {
+ && !mStateCallback.hasStates(STATE_HANDLER_INVALIDATED)
+ && !mCanceled) {
computeRecentsScrollIfInvisible();
- mRecentsView.post(this::continueComputingRecentsScrollIfNecessary);
+ mRecentsView.postOnAnimation(this::continueComputingRecentsScrollIfNecessary);
}
}
@@ -1156,8 +1154,9 @@
@UiThread
private void startNewTaskInternal() {
- startNewTask(STATE_HANDLER_INVALIDATED, success -> {
+ startNewTask(success -> {
if (!success) {
+ reset();
// We couldn't launch the task, so take user to overview so they can
// decide what to do instead of staying in this broken state.
endLauncherTransitionController();
@@ -1167,6 +1166,12 @@
});
}
+ @Override
+ protected void onRestartLastAppearedTask() {
+ super.onRestartLastAppearedTask();
+ reset();
+ }
+
private void reset() {
mStateCallback.setStateOnUiThread(STATE_HANDLER_INVALIDATED);
}
@@ -1182,19 +1187,6 @@
.getAnimationPlayer().isStarted()) {
mLauncherTransitionController.getAnimationPlayer().cancel();
}
-
- if (mFinishingRecentsAnimationForNewTaskId != -1) {
- // If we are canceling mid-starting a new task, switch to the screenshot since the
- // recents animation has finished
- switchToScreenshot();
- TaskView newRunningTaskView = mRecentsView.getTaskView(
- mFinishingRecentsAnimationForNewTaskId);
- int newRunningTaskId = newRunningTaskView != null
- ? newRunningTaskView.getTask().key.id
- : -1;
- mRecentsView.setCurrentTask(newRunningTaskId);
- mGestureState.setFinishingRecentsAnimationTaskId(newRunningTaskId);
- }
}
private void invalidateHandler() {
@@ -1333,8 +1325,7 @@
}
private void setTargetAlphaProvider(TargetAlphaProvider provider) {
- mAppWindowAnimationHelper.setTaskAlphaCallback(provider);
- mTaskViewSimulator.setTaskAlphaCallback(provider);
+ mTransformParams.setTaskAlphaCallback(provider);
updateFinalShift();
}
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 52a2558..03d522e 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsActivity.java
@@ -15,6 +15,9 @@
*/
package com.android.quickstep;
+import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
+import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
+
import static com.android.launcher3.QuickstepAppTransitionManagerImpl.RECENTS_LAUNCH_DURATION;
import static com.android.launcher3.QuickstepAppTransitionManagerImpl.STATUS_BAR_TRANSITION_DURATION;
import static com.android.launcher3.QuickstepAppTransitionManagerImpl.STATUS_BAR_TRANSITION_PRE_DELAY;
@@ -29,22 +32,32 @@
import android.app.ActivityOptions;
import android.content.Intent;
import android.content.res.Configuration;
+import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.view.View;
+import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherAnimationRunner;
import com.android.launcher3.R;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.compat.AccessibilityManagerCompat;
+import com.android.launcher3.statemanager.StateManager;
+import com.android.launcher3.statemanager.StateManager.StateHandler;
+import com.android.launcher3.statemanager.StatefulActivity;
+import com.android.launcher3.util.ActivityTracker;
import com.android.launcher3.util.ObjectWrapper;
+import com.android.launcher3.util.SystemUiController;
+import com.android.launcher3.util.Themes;
import com.android.launcher3.views.BaseDragLayer;
+import com.android.quickstep.fallback.FallbackRecentsStateController;
import com.android.quickstep.fallback.FallbackRecentsView;
import com.android.quickstep.fallback.RecentsRootView;
-import com.android.quickstep.util.AppWindowAnimationHelper;
+import com.android.quickstep.fallback.RecentsState;
+import com.android.quickstep.views.OverviewActionsView;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.ActivityOptionsCompat;
@@ -52,26 +65,40 @@
import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
/**
* A recents activity that shows the recently launched tasks as swipable task cards.
* See {@link com.android.quickstep.views.RecentsView}.
*/
-public final class RecentsActivity extends BaseRecentsActivity {
+public final class RecentsActivity extends StatefulActivity<RecentsState> {
public static final String EXTRA_THUMBNAIL = "thumbnailData";
public static final String EXTRA_TASK_ID = "taskID";
+ public static final ActivityTracker<RecentsActivity> ACTIVITY_TRACKER =
+ new ActivityTracker<>();
private Handler mUiHandler = new Handler(Looper.getMainLooper());
private RecentsRootView mRecentsRootView;
private FallbackRecentsView mFallbackRecentsView;
+ private OverviewActionsView mActionsView;
- @Override
+ private Configuration mOldConfig;
+
+ private StateManager<RecentsState> mStateManager;
+
+ /**
+ * Init drag layer and overview panel views.
+ */
protected void initViews() {
setContentView(R.layout.fallback_recents_activity);
mRecentsRootView = findViewById(R.id.drag_layer);
mFallbackRecentsView = findViewById(R.id.overview_panel);
+ mActionsView = findViewById(R.id.overview_actions_view);
+
mRecentsRootView.recreateControllers();
- mFallbackRecentsView.init(findViewById(R.id.overview_actions_view));
+ mFallbackRecentsView.init(mActionsView);
}
@Override
@@ -104,25 +131,38 @@
intent.removeExtra(EXTRA_TASK_ID);
intent.removeExtra(EXTRA_THUMBNAIL);
super.onNewIntent(intent);
+ ACTIVITY_TRACKER.handleNewIntent(this, intent);
}
- @Override
+ /**
+ * Logic for when device configuration changes (rotation, screen size change, multi-window,
+ * etc.)
+ */
protected void onHandleConfigChanged() {
- super.onHandleConfigChanged();
+ mUserEventDispatcher = null;
+ initDeviceProfile();
+
+ AbstractFloatingView.closeOpenViews(this, true,
+ AbstractFloatingView.TYPE_ALL & ~AbstractFloatingView.TYPE_REBIND_SAFE);
+ dispatchDeviceProfileChanged();
+
+ reapplyUi();
mRecentsRootView.recreateControllers();
}
- @Override
- protected void reapplyUi() {
- mRecentsRootView.dispatchInsets();
- }
-
- @Override
+ /**
+ * Generate the device profile to use in this activity.
+ * @return device profile
+ */
protected DeviceProfile createDeviceProfile() {
DeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(this).getDeviceProfile(this);
+ DeviceProfile dp1 = InvariantDeviceProfile.INSTANCE.get(this).getDeviceProfile(this);
+
+ // In case we are reusing IDP, create a copy so that we don't conflict with Launcher
+ // activity.
return (mRecentsRootView != null) && isInMultiWindowMode()
- ? dp.getMultiWindowProfile(this, mRecentsRootView.getLastKnownSize())
- : super.createDeviceProfile();
+ ? dp.getMultiWindowProfile(this, getMultiWindowDisplaySize())
+ : dp1.copy(this);
}
@Override
@@ -140,6 +180,10 @@
return (T) mFallbackRecentsView;
}
+ public OverviewActionsView getActionsView() {
+ return mActionsView;
+ }
+
@Override
public void returnToHomescreen() {
super.returnToHomescreen();
@@ -161,12 +205,7 @@
RemoteAnimationTargetCompat[] wallpaperTargets, AnimationResult result) {
AnimatorSet anim = composeRecentsLaunchAnimator(taskView, appTargets,
wallpaperTargets);
- anim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mFallbackRecentsView.resetViewUI();
- }
- });
+ anim.addListener(resetStateListener());
result.setAnimation(anim, RecentsActivity.this);
}
};
@@ -184,25 +223,17 @@
RemoteAnimationTargetCompat[] wallpaperTargets) {
AnimatorSet target = new AnimatorSet();
boolean activityClosing = taskIsATargetWithMode(appTargets, getTaskId(), MODE_CLOSING);
- AppWindowAnimationHelper helper = new AppWindowAnimationHelper(
- mFallbackRecentsView.getPagedViewOrientedState(), this);
Animator recentsAnimator = getRecentsWindowAnimator(taskView, !activityClosing, appTargets,
- wallpaperTargets, null /* depthController */,
- helper);
+ wallpaperTargets, null /* depthController */);
target.play(recentsAnimator.setDuration(RECENTS_LAUNCH_DURATION));
// Found a visible recents task that matches the opening app, lets launch the app from there
if (activityClosing) {
Animator adjacentAnimation = mFallbackRecentsView
- .createAdjacentPageAnimForTaskLaunch(taskView, helper);
+ .createAdjacentPageAnimForTaskLaunch(taskView);
adjacentAnimation.setInterpolator(Interpolators.TOUCH_RESPONSE_INTERPOLATOR);
adjacentAnimation.setDuration(RECENTS_LAUNCH_DURATION);
- adjacentAnimation.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mFallbackRecentsView.resetTaskVisuals();
- }
- });
+ adjacentAnimation.addListener(resetStateListener());
target.play(adjacentAnimation);
}
return target;
@@ -214,13 +245,14 @@
// onActivityStart callback.
mFallbackRecentsView.setContentAlpha(1);
super.onStart();
- mFallbackRecentsView.resetTaskVisuals();
}
@Override
protected void onStop() {
super.onStop();
- mFallbackRecentsView.reset();
+
+ // Workaround for b/78520668, explicitly trim memory once UI is hidden
+ onTrimMemory(TRIM_MEMORY_UI_HIDDEN);
}
@Override
@@ -232,4 +264,98 @@
public void onTaskLaunched() {
mFallbackRecentsView.resetTaskVisuals();
}
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mStateManager = new StateManager<>(this, RecentsState.DEFAULT);
+
+ mOldConfig = new Configuration(getResources().getConfiguration());
+ initDeviceProfile();
+ initViews();
+
+ getSystemUiController().updateUiState(SystemUiController.UI_STATE_BASE_WINDOW,
+ Themes.getAttrBoolean(this, R.attr.isWorkspaceDarkText));
+ ACTIVITY_TRACKER.handleCreate(this);
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ int diff = newConfig.diff(mOldConfig);
+ if ((diff & (CONFIG_ORIENTATION | CONFIG_SCREEN_SIZE)) != 0) {
+ onHandleConfigChanged();
+ }
+ mOldConfig.setTo(newConfig);
+ super.onConfigurationChanged(newConfig);
+ }
+
+ /**
+ * Initialize/update the device profile.
+ */
+ private void initDeviceProfile() {
+ mDeviceProfile = createDeviceProfile();
+ onDeviceProfileInitiated();
+ }
+
+ @Override
+ public void onEnterAnimationComplete() {
+ super.onEnterAnimationComplete();
+ // After the transition to home, enable the high-res thumbnail loader if it wasn't enabled
+ // as a part of quickstep, so that high-res thumbnails can load the next time we enter
+ // overview
+ RecentsModel.INSTANCE.get(this).getThumbnailCache()
+ .getHighResLoadingState().setVisible(true);
+ }
+
+ @Override
+ public void onTrimMemory(int level) {
+ super.onTrimMemory(level);
+ RecentsModel.INSTANCE.get(this).onTrimMemory(level);
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ ACTIVITY_TRACKER.onActivityDestroyed(this);
+ }
+
+ @Override
+ public void onBackPressed() {
+ // TODO: Launch the task we came from
+ startHome();
+ }
+
+ public void startHome() {
+ startActivity(new Intent(Intent.ACTION_MAIN)
+ .addCategory(Intent.CATEGORY_HOME)
+ .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+ }
+
+ @Override
+ protected StateHandler<RecentsState>[] createStateHandlers() {
+ return new StateHandler[] { new FallbackRecentsStateController(this) };
+ }
+
+ @Override
+ public StateManager<RecentsState> getStateManager() {
+ return mStateManager;
+ }
+
+ @Override
+ public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
+ super.dump(prefix, fd, writer, args);
+ writer.println(prefix + "Misc:");
+ dumpMisc(prefix + "\t", writer);
+ }
+
+ private AnimatorListenerAdapter resetStateListener() {
+ return new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mFallbackRecentsView.resetTaskVisuals();
+ mStateManager.reapplyState();
+ }
+ };
+ }
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskOverlayFactory.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskOverlayFactory.java
index b44d6df..042c542 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskOverlayFactory.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskOverlayFactory.java
@@ -22,6 +22,7 @@
import android.graphics.Insets;
import android.graphics.Matrix;
import android.graphics.Rect;
+import android.widget.Toast;
import com.android.launcher3.BaseActivity;
import com.android.launcher3.BaseDraggingActivity;
@@ -109,16 +110,26 @@
public void initOverlay(Task task, ThumbnailData thumbnail, Matrix matrix) {
ImageActionsApi imageApi = new ImageActionsApi(
mApplicationContext, mThumbnailView::getThumbnail);
+ final boolean isAllowedByPolicy = thumbnail.isRealSnapshot;
+
getActionsView().setCallbacks(new OverlayUICallbacks() {
@Override
public void onShare() {
- imageApi.startShareActivity();
+ if (isAllowedByPolicy) {
+ imageApi.startShareActivity();
+ } else {
+ showBlockedByPolicyMessage();
+ }
}
@Override
public void onScreenshot() {
- imageApi.saveScreenshot(mThumbnailView.getThumbnail(),
- getTaskSnapshotBounds(), getTaskSnapshotInsets(), task.key.id);
+ if (isAllowedByPolicy) {
+ imageApi.saveScreenshot(mThumbnailView.getThumbnail(),
+ getTaskSnapshotBounds(), getTaskSnapshotInsets(), task.key.id);
+ } else {
+ showBlockedByPolicyMessage();
+ }
}
});
}
@@ -152,6 +163,13 @@
// TODO: return the real insets
return Insets.of(0, 0, 0, 0);
}
+
+ private void showBlockedByPolicyMessage() {
+ Toast.makeText(
+ mThumbnailView.getContext(),
+ R.string.blocked_by_policy,
+ Toast.LENGTH_LONG).show();
+ }
}
/**
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 47c07af..9a7a491 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskViewUtils.java
@@ -38,6 +38,7 @@
import com.android.launcher3.statehandlers.DepthController;
import com.android.quickstep.util.AppWindowAnimationHelper;
import com.android.quickstep.util.MultiValueUpdateListener;
+import com.android.quickstep.util.TransformParams;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.Task;
@@ -123,18 +124,19 @@
public static Animator getRecentsWindowAnimator(TaskView v, boolean skipViewChanges,
RemoteAnimationTargetCompat[] appTargets,
RemoteAnimationTargetCompat[] wallpaperTargets,
- DepthController depthController,
- final AppWindowAnimationHelper inOutHelper) {
+ DepthController depthController) {
+ AppWindowAnimationHelper inOutHelper = new AppWindowAnimationHelper(
+ v.getRecentsView().getPagedViewOrientedState(), v.getContext());
+
SyncRtSurfaceTransactionApplierCompat applier =
new SyncRtSurfaceTransactionApplierCompat(v);
final RemoteAnimationTargets targets =
new RemoteAnimationTargets(appTargets, wallpaperTargets, MODE_OPENING);
targets.addDependentTransactionApplier(applier);
- AppWindowAnimationHelper.TransformParams params =
- new AppWindowAnimationHelper.TransformParams()
+ TransformParams params =
+ new TransformParams()
.setSyncTransactionApplier(applier)
- .setTargetSet(targets)
- .setLauncherOnTop(true);
+ .setTargetSet(targets);
AnimatorSet animatorSet = new AnimatorSet();
final RecentsView recentsView = v.getRecentsView();
@@ -148,11 +150,9 @@
final RectF mThumbnailRect;
{
- inOutHelper.setTaskAlphaCallback((t, alpha) -> mTaskAlpha.value);
-
+ params.setTaskAlphaCallback((t, alpha) -> mTaskAlpha.value);
inOutHelper.prepareAnimation(
- BaseActivity.fromContext(v.getContext()).getDeviceProfile(),
- true /* isOpening */);
+ BaseActivity.fromContext(v.getContext()).getDeviceProfile());
inOutHelper.fromTaskThumbnailView(v.getThumbnail(), (RecentsView) v.getParent(),
targets.apps.length == 0 ? null : targets.apps[0]);
@@ -175,7 +175,7 @@
v.getRecentsView().getClipAnimationHelper();
if (liveTileAnimationHelper != null) {
// Append the surface transform params for the live tile app.
- AppWindowAnimationHelper.TransformParams liveTileParams =
+ TransformParams liveTileParams =
v.getRecentsView().getLiveTileParams(true /* mightNeedToRefill */);
if (liveTileParams != null) {
SurfaceParams[] liveTileSurfaceParams =
@@ -186,7 +186,7 @@
}
}
// Apply surface transform using the surface params list.
- AppWindowAnimationHelper.applySurfaceParams(params.getSyncTransactionApplier(),
+ params.applySurfaceParams(
surfaceParamsList.toArray(new SurfaceParams[surfaceParamsList.size()]));
// Get the task bounds for the app that's being opened after surface transform
// update.
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
index ce7a141..4b2fc75 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
@@ -30,8 +30,6 @@
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_TRACING_ENABLED;
import android.annotation.TargetApi;
-import android.app.ActivityManager;
-import android.app.ActivityManager.RunningTaskInfo;
import android.app.PendingIntent;
import android.app.RemoteAction;
import android.app.Service;
@@ -518,8 +516,13 @@
private GestureState createGestureState() {
GestureState gestureState = new GestureState(mOverviewComponentObserver,
ActiveGestureLog.INSTANCE.generateAndSetLogId());
- gestureState.updateRunningTask(TraceHelper.whitelistIpcs("getRunningTask.0",
- () -> mAM.getRunningTask(false /* filterOnlyVisibleRecents */)));
+ if (mTaskAnimationManager.isRecentsAnimationRunning()) {
+ gestureState.updateRunningTask(mGestureState.getRunningTask());
+ gestureState.updateLastStartedTaskId(mGestureState.getLastStartedTaskId());
+ } else {
+ gestureState.updateRunningTask(TraceHelper.whitelistIpcs("getRunningTask.0",
+ () -> mAM.getRunningTask(false /* filterOnlyVisibleRecents */)));
+ }
return gestureState;
}
@@ -599,15 +602,24 @@
}
private void handleOrientationSetup(InputConsumer baseInputConsumer) {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.PAUSE_NOT_DETECTED, "handleOrientationSetup.1");
+ }
if (!isFixedRotationTransformEnabled(this)) {
return;
}
mDeviceState.enableMultipleRegions(baseInputConsumer instanceof OtherActivityInputConsumer);
BaseDraggingActivity activity =
mOverviewComponentObserver.getActivityInterface().getCreatedActivity();
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.PAUSE_NOT_DETECTED, "handleOrientationSetup.2");
+ }
if (activity == null || !(activity.getOverviewPanel() instanceof RecentsView)) {
return;
}
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.PAUSE_NOT_DETECTED, "handleOrientationSetup.3");
+ }
((RecentsView) activity.getOverviewPanel())
.setLayoutRotation(mDeviceState.getCurrentActiveRotation(),
mDeviceState.getDisplayRotation());
@@ -637,14 +649,7 @@
runningComponent != null && runningComponent.equals(homeComponent);
}
- if (previousGestureState.getFinishingRecentsAnimationTaskId() > 0) {
- // If the finish animation was interrupted, then continue using the other activity input
- // consumer but with the next task as the running task
- RunningTaskInfo info = new ActivityManager.RunningTaskInfo();
- info.id = previousGestureState.getFinishingRecentsAnimationTaskId();
- gestureState.updateRunningTask(info);
- return createOtherActivityInputConsumer(previousGestureState, gestureState, event);
- } else if (gestureState.getRunningTask() == null) {
+ if (gestureState.getRunningTask() == null) {
return mResetGestureInputConsumer;
} else if (previousGestureState.isRunningAnimationToLauncher()
|| gestureState.getActivityInterface().isResumed()
@@ -658,25 +663,22 @@
} else if (mDeviceState.isGestureBlockedActivity(gestureState.getRunningTask())) {
return mResetGestureInputConsumer;
} else {
- return createOtherActivityInputConsumer(previousGestureState, gestureState, event);
+ return createOtherActivityInputConsumer(gestureState, event);
}
}
- private InputConsumer createOtherActivityInputConsumer(GestureState previousGestureState,
- GestureState gestureState, MotionEvent event) {
+ private InputConsumer createOtherActivityInputConsumer(GestureState gestureState,
+ MotionEvent event) {
- final boolean shouldDefer;
final BaseSwipeUpHandler.Factory factory;
-
if (!mOverviewComponentObserver.isHomeAndOverviewSame()) {
- shouldDefer = previousGestureState.getFinishingRecentsAnimationTaskId() < 0;
factory = mFallbackSwipeHandlerFactory;
} else {
- shouldDefer = gestureState.getActivityInterface().deferStartingActivity(mDeviceState,
- event);
factory = mLauncherSwipeHandlerFactory;
}
+ final boolean shouldDefer = !mOverviewComponentObserver.isHomeAndOverviewSame()
+ || gestureState.getActivityInterface().deferStartingActivity(mDeviceState, event);
final boolean disableHorizontalSwipe = mDeviceState.isInExclusionRegion(event);
return new OtherActivityInputConsumer(this, mDeviceState, mTaskAnimationManager,
gestureState, shouldDefer, this::onConsumerInactive,
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackRecentsStateController.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
new file mode 100644
index 0000000..3f1e7ba
--- /dev/null
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.fallback;
+
+import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
+import static com.android.launcher3.anim.Interpolators.LINEAR;
+import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_MODAL;
+import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE;
+import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_X;
+import static com.android.launcher3.states.StateAnimationConfig.PLAY_ATOMIC_OVERVIEW_PEEK;
+import static com.android.launcher3.states.StateAnimationConfig.PLAY_ATOMIC_OVERVIEW_SCALE;
+import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW;
+import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_OFFSET;
+import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS;
+import static com.android.quickstep.views.RecentsView.TASK_MODALNESS;
+
+import com.android.launcher3.anim.PendingAnimation;
+import com.android.launcher3.anim.PropertySetter;
+import com.android.launcher3.statemanager.StateManager.StateHandler;
+import com.android.launcher3.states.StateAnimationConfig;
+import com.android.launcher3.util.MultiValueAlpha;
+import com.android.quickstep.RecentsActivity;
+import com.android.quickstep.views.ClearAllButton;
+
+/**
+ * State controller for fallback recents activity
+ */
+public class FallbackRecentsStateController implements StateHandler<RecentsState> {
+
+ private final StateAnimationConfig mNoConfig = new StateAnimationConfig();
+ private final RecentsActivity mActivity;
+ private final FallbackRecentsView mRecentsView;
+
+ public FallbackRecentsStateController(RecentsActivity activity) {
+ mActivity = activity;
+ mRecentsView = activity.getOverviewPanel();
+ }
+
+ @Override
+ public void setState(RecentsState state) {
+ mRecentsView.updateEmptyMessage();
+ mRecentsView.resetTaskVisuals();
+ setProperties(state, mNoConfig, PropertySetter.NO_ANIM_PROPERTY_SETTER);
+ }
+
+ @Override
+ public void setStateWithAnimation(RecentsState toState, StateAnimationConfig config,
+ PendingAnimation setter) {
+ if (!config.hasAnimationFlag(PLAY_ATOMIC_OVERVIEW_PEEK | PLAY_ATOMIC_OVERVIEW_SCALE)) {
+ // The entire recents animation is played atomically.
+ return;
+ }
+ if (config.hasAnimationFlag(SKIP_OVERVIEW)) {
+ return;
+ }
+ // While animating into recents, update the visible task data as needed
+ setter.addOnFrameCallback(mRecentsView::loadVisibleTaskData);
+ mRecentsView.updateEmptyMessage();
+
+ setProperties(toState, config, setter);
+ }
+
+ private void setProperties(RecentsState state, StateAnimationConfig config,
+ PropertySetter setter) {
+ float buttonAlpha = state.hasButtons() ? 1 : 0;
+ setter.setFloat(mRecentsView.getClearAllButton(), ClearAllButton.VISIBILITY_ALPHA,
+ buttonAlpha, LINEAR);
+ setter.setFloat(mActivity.getActionsView().getVisibilityAlpha(),
+ MultiValueAlpha.VALUE, buttonAlpha, LINEAR);
+
+ float[] scaleAndOffset = state.getOverviewScaleAndOffset(mActivity);
+ setter.setFloat(mRecentsView, SCALE_PROPERTY, scaleAndOffset[0],
+ config.getInterpolator(ANIM_OVERVIEW_SCALE, LINEAR));
+ setter.setFloat(mRecentsView, ADJACENT_PAGE_OFFSET, scaleAndOffset[1],
+ config.getInterpolator(ANIM_OVERVIEW_TRANSLATE_X, LINEAR));
+
+ setter.setFloat(mRecentsView, TASK_MODALNESS, state.getOverviewModalness(),
+ config.getInterpolator(ANIM_OVERVIEW_MODAL, LINEAR));
+ setter.setFloat(mRecentsView, FULLSCREEN_PROGRESS, state.isFullScreen() ? 1 : 0, LINEAR);
+ }
+}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackRecentsView.java
index 3cf9b2c..1ab317b 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackRecentsView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackRecentsView.java
@@ -15,48 +15,28 @@
*/
package com.android.quickstep.fallback;
-import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
+import static com.android.quickstep.fallback.RecentsState.DEFAULT;
+import static com.android.quickstep.fallback.RecentsState.MODAL_TASK;
+import static com.android.quickstep.util.WindowSizeStrategy.FALLBACK_RECENTS_SIZE_STRATEGY;
+import android.annotation.TargetApi;
import android.app.ActivityManager.RunningTaskInfo;
import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Rect;
+import android.os.Build;
import android.util.AttributeSet;
-import android.util.FloatProperty;
-import android.view.View;
-import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.Utilities;
+import com.android.launcher3.statemanager.StateManager.StateListener;
import com.android.quickstep.RecentsActivity;
-import com.android.quickstep.util.LayoutUtils;
import com.android.quickstep.views.OverviewActionsView;
import com.android.quickstep.views.RecentsView;
-import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.Task.TaskKey;
import java.util.ArrayList;
-public class FallbackRecentsView extends RecentsView<RecentsActivity> {
-
- public static final FloatProperty<FallbackRecentsView> ZOOM_PROGRESS =
- new FloatProperty<FallbackRecentsView> ("zoomInProgress") {
-
- @Override
- public void setValue(FallbackRecentsView view, float value) {
- view.setZoomProgress(value);
- }
-
- @Override
- public Float get(FallbackRecentsView view) {
- return view.mZoomInProgress;
- }
- };
-
- private float mZoomInProgress = 0;
- private boolean mInOverviewState = true;
-
- private float mZoomScale = 1f;
+@TargetApi(Build.VERSION_CODES.R)
+public class FallbackRecentsView extends RecentsView<RecentsActivity>
+ implements StateListener<RecentsState> {
private RunningTaskInfo mRunningTaskInfo;
@@ -65,7 +45,8 @@
}
public FallbackRecentsView(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr, false);
+ super(context, attrs, defStyleAttr, FALLBACK_RECENTS_SIZE_STRATEGY);
+ mActivity.getStateManager().addStateListener(this);
}
@Override
@@ -81,84 +62,11 @@
}
@Override
- public void onViewAdded(View child) {
- super.onViewAdded(child);
- updateEmptyMessage();
- }
-
- @Override
- public void onViewRemoved(View child) {
- super.onViewRemoved(child);
- updateEmptyMessage();
- }
-
- @Override
- public void draw(Canvas canvas) {
- maybeDrawEmptyMessage(canvas);
- super.draw(canvas);
- }
-
- @Override
- public void reset() {
- super.reset();
- resetViewUI();
- }
-
- @Override
- protected void getTaskSize(DeviceProfile dp, Rect outRect) {
- LayoutUtils.calculateFallbackTaskSize(getContext(), dp, outRect);
- }
-
- @Override
public boolean shouldUseMultiWindowTaskSizeStrategy() {
// Just use the activity task size for multi-window as well.
return false;
}
- public void resetViewUI() {
- setZoomProgress(0);
- resetTaskVisuals();
- }
-
- public void setInOverviewState(boolean inOverviewState) {
- if (mInOverviewState != inOverviewState) {
- mInOverviewState = inOverviewState;
- if (mInOverviewState) {
- resetTaskVisuals();
- } else {
- setZoomProgress(1);
- }
- }
- }
-
- @Override
- public void resetTaskVisuals() {
- super.resetTaskVisuals();
- setFullscreenProgress(mFullscreenProgress);
- }
-
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- super.onLayout(changed, left, top, right, bottom);
-
- if (getTaskViewCount() == 0) {
- mZoomScale = 1f;
- } else {
- TaskView dummyTask = getTaskViewAt(0);
- mZoomScale = getTempAppWindowAnimationHelper()
- .updateForFullscreenOverview(dummyTask)
- .getSrcToTargetScale();
- }
-
- setZoomProgress(mZoomInProgress);
- }
-
- public void setZoomProgress(float progress) {
- mZoomInProgress = progress;
- SCALE_PROPERTY.set(this, Utilities.mapRange(mZoomInProgress, 1, mZoomScale));
- FULLSCREEN_PROGRESS.set(this, mZoomInProgress);
- }
-
public void onGestureAnimationStart(RunningTaskInfo runningTaskInfo) {
mRunningTaskInfo = runningTaskInfo;
onGestureAnimationStart(runningTaskInfo == null ? -1 : runningTaskInfo.taskId);
@@ -195,4 +103,37 @@
}
super.applyLoadPlan(tasks);
}
+
+ @Override
+ public void setModalStateEnabled(boolean isModalState) {
+ super.setModalStateEnabled(isModalState);
+ if (isModalState) {
+ mActivity.getStateManager().goToState(RecentsState.MODAL_TASK);
+ } else {
+ if (mActivity.isInState(RecentsState.MODAL_TASK)) {
+ mActivity.getStateManager().goToState(DEFAULT);
+ }
+ }
+ }
+
+ @Override
+ public void onStateTransitionStart(RecentsState toState) {
+ setOverviewStateEnabled(true);
+ setFreezeViewVisibility(true);
+ }
+
+ @Override
+ public void onStateTransitionComplete(RecentsState finalState) {
+ setOverlayEnabled(finalState == DEFAULT || finalState == MODAL_TASK);
+ setFreezeViewVisibility(false);
+ }
+
+ @Override
+ public void setOverviewStateEnabled(boolean enabled) {
+ super.setOverviewStateEnabled(enabled);
+ if (enabled) {
+ RecentsState state = mActivity.getStateManager().getState();
+ setDisallowScrollToClearAll(!state.hasButtons());
+ }
+ }
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/RecentsState.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/RecentsState.java
new file mode 100644
index 0000000..211a30c
--- /dev/null
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/RecentsState.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.fallback;
+
+import static com.android.launcher3.uioverrides.states.BackgroundAppState.getOverviewScaleAndOffsetForBackgroundState;
+import static com.android.launcher3.uioverrides.states.OverviewModalTaskState.getOverviewScaleAndOffsetForModalState;
+
+import android.content.Context;
+
+import com.android.launcher3.statemanager.BaseState;
+import com.android.quickstep.RecentsActivity;
+
+/**
+ * State definition for Fallback recents
+ */
+public class RecentsState implements BaseState<RecentsState> {
+
+ private static final int FLAG_MODAL = BaseState.getFlag(0);
+ private static final int FLAG_HAS_BUTTONS = BaseState.getFlag(1);
+ private static final int FLAG_FULL_SCREEN = BaseState.getFlag(2);
+
+ public static final RecentsState DEFAULT = new RecentsState(0, FLAG_HAS_BUTTONS);
+ public static final RecentsState MODAL_TASK = new ModalState(1,
+ FLAG_DISABLE_RESTORE | FLAG_HAS_BUTTONS | FLAG_MODAL);
+ public static final RecentsState BACKGROUND_APP = new BackgroundAppState(2,
+ FLAG_DISABLE_RESTORE | FLAG_NON_INTERACTIVE | FLAG_FULL_SCREEN);
+
+ public final int ordinal;
+ private final int mFlags;
+
+ private static final float NO_OFFSET = 0;
+ private static final float NO_SCALE = 1;
+
+ public RecentsState(int id, int flags) {
+ this.ordinal = id;
+ this.mFlags = flags;
+ }
+
+
+ @Override
+ public String toString() {
+ return "Ordinal-" + ordinal;
+ }
+
+ @Override
+ public final boolean hasFlag(int mask) {
+ return (mFlags & mask) != 0;
+ }
+
+ @Override
+ public int getTransitionDuration(Context context) {
+ return 250;
+ }
+
+ @Override
+ public RecentsState getHistoryForState(RecentsState previousState) {
+ return DEFAULT;
+ }
+
+ /**
+ * For this state, how modal should over view been shown. 0 modalness means all tasks drawn,
+ * 1 modalness means the current task is show on its own.
+ */
+ public float getOverviewModalness() {
+ return hasFlag(FLAG_MODAL) ? 1 : 0;
+ }
+
+ public boolean isFullScreen() {
+ return hasFlag(FLAG_FULL_SCREEN);
+ }
+
+ public boolean hasButtons() {
+ return hasFlag(FLAG_HAS_BUTTONS);
+ }
+
+ public float[] getOverviewScaleAndOffset(RecentsActivity activity) {
+ return new float[] { NO_SCALE, NO_OFFSET };
+ }
+
+
+ private static class ModalState extends RecentsState {
+
+ public ModalState(int id, int flags) {
+ super(id, flags);
+ }
+
+ @Override
+ public float[] getOverviewScaleAndOffset(RecentsActivity activity) {
+ return getOverviewScaleAndOffsetForModalState(activity);
+ }
+ }
+
+ private static class BackgroundAppState extends RecentsState {
+ public BackgroundAppState(int id, int flags) {
+ super(id, flags);
+ }
+
+ @Override
+ public float[] getOverviewScaleAndOffset(RecentsActivity activity) {
+ return getOverviewScaleAndOffsetForBackgroundState(activity);
+ }
+ }
+}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
index 7b8d40c..adf19df 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
@@ -21,8 +21,8 @@
import static com.android.launcher3.Utilities.squaredHypot;
import static com.android.launcher3.Utilities.squaredTouchSlop;
-import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
import static com.android.quickstep.LauncherSwipeHandler.MIN_PROGRESS_FOR_OVERVIEW;
+import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
import static com.android.quickstep.util.ActiveGestureLog.INTENT_EXTRA_LOG_TRACE_ID;
import android.content.ComponentName;
@@ -44,12 +44,13 @@
import com.android.quickstep.InputConsumer;
import com.android.quickstep.LockScreenRecentsActivity;
import com.android.quickstep.MultiStateCallback;
+import com.android.quickstep.RecentsAnimationCallbacks;
import com.android.quickstep.RecentsAnimationController;
import com.android.quickstep.RecentsAnimationDeviceState;
-import com.android.quickstep.RecentsAnimationCallbacks;
import com.android.quickstep.RecentsAnimationTargets;
import com.android.quickstep.TaskAnimationManager;
import com.android.quickstep.util.AppWindowAnimationHelper;
+import com.android.quickstep.util.TransformParams;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.InputMonitorCompat;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
@@ -84,7 +85,7 @@
private final PointF mTouchDown = new PointF();
private final AppWindowAnimationHelper mAppWindowAnimationHelper;
- private final AppWindowAnimationHelper.TransformParams mTransformParams;
+ private final TransformParams mTransformParams;
private final Point mDisplaySize;
private final MultiStateCallback mStateCallback;
@@ -105,7 +106,7 @@
mGestureState = gestureState;
mTouchSlopSquared = squaredTouchSlop(context);
mAppWindowAnimationHelper = new AppWindowAnimationHelper(context);
- mTransformParams = new AppWindowAnimationHelper.TransformParams();
+ mTransformParams = new TransformParams();
mInputMonitorCompat = inputMonitorCompat;
// Do not use DeviceProfile as the user data might be locked
@@ -230,8 +231,7 @@
Utilities.scaleRectAboutCenter(displaySize, SCALE_DOWN);
displaySize.offsetTo(displaySize.left, 0);
- mTransformParams.setTargetSet(mRecentsAnimationTargets)
- .setLauncherOnTop(true);
+ mTransformParams.setTargetSet(mRecentsAnimationTargets);
mAppWindowAnimationHelper.updateTargetRect(displaySize);
mAppWindowAnimationHelper.applyTransform(mTransformParams);
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java
index 6bfabcd..c82d4b5 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java
@@ -18,6 +18,7 @@
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
+import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -95,6 +96,9 @@
ev.setEdgeFlags(flags | Utilities.EDGE_NAV_BAR);
}
ev.offsetLocation(-mLocationOnScreen[0], -mLocationOnScreen[1]);
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.PAUSE_NOT_DETECTED, "OverviewInputConsumer");
+ }
boolean handled = mEventReceiver.test(ev);
ev.offsetLocation(mLocationOnScreen[0], mLocationOnScreen[1]);
ev.setEdgeFlags(flags);
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/AppWindowAnimationHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/AppWindowAnimationHelper.java
index 5abbd86..a7979cc 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/AppWindowAnimationHelper.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/AppWindowAnimationHelper.java
@@ -15,12 +15,10 @@
*/
package com.android.quickstep.util;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
+import static com.android.launcher3.Utilities.boundToRange;
+import static com.android.launcher3.Utilities.mapRange;
import static com.android.systemui.shared.system.QuickStepContract.getWindowCornerRadius;
import static com.android.systemui.shared.system.QuickStepContract.supportsRoundedCornersOnWindows;
-import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME;
-import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
-import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING;
import android.annotation.TargetApi;
import android.content.Context;
@@ -37,25 +35,22 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
-import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.views.BaseDragLayer;
-import com.android.quickstep.RemoteAnimationTargets;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskThumbnailView;
-import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.utilities.RectFEvaluator;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat;
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
-import com.android.systemui.shared.system.TransactionCompat;
+import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams.Builder;
import com.android.systemui.shared.system.WindowManagerWrapper;
/**
* Utility class to handle window clip animation
*/
@TargetApi(Build.VERSION_CODES.P)
-public class AppWindowAnimationHelper {
+public class AppWindowAnimationHelper implements TransformParams.BuilderProxy {
// The bounds of the source app in device coordinates
private final RectF mSourceStackBounds = new RectF();
@@ -96,12 +91,6 @@
// Corner radius currently applied to transformed window.
private float mCurrentCornerRadius;
- // Whether to boost the opening animation target layers, or the closing
- private int mBoostModeTargetLayers = -1;
-
- private TargetAlphaProvider mTaskAlphaCallback = (t, a) -> a;
- private TargetAlphaProvider mBaseAlphaCallback = (t, a) -> 1;
-
public AppWindowAnimationHelper(RecentsOrientedState orientedState, Context context) {
Resources res = context.getResources();
mOrientedState = orientedState;
@@ -163,8 +152,7 @@
mTargetRect.width(), mTargetRect.height());
}
- public void prepareAnimation(DeviceProfile dp, boolean isOpening) {
- mBoostModeTargetLayers = isOpening ? MODE_OPENING : MODE_CLOSING;
+ public void prepareAnimation(DeviceProfile dp) {
mUseRoundedCornersOnWindows = mSupportsRoundedCornersOnWindows && !dp.isMultiWindowMode;
}
@@ -173,7 +161,7 @@
if (surfaceParams == null) {
return null;
}
- applySurfaceParams(params.mSyncTransactionApplier, surfaceParams);
+ params.applySurfaceParams(surfaceParams);
return mCurrentRect;
}
@@ -182,97 +170,60 @@
* the SurfaceParams to apply via {@link SyncRtSurfaceTransactionApplierCompat#applyParams}.
*/
public SurfaceParams[] computeSurfaceParams(TransformParams params) {
- if (params.mTargetSet == null) {
+ if (params.getTargetSet() == null) {
return null;
}
- float progress = Utilities.boundToRange(params.mProgress, 0, 1);
updateCurrentRect(params);
+ return params.createSurfaceParams(this);
+ }
- SurfaceParams[] surfaceParams = new SurfaceParams[params.mTargetSet.unfilteredApps.length];
- for (int i = 0; i < params.mTargetSet.unfilteredApps.length; i++) {
- RemoteAnimationTargetCompat app = params.mTargetSet.unfilteredApps[i];
- SurfaceParams.Builder builder = new SurfaceParams.Builder(app.leash);
+ @Override
+ public void onBuildParams(Builder builder, RemoteAnimationTargetCompat app,
+ int targetMode, TransformParams params) {
+ Rect crop = mTmpRect;
+ crop.set(app.screenSpaceBounds);
+ crop.offsetTo(0, 0);
+ float cornerRadius = 0f;
+ float scale = Math.max(mCurrentRect.width(), mTargetRect.width()) / crop.width();
+ if (app.mode == targetMode
+ && app.activityType != RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) {
+ mTmpMatrix.setRectToRect(mSourceRect, mCurrentRect, ScaleToFit.FILL);
if (app.localBounds != null) {
- mTmpMatrix.setTranslate(0, 0);
- if (app.activityType == ACTIVITY_TYPE_HOME && app.mode == MODE_CLOSING) {
- mTmpMatrix.setTranslate(app.localBounds.left, app.localBounds.top);
- }
+ mTmpMatrix.postTranslate(app.localBounds.left, app.localBounds.top);
} else {
- mTmpMatrix.setTranslate(app.position.x, app.position.y);
+ mTmpMatrix.postTranslate(app.position.x, app.position.y);
+ }
+ mCurrentClipRectF.roundOut(crop);
+ if (mSupportsRoundedCornersOnWindows) {
+ if (params.getCornerRadius() > -1) {
+ cornerRadius = params.getCornerRadius();
+ scale = mCurrentRect.width() / crop.width();
+ } else {
+ float windowCornerRadius = mUseRoundedCornersOnWindows
+ ? mWindowCornerRadius : 0;
+ cornerRadius = mapRange(boundToRange(params.getProgress(), 0, 1),
+ windowCornerRadius, mTaskCornerRadius);
+ }
+ mCurrentCornerRadius = cornerRadius;
}
- Rect crop = mTmpRect;
- crop.set(app.screenSpaceBounds);
- crop.offsetTo(0, 0);
- float alpha;
- float cornerRadius = 0f;
- float scale = Math.max(mCurrentRect.width(), mTargetRect.width()) / crop.width();
- if (app.mode == params.mTargetSet.targetMode) {
- alpha = mTaskAlphaCallback.getAlpha(app, params.mTargetAlpha);
- if (app.activityType != RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) {
- mTmpMatrix.setRectToRect(mSourceRect, mCurrentRect, ScaleToFit.FILL);
- if (app.localBounds != null) {
- mTmpMatrix.postTranslate(app.localBounds.left, app.localBounds.top);
- } else {
- mTmpMatrix.postTranslate(app.position.x, app.position.y);
- }
- mCurrentClipRectF.roundOut(crop);
- if (mSupportsRoundedCornersOnWindows) {
- if (params.mCornerRadius > -1) {
- cornerRadius = params.mCornerRadius;
- scale = mCurrentRect.width() / crop.width();
- } else {
- float windowCornerRadius = mUseRoundedCornersOnWindows
- ? mWindowCornerRadius : 0;
- cornerRadius = Utilities.mapRange(progress, windowCornerRadius,
- mTaskCornerRadius);
- }
- mCurrentCornerRadius = cornerRadius;
- }
- // Fade out Assistant overlay.
- if (app.activityType == RemoteAnimationTargetCompat.ACTIVITY_TYPE_ASSISTANT
- && app.isNotInRecents) {
- alpha = 1 - Interpolators.DEACCEL_2_5.getInterpolation(progress);
- }
- } else if (params.mTargetSet.hasRecents) {
- // If home has a different target then recents, reverse anim the
- // home target.
- alpha = 1 - (progress * params.mTargetAlpha);
- }
- } else {
- alpha = mBaseAlphaCallback.getAlpha(app, progress);
- if (ENABLE_QUICKSTEP_LIVE_TILE.get() && params.mLauncherOnTop) {
- crop = null;
- }
- }
- builder.withAlpha(alpha)
- .withMatrix(mTmpMatrix)
+ builder.withMatrix(mTmpMatrix)
.withWindowCrop(crop)
// Since radius is in Surface space, but we draw the rounded corners in screen
// space, we have to undo the scale
.withCornerRadius(cornerRadius / scale);
- surfaceParams[i] = builder.build();
+
}
- return surfaceParams;
}
public RectF updateCurrentRect(TransformParams params) {
- if (params.mCurrentRect != null) {
- mCurrentRect.set(params.mCurrentRect);
+ if (params.getCurrentRect() != null) {
+ mCurrentRect.set(params.getCurrentRect());
} else {
mTmpRectF.set(mTargetRect);
- Utilities.scaleRectFAboutCenter(mTmpRectF, params.mOffsetScale);
- mCurrentRect.set(mRectFEvaluator.evaluate(params.mProgress, mSourceRect, mTmpRectF));
- if (mOrientedState == null
- || !mOrientedState.isMultipleOrientationSupportedByDevice()) {
- mCurrentRect.offset(params.mOffset, 0);
- } else {
- int displayRotation = mOrientedState.getDisplayRotation();
- int launcherRotation = mOrientedState.getLauncherRotation();
- mOrientedState.getOrientationHandler().offsetTaskRect(mCurrentRect,
- params.mOffset, displayRotation, launcherRotation);
- }
+ mCurrentRect.set(mRectFEvaluator.evaluate(
+ params.getProgress(), mSourceRect, mTmpRectF));
}
updateClipRect(params);
@@ -281,7 +232,7 @@
private void updateClipRect(TransformParams params) {
// Don't clip past progress > 1.
- float progress = Math.min(1, params.mProgress);
+ float progress = Math.min(1, params.getProgress());
mCurrentClipRectF.left = mSourceWindowClipInsets.left * progress;
mCurrentClipRectF.top = mSourceWindowClipInsets.top * progress;
mCurrentClipRectF.right =
@@ -295,32 +246,6 @@
return mCurrentRectWithInsets;
}
- public static void applySurfaceParams(@Nullable SyncRtSurfaceTransactionApplierCompat
- syncTransactionApplier, SurfaceParams[] params) {
- if (syncTransactionApplier != null) {
- syncTransactionApplier.scheduleApply(params);
- } else {
- TransactionCompat t = new TransactionCompat();
- for (SurfaceParams param : params) {
- SyncRtSurfaceTransactionApplierCompat.applyParams(t, param);
- }
- t.setEarlyWakeup();
- t.apply();
- }
- }
-
- public void setTaskAlphaCallback(TargetAlphaProvider callback) {
- mTaskAlphaCallback = callback;
- }
-
- public void setBaseAlphaCallback(TargetAlphaProvider callback) {
- mBaseAlphaCallback = callback;
- }
-
- public void fromTaskThumbnailView(TaskThumbnailView ttv, RecentsView rv) {
- fromTaskThumbnailView(ttv, rv, null);
- }
-
public void fromTaskThumbnailView(TaskThumbnailView ttv, RecentsView rv,
@Nullable RemoteAnimationTargetCompat target) {
BaseDraggingActivity activity = BaseDraggingActivity.fromContext(ttv.getContext());
@@ -357,19 +282,6 @@
}
}
- /**
- * Compute scale and translation y such that the specified task view fills the screen.
- */
- public AppWindowAnimationHelper updateForFullscreenOverview(TaskView v) {
- TaskThumbnailView thumbnailView = v.getThumbnail();
- RecentsView recentsView = v.getRecentsView();
- fromTaskThumbnailView(thumbnailView, recentsView);
- Rect taskSize = new Rect();
- recentsView.getTaskSize(taskSize);
- updateTargetRect(taskSize);
- return this;
- }
-
private void updateStackBoundsToMultiWindowTaskSize(BaseDraggingActivity activity) {
SystemUiProxy proxy = SystemUiProxy.INSTANCE.get(activity);
if (proxy.isActive()) {
@@ -409,157 +321,4 @@
return mCurrentCornerRadius;
}
- public interface TargetAlphaProvider {
- float getAlpha(RemoteAnimationTargetCompat target, float expectedAlpha);
- }
-
- public static class TransformParams {
- private float mProgress;
- private float mOffset;
- private float mOffsetScale;
- private @Nullable RectF mCurrentRect;
- private float mTargetAlpha;
- private float mCornerRadius;
- private boolean mLauncherOnTop;
- private RemoteAnimationTargets mTargetSet;
- private SyncRtSurfaceTransactionApplierCompat mSyncTransactionApplier;
-
- public TransformParams() {
- mProgress = 0;
- mOffset = 0;
- mOffsetScale = 1;
- mCurrentRect = null;
- mTargetAlpha = 1;
- mCornerRadius = -1;
- mLauncherOnTop = false;
- }
-
- /**
- * Sets the progress of the transformation, where 0 is the source and 1 is the target. We
- * automatically adjust properties such as currentRect and cornerRadius based on this
- * progress, unless they are manually overridden by setting them on this TransformParams.
- */
- public TransformParams setProgress(float progress) {
- mProgress = progress;
- return this;
- }
-
- /**
- * Sets the corner radius of the transformed window, in pixels. If unspecified (-1), we
- * simply interpolate between the window's corner radius to the task view's corner radius,
- * based on {@link #mProgress}.
- */
- public TransformParams setCornerRadius(float cornerRadius) {
- mCornerRadius = cornerRadius;
- return this;
- }
-
- /**
- * Sets the current rect to show the transformed window, in device coordinates. This gives
- * the caller manual control of where to show the window. If unspecified (null), we
- * interpolate between {@link AppWindowAnimationHelper#mSourceRect} and
- * {@link AppWindowAnimationHelper#mTargetRect}, based on {@link #mProgress}.
- */
- public TransformParams setCurrentRect(RectF currentRect) {
- mCurrentRect = currentRect;
- return this;
- }
-
- /**
- * Specifies the alpha of the transformed window. Default is 1.
- */
- public TransformParams setTargetAlpha(float targetAlpha) {
- mTargetAlpha = targetAlpha;
- return this;
- }
-
- /**
- * If {@link #mCurrentRect} is null (i.e. {@link #setCurrentRect(RectF)} hasn't overridden
- * the default), then offset the current rect by this amount after computing the rect based
- * on {@link #mProgress}.
- */
- public TransformParams setOffset(float offset) {
- mOffset = offset;
- return this;
- }
-
- /**
- * If {@link #mCurrentRect} is null (i.e. {@link #setCurrentRect(RectF)} hasn't overridden
- * the default), then scale the current rect by this amount after computing the rect based
- * on {@link #mProgress}.
- */
- public TransformParams setOffsetScale(float offsetScale) {
- mOffsetScale = offsetScale;
- return this;
- }
-
- /**
- * If true, sets the crop = null and layer = Integer.MAX_VALUE for targets that don't match
- * {@link #mTargetSet}.targetMode. (Currently only does this when live tiles are enabled.)
- */
- public TransformParams setLauncherOnTop(boolean launcherOnTop) {
- mLauncherOnTop = launcherOnTop;
- return this;
- }
-
- /**
- * Specifies the set of RemoteAnimationTargetCompats that are included in the transformation
- * that these TransformParams help compute. These TransformParams generally only apply to
- * the targetSet.apps which match the targetSet.targetMode (e.g. the MODE_CLOSING app when
- * swiping to home).
- */
- public TransformParams setTargetSet(RemoteAnimationTargets targetSet) {
- mTargetSet = targetSet;
- return this;
- }
-
- /**
- * Sets the SyncRtSurfaceTransactionApplierCompat that will apply the SurfaceParams that
- * are computed based on these TransformParams.
- */
- public TransformParams setSyncTransactionApplier(
- SyncRtSurfaceTransactionApplierCompat applier) {
- mSyncTransactionApplier = applier;
- return this;
- }
-
- // Pubic getters so outside packages can read the values.
-
- public float getProgress() {
- return mProgress;
- }
-
- public float getOffset() {
- return mOffset;
- }
-
- public float getOffsetScale() {
- return mOffsetScale;
- }
-
- @Nullable
- public RectF getCurrentRect() {
- return mCurrentRect;
- }
-
- public float getTargetAlpha() {
- return mTargetAlpha;
- }
-
- public float getCornerRadius() {
- return mCornerRadius;
- }
-
- public boolean isLauncherOnTop() {
- return mLauncherOnTop;
- }
-
- public RemoteAnimationTargets getTargetSet() {
- return mTargetSet;
- }
-
- public SyncRtSurfaceTransactionApplierCompat getSyncTransactionApplier() {
- return mSyncTransactionApplier;
- }
- }
}
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
index 217eca5..85006da 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/ShelfPeekAnim.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/ShelfPeekAnim.java
@@ -15,10 +15,10 @@
*/
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 static com.android.launcher3.uioverrides.states.QuickstepAtomicAnimationFactory.INDEX_SHELF_ANIM;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
index 820bd17..32fc0de 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
@@ -202,6 +202,12 @@
alpha.setInterpolator(LINEAR);
alpha.setDuration(ALPHA_DURATION_MS);
alpha.setStartDelay(startDelay);
+ alpha.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ v.setAlpha(1f);
+ }
+ });
mAnimators.play(alpha);
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TaskViewSimulator.java
index 9781300..b8f0f4d 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TaskViewSimulator.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TaskViewSimulator.java
@@ -17,14 +17,9 @@
import static android.view.Surface.ROTATION_0;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
import static com.android.launcher3.states.RotationHelper.deltaRotation;
import static com.android.launcher3.touch.PagedOrientationHandler.MATRIX_POST_TRANSLATE;
-import static com.android.quickstep.util.AppWindowAnimationHelper.applySurfaceParams;
-import static com.android.quickstep.util.RecentsOrientedState.isFixedRotationTransformEnabled;
import static com.android.quickstep.util.RecentsOrientedState.postDisplayRotation;
-import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
-import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING;
import static com.android.systemui.shared.system.WindowManagerWrapper.WINDOWING_MODE_FULLSCREEN;
import android.content.Context;
@@ -36,24 +31,20 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
-import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.quickstep.AnimatedFloat;
-import com.android.quickstep.RecentsAnimationTargets;
-import com.android.quickstep.util.AppWindowAnimationHelper.TargetAlphaProvider;
-import com.android.quickstep.util.AppWindowAnimationHelper.TransformParams;
import com.android.quickstep.views.RecentsView.ScrollState;
import com.android.quickstep.views.TaskThumbnailView.PreviewPositionHelper;
import com.android.quickstep.views.TaskView;
import com.android.quickstep.views.TaskView.FullscreenDrawParams;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
-import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
+import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams.Builder;
/**
* A utility class which emulates the layout behavior of TaskView and RecentsView
*/
-public class TaskViewSimulator {
+public class TaskViewSimulator implements TransformParams.BuilderProxy {
private final Rect mTmpCropRect = new Rect();
private final RectF mTempRectF = new RectF();
@@ -61,7 +52,7 @@
private final RecentsOrientedState mOrientationState;
private final Context mContext;
- private final TaskSizeProvider mSizeProvider;
+ private final WindowSizeStrategy mSizeStrategy;
private final Rect mTaskRect = new Rect();
private final PointF mPivot = new PointF();
@@ -69,16 +60,11 @@
private final Matrix mMatrix = new Matrix();
private RemoteAnimationTargetCompat mRunningTarget;
- private RecentsAnimationTargets mAllTargets;
-
- // Whether to boost the opening animation target layers, or the closing
- private int mBoostModeTargetLayers = -1;
- private TargetAlphaProvider mTaskAlphaCallback = (t, a) -> a;
// Thumbnail view properties
private final Rect mThumbnailPosition = new Rect();
private final ThumbnailData mThumbnailData = new ThumbnailData();
- private final PreviewPositionHelper mPositionHelper;
+ private final PreviewPositionHelper mPositionHelper = new PreviewPositionHelper();
private final Matrix mInversePositionMatrix = new Matrix();
// TaskView properties
@@ -95,17 +81,11 @@
private boolean mLayoutValid = false;
private boolean mScrollValid = false;
- public TaskViewSimulator(Context context, TaskSizeProvider sizeProvider,
- boolean rotationSupportedByActivity) {
+ public TaskViewSimulator(Context context, WindowSizeStrategy sizeStrategy) {
mContext = context;
- mSizeProvider = sizeProvider;
- mPositionHelper = new PreviewPositionHelper(context);
+ mSizeStrategy = sizeStrategy;
- mOrientationState = new RecentsOrientedState(context, rotationSupportedByActivity,
- i -> { });
- // We do not need to attach listeners as the simulator is created just for the gesture
- // duration, and any settings are unlikely to change during this
- mOrientationState.initWithoutListeners();
+ mOrientationState = new RecentsOrientedState(context, sizeStrategy, i -> { });
mCurrentFullscreenParams = new FullscreenDrawParams(context);
mPageSpacing = context.getResources().getDimensionPixelSize(R.dimen.recents_page_spacing);
@@ -114,9 +94,9 @@
/**
* Sets the device profile for the current state
*/
- public void setDp(DeviceProfile dp, boolean isOpening) {
+ public void setDp(DeviceProfile dp) {
mDp = dp;
- mBoostModeTargetLayers = isOpening ? MODE_OPENING : MODE_CLOSING;
+ mOrientationState.setMultiWindowMode(mDp.isMultiWindowMode);
mLayoutValid = false;
}
@@ -124,15 +104,7 @@
* @see com.android.quickstep.views.RecentsView#setLayoutRotation(int, int)
*/
public void setLayoutRotation(int touchRotation, int displayRotation) {
- int launcherRotation;
- if (!mOrientationState.isMultipleOrientationSupportedByDevice()
- || mOrientationState.isHomeRotationAllowed()) {
- launcherRotation = displayRotation;
- } else {
- launcherRotation = ROTATION_0;
- }
-
- mOrientationState.update(touchRotation, displayRotation, launcherRotation);
+ mOrientationState.update(touchRotation, displayRotation);
mLayoutValid = false;
}
@@ -143,17 +115,15 @@
if (mDp == null) {
return 1;
}
- mSizeProvider.calculateTaskSize(mContext, mDp, mTaskRect);
+ mSizeStrategy.calculateTaskSize(mContext, mDp, mTaskRect);
return mOrientationState.getFullScreenScaleAndPivot(mTaskRect, mDp, mPivot);
}
/**
* Sets the targets which the simulator will control
*/
- public void setPreview(
- RemoteAnimationTargetCompat runningTarget, RecentsAnimationTargets allTargets) {
+ public void setPreview(RemoteAnimationTargetCompat runningTarget) {
mRunningTarget = runningTarget;
- mAllTargets = allTargets;
mThumbnailData.insets.set(mRunningTarget.contentInsets);
// TODO: What is this?
@@ -161,8 +131,7 @@
mThumbnailPosition.set(runningTarget.screenSpaceBounds);
// TODO: Should sourceContainerBounds already have this offset?
- mThumbnailPosition.offsetTo(mRunningTarget.position.x, mRunningTarget.position.y);
-
+ mThumbnailPosition.offset(-mRunningTarget.position.x, -mRunningTarget.position.y);
mLayoutValid = false;
}
@@ -177,10 +146,40 @@
}
/**
- * Sets an alternate function which can be used to control the alpha
+ * Returns the current clipped/visible window bounds in the window coordinate space
*/
- public void setTaskAlphaCallback(TargetAlphaProvider callback) {
- mTaskAlphaCallback = callback;
+ public RectF getCurrentCropRect() {
+ // Crop rect is the inverse of thumbnail matrix
+ RectF insets = mCurrentFullscreenParams.mCurrentDrawnInsets;
+ mTempRectF.set(-insets.left, -insets.top,
+ mTaskRect.width() + insets.right, mTaskRect.height() + insets.bottom);
+ mInversePositionMatrix.mapRect(mTempRectF);
+ return mTempRectF;
+ }
+
+ public RecentsOrientedState getOrientationState() {
+ return mOrientationState;
+ }
+
+ /**
+ * Returns the current transform applied to the window
+ */
+ public Matrix getCurrentMatrix() {
+ return mMatrix;
+ }
+
+ /**
+ * Applies the rotation on the matrix to so that it maps from launcher coordinate space to
+ * window coordinate space.
+ */
+ public void applyWindowToHomeRotation(Matrix matrix) {
+ mMatrix.postTranslate(mDp.windowX, mDp.windowY);
+ postDisplayRotation(deltaRotation(
+ mOrientationState.getLauncherRotation(), mOrientationState.getDisplayRotation()),
+ mDp.widthPx, mDp.heightPx, matrix);
+ if (mRunningTarget != null) {
+ matrix.postTranslate(-mRunningTarget.position.x, -mRunningTarget.position.y);
+ }
}
/**
@@ -194,12 +193,12 @@
mLayoutValid = true;
getFullScreenScale();
- mThumbnailData.rotation = isFixedRotationTransformEnabled(mContext)
- ? mOrientationState.getDisplayRotation() : mPositionHelper.getCurrentRotation();
+ mThumbnailData.rotation = mOrientationState.getDisplayRotation();
- mPositionHelper.updateThumbnailMatrix(mThumbnailPosition, mThumbnailData,
- mDp.isMultiWindowMode, mTaskRect.width(), mTaskRect.height());
-
+ mPositionHelper.updateThumbnailMatrix(
+ mThumbnailPosition, mThumbnailData,
+ mTaskRect.width(), mTaskRect.height(),
+ mDp, mOrientationState.getLauncherRotation());
mPositionHelper.getMatrix().invert(mInversePositionMatrix);
PagedOrientationHandler poh = mOrientationState.getOrientationHandler();
@@ -240,9 +239,7 @@
// Apply recensView matrix
mMatrix.postScale(recentsViewScale.value, recentsViewScale.value, mPivot.x, mPivot.y);
- postDisplayRotation(deltaRotation(
- mOrientationState.getLauncherRotation(), mOrientationState.getDisplayRotation()),
- mDp.widthPx, mDp.heightPx, mMatrix);
+ applyWindowToHomeRotation(mMatrix);
// Crop rect is the inverse of thumbnail matrix
mTempRectF.set(-insets.left, -insets.top,
@@ -250,39 +247,18 @@
mInversePositionMatrix.mapRect(mTempRectF);
mTempRectF.roundOut(mTmpCropRect);
- SurfaceParams[] surfaceParams = new SurfaceParams[mAllTargets.unfilteredApps.length];
- for (int i = 0; i < mAllTargets.unfilteredApps.length; i++) {
- RemoteAnimationTargetCompat app = mAllTargets.unfilteredApps[i];
- SurfaceParams.Builder builder = new SurfaceParams.Builder(app.leash)
- .withLayer(RemoteAnimationProvider.getLayer(app, mBoostModeTargetLayers));
+ params.applySurfaceParams(params.createSurfaceParams(this));
+ }
- if (app.mode == mAllTargets.targetMode) {
- float alpha = mTaskAlphaCallback.getAlpha(app, params.getTargetAlpha());
- if (app.activityType != RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) {
- // Fade out Assistant overlay.
- if (app.activityType == RemoteAnimationTargetCompat.ACTIVITY_TYPE_ASSISTANT
- && app.isNotInRecents) {
- alpha = Interpolators.ACCEL_2.getInterpolation(fullScreenProgress.value);
- }
-
- builder.withAlpha(alpha)
- .withMatrix(mMatrix)
- .withWindowCrop(mTmpCropRect)
- .withCornerRadius(getCurrentCornerRadius());
- } else if (params.getTargetSet().hasRecents) {
- // If home has a different target then recents, reverse anim the home target.
- builder.withAlpha(fullScreenProgress.value * params.getTargetAlpha());
- }
- } else {
- builder.withAlpha(1);
- if (ENABLE_QUICKSTEP_LIVE_TILE.get() && params.isLauncherOnTop()) {
- builder.withLayer(Integer.MAX_VALUE);
- }
- }
- surfaceParams[i] = builder.build();
+ @Override
+ public void onBuildParams(Builder builder, RemoteAnimationTargetCompat app,
+ int targetMode, TransformParams params) {
+ if (app.mode == targetMode
+ && app.activityType != RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) {
+ builder.withMatrix(mMatrix)
+ .withWindowCrop(mTmpCropRect)
+ .withCornerRadius(getCurrentCornerRadius());
}
-
- applySurfaceParams(params.getSyncTransactionApplier(), surfaceParams);
}
/**
@@ -298,16 +274,4 @@
// Ideally we should use square-root. This is an optimization as one of the dimension is 0.
return Math.max(Math.abs(mTempPoint[0]), Math.abs(mTempPoint[1]));
}
-
- /**
- * Interface for calculating taskSize
- */
- public interface TaskSizeProvider {
-
- /**
- * Sets the outRect to the expected taskSize
- */
- void calculateTaskSize(Context context, DeviceProfile dp, Rect outRect);
- }
-
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TransformParams.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TransformParams.java
new file mode 100644
index 0000000..83b64db
--- /dev/null
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TransformParams.java
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.util;
+
+import android.graphics.RectF;
+
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.Utilities;
+import com.android.launcher3.anim.Interpolators;
+import com.android.quickstep.RemoteAnimationTargets;
+import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
+import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat;
+import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
+import com.android.systemui.shared.system.TransactionCompat;
+
+public class TransformParams {
+
+ private float mProgress;
+ private @Nullable RectF mCurrentRect;
+ private float mTargetAlpha;
+ private float mCornerRadius;
+ private RemoteAnimationTargets mTargetSet;
+ private SyncRtSurfaceTransactionApplierCompat mSyncTransactionApplier;
+
+ private TargetAlphaProvider mTaskAlphaCallback = (t, a) -> a;
+ private TargetAlphaProvider mBaseAlphaCallback = (t, a) -> 1;
+
+ public TransformParams() {
+ mProgress = 0;
+ mCurrentRect = null;
+ mTargetAlpha = 1;
+ mCornerRadius = -1;
+ }
+
+ /**
+ * Sets the progress of the transformation, where 0 is the source and 1 is the target. We
+ * automatically adjust properties such as currentRect and cornerRadius based on this
+ * progress, unless they are manually overridden by setting them on this TransformParams.
+ */
+ public TransformParams setProgress(float progress) {
+ mProgress = progress;
+ return this;
+ }
+
+ /**
+ * Sets the corner radius of the transformed window, in pixels. If unspecified (-1), we
+ * simply interpolate between the window's corner radius to the task view's corner radius,
+ * based on {@link #mProgress}.
+ */
+ public TransformParams setCornerRadius(float cornerRadius) {
+ mCornerRadius = cornerRadius;
+ return this;
+ }
+
+ /**
+ * Sets the current rect to show the transformed window, in device coordinates. This gives
+ * the caller manual control of where to show the window. If unspecified (null), we
+ * interpolate between {@link AppWindowAnimationHelper#mSourceRect} and
+ * {@link AppWindowAnimationHelper#mTargetRect}, based on {@link #mProgress}.
+ */
+ public TransformParams setCurrentRect(RectF currentRect) {
+ mCurrentRect = currentRect;
+ return this;
+ }
+
+ /**
+ * Specifies the alpha of the transformed window. Default is 1.
+ */
+ public TransformParams setTargetAlpha(float targetAlpha) {
+ mTargetAlpha = targetAlpha;
+ return this;
+ }
+
+ /**
+ * Specifies the set of RemoteAnimationTargetCompats that are included in the transformation
+ * that these TransformParams help compute. These TransformParams generally only apply to
+ * the targetSet.apps which match the targetSet.targetMode (e.g. the MODE_CLOSING app when
+ * swiping to home).
+ */
+ public TransformParams setTargetSet(RemoteAnimationTargets targetSet) {
+ mTargetSet = targetSet;
+ return this;
+ }
+
+ /**
+ * Sets the SyncRtSurfaceTransactionApplierCompat that will apply the SurfaceParams that
+ * are computed based on these TransformParams.
+ */
+ public TransformParams setSyncTransactionApplier(
+ SyncRtSurfaceTransactionApplierCompat applier) {
+ mSyncTransactionApplier = applier;
+ return this;
+ }
+
+ /**
+ * Sets an alternate function which can be used to control the alpha of target app
+ */
+ public TransformParams setTaskAlphaCallback(TargetAlphaProvider callback) {
+ mTaskAlphaCallback = callback;
+ return this;
+ }
+
+ /**
+ * Sets an alternate function which can be used to control the alpha of non-target app
+ */
+ public TransformParams setBaseAlphaCallback(TargetAlphaProvider callback) {
+ mBaseAlphaCallback = callback;
+ return this;
+ }
+
+ public SurfaceParams[] createSurfaceParams(BuilderProxy proxy) {
+ RemoteAnimationTargets targets = mTargetSet;
+ SurfaceParams[] surfaceParams = new SurfaceParams[targets.unfilteredApps.length];
+ for (int i = 0; i < targets.unfilteredApps.length; i++) {
+ RemoteAnimationTargetCompat app = targets.unfilteredApps[i];
+ SurfaceParams.Builder builder = new SurfaceParams.Builder(app.leash);
+
+ float progress = Utilities.boundToRange(getProgress(), 0, 1);
+ float alpha;
+ if (app.mode == targets.targetMode) {
+ alpha = mTaskAlphaCallback.getAlpha(app, getTargetAlpha());
+ if (app.activityType != RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) {
+ // Fade out Assistant overlay.
+ if (app.activityType == RemoteAnimationTargetCompat.ACTIVITY_TYPE_ASSISTANT
+ && app.isNotInRecents) {
+ alpha = 1 - Interpolators.DEACCEL_2_5.getInterpolation(progress);
+ }
+ } else if (targets.hasRecents) {
+ // If home has a different target then recents, reverse anim the
+ // home target.
+ alpha = 1 - (progress * getTargetAlpha());
+ }
+ } else {
+ alpha = mBaseAlphaCallback.getAlpha(app, progress);
+ }
+ proxy.onBuildParams(builder.withAlpha(alpha), app, targets.targetMode, this);
+ surfaceParams[i] = builder.build();
+ }
+ return surfaceParams;
+ }
+
+ // Pubic getters so outside packages can read the values.
+
+ public float getProgress() {
+ return mProgress;
+ }
+
+ @Nullable
+ public RectF getCurrentRect() {
+ return mCurrentRect;
+ }
+
+ public float getTargetAlpha() {
+ return mTargetAlpha;
+ }
+
+ public float getCornerRadius() {
+ return mCornerRadius;
+ }
+
+ public RemoteAnimationTargets getTargetSet() {
+ return mTargetSet;
+ }
+
+ public SyncRtSurfaceTransactionApplierCompat getSyncTransactionApplier() {
+ return mSyncTransactionApplier;
+ }
+
+ public void applySurfaceParams(SurfaceParams[] params) {
+ if (mSyncTransactionApplier != null) {
+ mSyncTransactionApplier.scheduleApply(params);
+ } else {
+ TransactionCompat t = new TransactionCompat();
+ for (SurfaceParams param : params) {
+ SyncRtSurfaceTransactionApplierCompat.applyParams(t, param);
+ }
+ t.setEarlyWakeup();
+ t.apply();
+ }
+ }
+
+ public interface TargetAlphaProvider {
+ float getAlpha(RemoteAnimationTargetCompat target, float expectedAlpha);
+ }
+
+ public interface BuilderProxy {
+
+ void onBuildParams(SurfaceParams.Builder builder,
+ RemoteAnimationTargetCompat app, int targetMode, TransformParams params);
+ }
+}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/ClearAllButton.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/ClearAllButton.java
index e455939..1018211 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/ClearAllButton.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/ClearAllButton.java
@@ -56,7 +56,8 @@
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
- mScrollOffset = mIsRtl ? mParent.getPaddingRight() / 2 : - mParent.getPaddingLeft() / 2;
+ PagedOrientationHandler orientationHandler = mParent.getPagedOrientationHandler();
+ mScrollOffset = orientationHandler.getClearAllScrollOffset(mParent, mIsRtl);
}
@Override
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/IconView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/IconView.java
index eb8da6e..7cc00b7 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/IconView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/IconView.java
@@ -21,12 +21,12 @@
import android.util.AttributeSet;
import android.view.View;
+import androidx.annotation.NonNull;
+
import com.android.launcher3.FastBitmapDrawable;
import java.util.ArrayList;
-import androidx.annotation.NonNull;
-
/**
* A view which draws a drawable stretched to fit its size. Unlike ImageView, it avoids relayout
* when the drawable changes.
@@ -130,4 +130,14 @@
mScaleListeners.remove(listener);
}
}
+
+ @Override
+ public void setAlpha(float alpha) {
+ super.setAlpha(alpha);
+ if (alpha > 0) {
+ setVisibility(VISIBLE);
+ } else {
+ setVisibility(INVISIBLE);
+ }
+ }
}
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 9005651..250c78b 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
@@ -25,35 +25,30 @@
import static com.android.launcher3.QuickstepAppTransitionManagerImpl.ALL_APPS_PROGRESS_OFF_SCREEN;
import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PROGRESS;
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
+import static com.android.quickstep.util.WindowSizeStrategy.LAUNCHER_ACTIVITY_SIZE_STRATEGY;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.annotation.TargetApi;
import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Rect;
import android.os.Build;
import android.util.AttributeSet;
import android.view.MotionEvent;
-import android.view.View;
import android.widget.FrameLayout;
import com.android.launcher3.BaseQuickstepLauncher;
-import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Hotseat;
import com.android.launcher3.LauncherState;
-import com.android.launcher3.LauncherStateManager.StateListener;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.appprediction.PredictionUiStateManager;
import com.android.launcher3.appprediction.PredictionUiStateManager.Client;
import com.android.launcher3.statehandlers.DepthController;
+import com.android.launcher3.statemanager.StateManager.StateListener;
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
import com.android.launcher3.util.TraceHelper;
import com.android.launcher3.views.ScrimView;
import com.android.quickstep.SysUINavigationMode;
-import com.android.quickstep.util.AppWindowAnimationHelper;
-import com.android.quickstep.util.AppWindowAnimationHelper.TransformParams;
-import com.android.quickstep.util.LayoutUtils;
+import com.android.quickstep.util.TransformParams;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.plugins.RecentsExtraCard;
@@ -62,9 +57,7 @@
*/
@TargetApi(Build.VERSION_CODES.O)
public class LauncherRecentsView extends RecentsView<BaseQuickstepLauncher>
- implements StateListener {
-
- private static final Rect sTempRect = new Rect();
+ implements StateListener<LauncherState> {
private final TransformParams mTransformParams = new TransformParams();
@@ -96,7 +89,7 @@
}
public LauncherRecentsView(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr, true);
+ super(context, attrs, defStyleAttr, LAUNCHER_ACTIVITY_SIZE_STRATEGY);
mActivity.getStateManager().addStateListener(this);
}
@@ -128,31 +121,12 @@
}
}
- @Override
- public void draw(Canvas canvas) {
- maybeDrawEmptyMessage(canvas);
- super.draw(canvas);
- }
-
- @Override
- public void onViewAdded(View child) {
- super.onViewAdded(child);
- updateEmptyMessage();
- }
-
- @Override
- protected void onTaskStackUpdated() {
- // Lazily update the empty message only when the task stack is reapplied
- updateEmptyMessage();
- }
-
/**
* Animates adjacent tasks and translate hotseat off screen as well.
*/
@Override
- public AnimatorSet createAdjacentPageAnimForTaskLaunch(TaskView tv,
- AppWindowAnimationHelper helper) {
- AnimatorSet anim = super.createAdjacentPageAnimForTaskLaunch(tv, helper);
+ public AnimatorSet createAdjacentPageAnimForTaskLaunch(TaskView tv) {
+ AnimatorSet anim = super.createAdjacentPageAnimForTaskLaunch(tv);
if (!SysUINavigationMode.getMode(mActivity).hasGestures) {
// Hotseat doesn't move when opening recents with the button,
@@ -179,11 +153,6 @@
}
@Override
- protected void getTaskSize(DeviceProfile dp, Rect outRect) {
- LayoutUtils.calculateLauncherTaskSize(getContext(), dp, outRect);
- }
-
- @Override
protected void onTaskLaunchAnimationUpdate(float progress, TaskView tv) {
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
if (tv.isRunningTask()) {
@@ -223,14 +192,14 @@
@Override
public void redrawLiveTile(boolean mightNeedToRefill) {
- AppWindowAnimationHelper.TransformParams transformParams = getLiveTileParams(mightNeedToRefill);
+ TransformParams transformParams = getLiveTileParams(mightNeedToRefill);
if (transformParams != null) {
mAppWindowAnimationHelper.applyTransform(transformParams);
}
}
@Override
- public AppWindowAnimationHelper.TransformParams getLiveTileParams(
+ public TransformParams getLiveTileParams(
boolean mightNeedToRefill) {
if (!mEnableDrawingLiveTile || mRecentsAnimationController == null
|| mRecentsAnimationTargets == null || mAppWindowAnimationHelper == null) {
@@ -258,8 +227,7 @@
.setCurrentRect(mTempRectF)
.setTargetAlpha(taskView.getAlpha())
.setSyncTransactionApplier(mSyncTransactionApplier)
- .setTargetSet(mRecentsAnimationTargets)
- .setLauncherOnTop(true);
+ .setTargetSet(mRecentsAnimationTargets);
}
return mTransformParams;
}
@@ -383,4 +351,16 @@
protected DepthController getDepthController() {
return mActivity.getDepthController();
}
+
+ @Override
+ public void setModalStateEnabled(boolean isModalState) {
+ super.setModalStateEnabled(isModalState);
+ if (isModalState) {
+ mActivity.getStateManager().goToState(LauncherState.OVERVIEW_MODAL_TASK);
+ } else {
+ if (mActivity.isInState(LauncherState.OVERVIEW_MODAL_TASK)) {
+ mActivity.getStateManager().goToState(LauncherState.OVERVIEW);
+ }
+ }
+ }
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/OverviewActionsView.java
index d160686..7201b02 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/OverviewActionsView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/OverviewActionsView.java
@@ -31,6 +31,7 @@
import com.android.launcher3.R;
import com.android.launcher3.util.MultiValueAlpha;
import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
+import com.android.quickstep.SysUINavigationMode.Mode;
import com.android.quickstep.TaskOverlayFactory.OverlayUICallbacks;
import java.lang.annotation.Retention;
@@ -42,6 +43,8 @@
public class OverviewActionsView<T extends OverlayUICallbacks> extends FrameLayout
implements OnClickListener {
+ public static final long VISIBILITY_TRANSITION_DURATION_MS = 80;
+
@IntDef(flag = true, value = {
HIDDEN_UNSUPPORTED_NAVIGATION,
HIDDEN_DISABLED_FEATURE,
@@ -139,4 +142,21 @@
public AlphaProperty getVisibilityAlpha() {
return mMultiValueAlpha.getProperty(INDEX_VISIBILITY_ALPHA);
}
+
+ /** Updates vertical margins for different navigation mode. */
+ public void updateVerticalMarginForNavModeChange(Mode mode) {
+ int topMargin = getResources()
+ .getDimensionPixelSize(R.dimen.overview_actions_top_margin);
+ int bottomMargin = 0;
+ if (mode == Mode.THREE_BUTTONS) {
+ bottomMargin = getResources()
+ .getDimensionPixelSize(R.dimen.overview_actions_bottom_margin_three_button);
+ } else {
+ bottomMargin = getResources()
+ .getDimensionPixelSize(R.dimen.overview_actions_bottom_margin_gesture);
+ }
+ LayoutParams params = (LayoutParams) getLayoutParams();
+ params.setMargins(
+ params.leftMargin, topMargin, params.rightMargin, bottomMargin);
+ }
}
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 cd3abed..979e3ef 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
@@ -16,12 +16,15 @@
package com.android.quickstep.views;
+import static android.view.Surface.ROTATION_0;
+
import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAGS;
import static com.android.launcher3.InvariantDeviceProfile.CHANGE_FLAG_ICON_PARAMS;
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
import static com.android.launcher3.Utilities.EDGE_NAV_BAR;
+import static com.android.launcher3.Utilities.mapToRange;
import static com.android.launcher3.Utilities.squaredHypot;
import static com.android.launcher3.Utilities.squaredTouchSlop;
import static com.android.launcher3.anim.Interpolators.ACCEL;
@@ -29,8 +32,8 @@
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
-import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.TASK_DISMISS_SWIPE_UP;
-import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.TASK_LAUNCH_SWIPE_DOWN;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_DISMISS_SWIPE_UP;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_LAUNCH_SWIPE_DOWN;
import static com.android.launcher3.statehandlers.DepthController.DEPTH;
import static com.android.launcher3.uioverrides.touchcontrollers.TaskViewTouchController.SUCCESS_TRANSITION_PROGRESS;
import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch.TAP;
@@ -54,7 +57,6 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.content.res.Configuration;
import android.graphics.Canvas;
import android.graphics.Point;
import android.graphics.PointF;
@@ -109,6 +111,7 @@
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.DynamicResource;
+import com.android.launcher3.util.MultiValueAlpha;
import com.android.launcher3.util.OverScroller;
import com.android.launcher3.util.Themes;
import com.android.launcher3.util.ViewPool;
@@ -121,13 +124,15 @@
import com.android.quickstep.TaskUtils;
import com.android.quickstep.ViewUtils;
import com.android.quickstep.util.AppWindowAnimationHelper;
+import com.android.quickstep.util.LayoutUtils;
import com.android.quickstep.util.RecentsOrientedState;
+import com.android.quickstep.util.TransformParams;
+import com.android.quickstep.util.WindowSizeStrategy;
import com.android.systemui.plugins.ResourceProvider;
import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.ActivityManagerWrapper;
-import com.android.systemui.shared.system.ConfigurationCompat;
import com.android.systemui.shared.system.LauncherEventUtil;
import com.android.systemui.shared.system.PackageManagerWrapper;
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat;
@@ -202,6 +207,7 @@
};
protected final RecentsOrientedState mOrientationState;
+ protected final WindowSizeStrategy mSizeStrategy;
protected RecentsAnimationController mRecentsAnimationController;
protected RecentsAnimationTargets mRecentsAnimationTargets;
protected AppWindowAnimationHelper mAppWindowAnimationHelper;
@@ -212,6 +218,7 @@
protected final Rect mTempRect = new Rect();
protected final RectF mTempRectF = new RectF();
private final PointF mTempPointF = new PointF();
+ private final float[] mTempFloatPoint = new float[2];
private static final int DISMISS_TASK_DURATION = 300;
private static final int ADDITION_TASK_DURATION = 200;
@@ -225,7 +232,6 @@
private final ClearAllButton mClearAllButton;
private final Rect mClearAllButtonDeadZoneRect = new Rect();
private final Rect mTaskViewDeadZoneRect = new Rect();
- protected final AppWindowAnimationHelper mTempAppWindowAnimationHelper;
private final ScrollState mScrollState = new ScrollState();
// Keeps track of the previously known visible tasks for purposes of loading/unloading task data
@@ -373,20 +379,19 @@
};
public RecentsView(Context context, AttributeSet attrs, int defStyleAttr,
- boolean rotationSupportedByActivity) {
+ WindowSizeStrategy sizeStrategy) {
super(context, attrs, defStyleAttr);
setPageSpacing(getResources().getDimensionPixelSize(R.dimen.recents_page_spacing));
setEnableFreeScroll(true);
+ mSizeStrategy = sizeStrategy;
mOrientationState = new RecentsOrientedState(
- context, rotationSupportedByActivity, this::animateRecentsRotationInPlace);
+ context, mSizeStrategy, this::animateRecentsRotationInPlace);
mFastFlingVelocity = getResources()
.getDimensionPixelSize(R.dimen.recents_fast_fling_velocity);
mActivity = BaseActivity.fromContext(context);
mModel = RecentsModel.INSTANCE.get(context);
mIdp = InvariantDeviceProfile.INSTANCE.get(context);
- mTempAppWindowAnimationHelper =
- new AppWindowAnimationHelper(getPagedViewOrientedState(), context);
mClearAllButton = (ClearAllButton) LayoutInflater.from(context)
.inflate(R.layout.overview_clear_all_button, this, false);
@@ -504,7 +509,7 @@
mIPinnedStackAnimationListener.setActivity(mActivity);
SystemUiProxy.INSTANCE.get(getContext()).setPinnedStackAnimationListener(
mIPinnedStackAnimationListener);
- mOrientationState.init();
+ mOrientationState.initListeners();
}
@Override
@@ -519,7 +524,7 @@
mIdp.removeOnChangeListener(this);
SystemUiProxy.INSTANCE.get(getContext()).setPinnedStackAnimationListener(null);
mIPinnedStackAnimationListener.setActivity(null);
- mOrientationState.destroy();
+ mOrientationState.destroyListeners();
}
@Override
@@ -545,6 +550,13 @@
child.setLayoutDirection(mIsRtl ? View.LAYOUT_DIRECTION_LTR : View.LAYOUT_DIRECTION_RTL);
updateTaskStartIndex(child);
mActionsView.updateHiddenFlags(HIDDEN_NO_TASKS, false);
+ updateEmptyMessage();
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ maybeDrawEmptyMessage(canvas);
+ super.draw(canvas);
}
private void updateTaskStartIndex(View affectingView) {
@@ -595,20 +607,20 @@
}
@Override
- protected void onPageEndTransition() {
- super.onPageEndTransition();
- if (getNextPage() > 0) {
- setSwipeDownShouldLaunchApp(true);
- }
+ protected void onPageBeginTransition() {
+ super.onPageBeginTransition();
+ LayoutUtils.setViewEnabled(mActionsView, false);
}
@Override
- protected void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
- int windowConfigurationRotation = ConfigurationCompat
- .getWindowConfigurationRotation(getResources().getConfiguration());
- setLayoutInternal(mOrientationState.getTouchRotation(),
- mOrientationState.getDisplayRotation(), windowConfigurationRotation);
+ protected void onPageEndTransition() {
+ super.onPageEndTransition();
+ if (getScrollX() == getScrollForPage(getPageNearestToCenterOfScreen())) {
+ LayoutUtils.setViewEnabled(mActionsView, true);
+ }
+ if (getNextPage() > 0) {
+ setSwipeDownShouldLaunchApp(true);
+ }
}
@Override
@@ -637,7 +649,7 @@
case MotionEvent.ACTION_DOWN:
// Touch down anywhere but the deadzone around the visible clear all button and
// between the task views will start home on touch up
- if (!isHandlingTouch()) {
+ if (!isHandlingTouch() && !isModal()) {
if (mShowEmptyMessage) {
mTouchDownToStartHome = true;
} else {
@@ -665,7 +677,7 @@
@Override
protected void determineScrollingStart(MotionEvent ev, float touchSlopScale) {
// Enables swiping to the left or right only if the task overlay is not modal.
- if (mTaskModalness == 0f) {
+ if (!isModal()) {
super.determineScrollingStart(ev, touchSlopScale);
}
}
@@ -712,7 +724,7 @@
final int pageIndex = requiredTaskCount - i - 1 + mTaskViewStartIndex;
final Task task = tasks.get(i);
final TaskView taskView = (TaskView) getChildAt(pageIndex);
- taskView.bind(task, mOrientationState, mActivity.getDeviceProfile().isMultiWindowMode);
+ taskView.bind(task, mOrientationState);
}
if (mNextPage == INVALID_PAGE) {
@@ -736,6 +748,10 @@
updateEnabledOverlays();
}
+ private boolean isModal() {
+ return mTaskModalness > 0;
+ }
+
private void removeTasksViewsAndClearAllButton() {
for (int i = getTaskViewCount() - 1; i >= 0; i--) {
removeView(getTaskViewAt(i));
@@ -753,7 +769,10 @@
return taskViewCount;
}
- protected void onTaskStackUpdated() { }
+ protected void onTaskStackUpdated() {
+ // Lazily update the empty message only when the task stack is reapplied
+ updateEmptyMessage();
+ }
public void resetTaskVisuals() {
for (int i = getTaskViewCount() - 1; i >= 0; i--) {
@@ -784,7 +803,10 @@
for (int i = 0; i < taskCount; i++) {
getTaskViewAt(i).setFullscreenProgress(mFullscreenProgress);
}
- mActionsView.updateHiddenFlags(HIDDEN_FULLESCREEN_PROGRESS, fullscreenProgress > 0);
+ // Fade out the actions view quickly (0.1 range)
+ mActionsView.getVisibilityAlpha().setValue(
+ mapToRange(fullscreenProgress, 0, 0.1f, 1f, 0f, LINEAR));
+ mActionsView.updateHiddenFlags(HIDDEN_FULLESCREEN_PROGRESS, fullscreenProgress == 1.0f);
}
private void updateTaskStackListenerState() {
@@ -802,7 +824,8 @@
public void setInsets(Rect insets) {
mInsets.set(insets);
DeviceProfile dp = mActivity.getDeviceProfile();
- getTaskSize(dp, mTempRect);
+ mOrientationState.setMultiWindowMode(dp.isMultiWindowMode);
+ getTaskSize(mTempRect);
mTaskWidth = mTempRect.width();
mTaskHeight = mTempRect.height();
@@ -812,10 +835,8 @@
dp.heightPx - mInsets.bottom - mTempRect.bottom);
}
- protected abstract void getTaskSize(DeviceProfile dp, Rect outRect);
-
public void getTaskSize(Rect outRect) {
- getTaskSize(mActivity.getDeviceProfile(), outRect);
+ mSizeStrategy.calculateTaskSize(mActivity, mActivity.getDeviceProfile(), outRect);
}
@Override
@@ -949,6 +970,7 @@
setCurrentPage(0);
mDwbToastShown = false;
mActivity.getSystemUiController().updateUiState(UI_STATE_OVERVIEW, 0);
+ LayoutUtils.setViewEnabled(mActionsView, true);
}
public @Nullable TaskView getRunningTaskView() {
@@ -956,7 +978,15 @@
}
public int getRunningTaskIndex() {
- TaskView tv = getRunningTaskView();
+ return getTaskIndexForId(mRunningTaskId);
+ }
+
+ /**
+ * Get the index of the task view whose id matches {@param taskId}.
+ * @return -1 if there is no task view for the task id, else the index of the task view.
+ */
+ public int getTaskIndexForId(int taskId) {
+ TaskView tv = getTaskView(taskId);
return tv == null ? -1 : indexOfChild(tv);
}
@@ -1044,7 +1074,7 @@
}
setRunningTaskHidden(false);
animateUpRunningTaskIconScale();
- mActionsView.updateHiddenFlags(HIDDEN_GESTURE_RUNNING, false);
+ animateActionsViewIn();
}
/**
@@ -1068,8 +1098,7 @@
new ComponentName(getContext(), getClass()), 0, 0), null, null, "", "", 0, 0,
false, true, false, false, new ActivityManager.TaskDescription(), 0,
new ComponentName("", ""), false);
- taskView.bind(mTmpRunningTask, mOrientationState,
- mActivity.getDeviceProfile().isMultiWindowMode);
+ taskView.bind(mTmpRunningTask, mOrientationState);
}
boolean runningTaskTileHidden = mRunningTaskTileHidden;
@@ -1158,6 +1187,14 @@
}
}
+ private void animateActionsViewIn() {
+ mActionsView.updateHiddenFlags(HIDDEN_GESTURE_RUNNING, false);
+ ObjectAnimator anim = ObjectAnimator.ofFloat(
+ mActionsView.getVisibilityAlpha(), MultiValueAlpha.VALUE, 1);
+ anim.setDuration(OverviewActionsView.VISIBILITY_TRANSITION_DURATION_MS);
+ anim.start();
+ }
+
public void animateUpRunningTaskIconScale() {
animateUpRunningTaskIconScale(0);
}
@@ -1278,7 +1315,8 @@
ComponentKey compKey = TaskUtils.getLaunchComponentKeyForTask(taskView.getTask().key);
mActivity.getUserEventDispatcher().logTaskLaunchOrDismiss(
endState.logAction, Direction.UP, index, compKey);
- mActivity.getStatsLogManager().log(TASK_DISMISS_SWIPE_UP, taskView.buildProto());
+ mActivity.getStatsLogManager().log(
+ LAUNCHER_TASK_DISMISS_SWIPE_UP, taskView.buildProto());
}
}
@@ -1558,19 +1596,14 @@
}
public void setLayoutRotation(int touchRotation, int displayRotation) {
- int launcherRotation = mOrientationState.getLauncherRotation();
- setLayoutInternal(touchRotation, displayRotation, launcherRotation);
- }
-
- private void setLayoutInternal(int touchRotation, int displayRotation, int launcherRotation) {
- if (mOrientationState.update(touchRotation, displayRotation, launcherRotation)) {
+ if (mOrientationState.update(touchRotation, displayRotation)) {
mOrientationHandler = mOrientationState.getOrientationHandler();
mIsRtl = mOrientationHandler.getRecentsRtlSetting(getResources());
setLayoutDirection(mIsRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR);
mClearAllButton.setRotation(mOrientationHandler.getDegreesRotated());
mActivity.getDragLayer().recreateControllers();
mActionsView.updateHiddenFlags(HIDDEN_NON_ZERO_ROTATION,
- touchRotation != 0 || launcherRotation != 0);
+ touchRotation != 0 || mOrientationState.getLauncherRotation() != ROTATION_0);
requestLayout();
}
}
@@ -1653,6 +1686,7 @@
mTempRect, mActivity.getDeviceProfile(), mTempPointF);
setPivotX(mTempPointF.x);
setPivotY(mTempPointF.y);
+ setTaskModalness(mTaskModalness);
updatePageOffsets();
}
@@ -1665,7 +1699,8 @@
}
int count = getChildCount();
- TaskView runningTask = mRunningTaskId == -1 ? null : getTaskView(mRunningTaskId);
+ TaskView runningTask = mRunningTaskId == -1 || !mRunningTaskTileHidden
+ ? null : getTaskView(mRunningTaskId);
int midPoint = runningTask == null ? -1 : indexOfChild(runningTask);
int currentPage = getCurrentPage();
@@ -1756,15 +1791,14 @@
* If launching one of the adjacent tasks, parallax the center task and other adjacent task
* to the right.
*/
- public AnimatorSet createAdjacentPageAnimForTaskLaunch(
- TaskView tv, AppWindowAnimationHelper appWindowAnimationHelper) {
+ public AnimatorSet createAdjacentPageAnimForTaskLaunch(TaskView tv) {
AnimatorSet anim = new AnimatorSet();
int taskIndex = indexOfChild(tv);
int centerTaskIndex = getCurrentPage();
boolean launchingCenterTask = taskIndex == centerTaskIndex;
- float toScale = appWindowAnimationHelper.getSrcToTargetScale();
+ float toScale = getMaxScaleForFullScreen();
if (launchingCenterTask) {
RecentsView recentsView = tv.getRecentsView();
anim.play(ObjectAnimator.ofFloat(recentsView, SCALE_PROPERTY, toScale));
@@ -1786,6 +1820,15 @@
return anim;
}
+ /**
+ * Returns the scale up required on the view, so that it coves the screen completely
+ */
+ public float getMaxScaleForFullScreen() {
+ getTaskSize(mTempRect);
+ return getPagedViewOrientedState().getFullScreenScaleAndPivot(
+ mTempRect, mActivity.getDeviceProfile(), mTempPointF);
+ }
+
public PendingAnimation createTaskLaunchAnimation(
TaskView tv, long duration, Interpolator interpolator) {
if (FeatureFlags.IS_STUDIO_BUILD && mPendingAnimation != null) {
@@ -1820,11 +1863,7 @@
}
});
- AppWindowAnimationHelper appWindowAnimationHelper = new AppWindowAnimationHelper(
- getPagedViewOrientedState(), mActivity);
- appWindowAnimationHelper.fromTaskThumbnailView(tv.getThumbnail(), this);
- appWindowAnimationHelper.prepareAnimation(mActivity.getDeviceProfile(), true /* isOpening */);
- AnimatorSet anim = createAdjacentPageAnimForTaskLaunch(tv, appWindowAnimationHelper);
+ AnimatorSet anim = createAdjacentPageAnimForTaskLaunch(tv);
DepthController depthController = getDepthController();
if (depthController != null) {
@@ -1851,8 +1890,8 @@
mActivity.getUserEventDispatcher().logTaskLaunchOrDismiss(
endState.logAction, Direction.DOWN, indexOfChild(tv),
TaskUtils.getLaunchComponentKeyForTask(task.key));
- mActivity.getStatsLogManager().log(TASK_LAUNCH_SWIPE_DOWN, tv.buildProto()
- );
+ mActivity.getStatsLogManager().log(
+ LAUNCHER_TASK_LAUNCH_SWIPE_DOWN, tv.buildProto());
}
} else {
onTaskLaunched(false);
@@ -2038,14 +2077,6 @@
return getScrollForPage(getRunningTaskIndex()) - mOrientationHandler.getPrimaryScroll(this);
}
- /**
- * @return How many pixels the running task is offset on the x-axis due to the current scrollX
- * and parent scale.
- */
- public float getScrollOffsetScaled() {
- return getScrollOffset() * mOrientationHandler.getPrimaryScale(this);
- }
-
public Consumer<MotionEvent> getEventDispatcher(float navbarRotation) {
float degreesRotated;
if (navbarRotation == 0) {
@@ -2079,11 +2110,7 @@
return mAppWindowAnimationHelper;
}
- public AppWindowAnimationHelper getTempAppWindowAnimationHelper() {
- return mTempAppWindowAnimationHelper;
- }
-
- public AppWindowAnimationHelper.TransformParams getLiveTileParams(
+ public TransformParams getLiveTileParams(
boolean mightNeedToRefill) {
return null;
}
@@ -2128,6 +2155,18 @@
updatePageOffsets();
if (getCurrentPageTaskView() != null) {
getCurrentPageTaskView().setModalness(modalness);
+ TaskView tv = getCurrentPageTaskView();
+
+ // Move the task view up as it scales...
+ // ...the icon on taskview is hidden in modal state, so consider the top of the task
+ mTempFloatPoint[0] = 0;
+ mTempFloatPoint[1] = tv.getTop() + mTaskTopMargin;
+ // ...find the top after the transformation
+ getMatrix().mapPoints(mTempFloatPoint);
+
+ // ...make it match the top inset
+ float calcOffset = (mInsets.top - mTempFloatPoint[1]) * mTaskModalness;
+ tv.setTranslationY(calcOffset);
}
}
@@ -2137,6 +2176,12 @@
}
/**
+ * Enables or disables modal state for RecentsView
+ * @param isModalState
+ */
+ public void setModalStateEnabled(boolean isModalState) { }
+
+ /**
* Used to register callbacks for when our empty message state changes.
*
* @see #setOnEmptyMessageUpdatedListener(OnEmptyMessageUpdatedListener)
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskMenuView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskMenuView.java
index 9b47520..512bbac 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskMenuView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskMenuView.java
@@ -239,7 +239,8 @@
setLayoutParams(params);
setScaleX(taskView.getScaleX());
setScaleY(taskView.getScaleY());
- mOptionLayout.setOrientation(orientationHandler.getTaskMenuLayoutOrientation());
+ mOptionLayout.setOrientation(orientationHandler
+ .getTaskMenuLayoutOrientation(mOptionLayout));
setPosition(sTempRect.left - insets.left, sTempRect.top - insets.top,
taskView.getPagedOrientationHandler());
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java
index e525842..a3e360f 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java
@@ -36,12 +36,12 @@
import android.graphics.Shader;
import android.util.AttributeSet;
import android.util.FloatProperty;
-import android.util.Log;
import android.util.Property;
import android.view.Surface;
import android.view.View;
import com.android.launcher3.BaseActivity;
+import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
@@ -90,7 +90,7 @@
// Contains the portion of the thumbnail that is clipped when fullscreen progress = 0.
private final Rect mPreviewRect = new Rect();
- private final PreviewPositionHelper mPreviewPositionHelper;
+ private final PreviewPositionHelper mPreviewPositionHelper = new PreviewPositionHelper();
// Initialize with dummy value. It is overridden later by TaskView
private TaskView.FullscreenDrawParams mFullscreenParams = TEMP_PARAMS;
@@ -104,7 +104,6 @@
private boolean mOverlayEnabled;
private OverviewScreenshotActions mOverviewScreenshotActionsPlugin;
- private boolean mIsMultiWindowMode;
public TaskThumbnailView(Context context) {
this(context, null);
@@ -123,11 +122,13 @@
mDimmingPaintAfterClearing.setColor(Color.BLACK);
mActivity = BaseActivity.fromContext(context);
mIsDarkTextTheme = Themes.getAttrBoolean(mActivity, R.attr.isWorkspaceDarkText);
- mPreviewPositionHelper = new PreviewPositionHelper(context);
}
- public void bind(Task task, boolean isMultiWindowMode) {
- mIsMultiWindowMode = isMultiWindowMode;
+ /**
+ * Updates the thumbnail to draw the provided task
+ * @param task
+ */
+ public void bind(Task task) {
mOverlay.reset();
mTask = task;
int color = task == null ? Color.BLACK : task.colorBackground | 0xFF000000;
@@ -193,11 +194,6 @@
updateThumbnailPaintFilter();
}
- public void setSaturation(float saturation) {
- mSaturation = saturation;
- updateThumbnailPaintFilter();
- }
-
public TaskOverlay getTaskOverlay() {
return mOverlay;
}
@@ -352,8 +348,11 @@
if (mBitmapShader != null && mThumbnailData != null) {
mPreviewRect.set(0, 0, mThumbnailData.thumbnail.getWidth(),
mThumbnailData.thumbnail.getHeight());
+ int currentRotation = ConfigurationCompat.getWindowConfigurationRotation(
+ mActivity.getResources().getConfiguration());
mPreviewPositionHelper.updateThumbnailMatrix(mPreviewRect, mThumbnailData,
- mIsMultiWindowMode, getMeasuredWidth(), getMeasuredHeight());
+ getMeasuredWidth(), getMeasuredHeight(), mActivity.getDeviceProfile(),
+ currentRotation);
mBitmapShader.setLocalMatrix(mPreviewPositionHelper.mMatrix);
mPaint.setShader(mBitmapShader);
@@ -420,17 +419,6 @@
private float mClipBottom = -1;
private boolean mIsOrientationChanged;
- private final Context mContext;
-
- public PreviewPositionHelper(Context context) {
- mContext = context;
- }
-
- public int getCurrentRotation() {
- return ConfigurationCompat.getWindowConfigurationRotation(
- mContext.getResources().getConfiguration());
- }
-
public Matrix getMatrix() {
return mMatrix;
}
@@ -439,13 +427,14 @@
* Updates the matrix based on the provided parameters
*/
public void updateThumbnailMatrix(Rect thumbnailPosition, ThumbnailData thumbnailData,
- boolean isInMultiWindowMode, int canvasWidth, int canvasHeight) {
+ int canvasWidth, int canvasHeight, DeviceProfile dp, int currentRotation) {
boolean isRotated = false;
boolean isOrientationDifferent;
mClipBottom = -1;
float scale = thumbnailData.scale;
- Rect thumbnailInsets = thumbnailData.insets;
+ Rect activityInsets = dp.getInsets();
+ Rect thumbnailInsets = getBoundedInsets(activityInsets, thumbnailData.insets);
final float thumbnailWidth = thumbnailPosition.width()
- (thumbnailInsets.left + thumbnailInsets.right) * scale;
final float thumbnailHeight = thumbnailPosition.height()
@@ -453,11 +442,11 @@
final float thumbnailScale;
int thumbnailRotation = thumbnailData.rotation;
- int currentRotation = getCurrentRotation();
int deltaRotate = getRotationDelta(currentRotation, thumbnailRotation);
+ Rect deviceInsets = dp.getInsets();
// Landscape vs portrait change
- boolean windowingModeSupportsRotation = !isInMultiWindowMode
+ boolean windowingModeSupportsRotation = !dp.isMultiWindowMode
&& thumbnailData.windowingMode == WINDOWING_MODE_FULLSCREEN;
isOrientationDifferent = isOrientationChange(deltaRotate)
&& windowingModeSupportsRotation;
@@ -476,9 +465,10 @@
if (!isRotated) {
// No Rotation
- mClippedInsets.offsetTo(thumbnailInsets.left * scale,
- thumbnailInsets.top * scale);
- mMatrix.setTranslate(-mClippedInsets.left, -mClippedInsets.top);
+ mClippedInsets.offsetTo(deviceInsets.left * scale, deviceInsets.top * scale);
+ mMatrix.setTranslate(
+ -thumbnailInsets.left * scale,
+ -thumbnailInsets.top * scale);
} else {
setThumbnailRotation(deltaRotate, thumbnailInsets, scale, thumbnailPosition);
}
@@ -495,8 +485,16 @@
}
mClippedInsets.left *= thumbnailScale;
mClippedInsets.top *= thumbnailScale;
- mClippedInsets.right = widthWithInsets - mClippedInsets.left - canvasWidth;
- mClippedInsets.bottom = heightWithInsets - mClippedInsets.top - canvasHeight;
+
+ if (dp.isMultiWindowMode) {
+ mClippedInsets.right = deviceInsets.right * scale * thumbnailScale;
+ mClippedInsets.bottom = deviceInsets.bottom * scale * thumbnailScale;
+ } else {
+ mClippedInsets.right = Math.max(0,
+ widthWithInsets - mClippedInsets.left - canvasWidth);
+ mClippedInsets.bottom = Math.max(0,
+ heightWithInsets - mClippedInsets.top - canvasHeight);
+ }
mMatrix.postScale(thumbnailScale, thumbnailScale);
@@ -508,6 +506,13 @@
mIsOrientationChanged = isOrientationDifferent;
}
+ private Rect getBoundedInsets(Rect activityInsets, Rect insets) {
+ return new Rect(Math.min(insets.left, activityInsets.left),
+ Math.min(insets.top, activityInsets.top),
+ Math.min(insets.right, activityInsets.right),
+ Math.min(insets.bottom, activityInsets.bottom));
+ }
+
private int getRotationDelta(int oldRotation, int newRotation) {
int delta = newRotation - oldRotation;
if (delta < 0) delta += 4;
@@ -557,9 +562,8 @@
/**
* Insets to used for clipping the thumbnail (in case it is drawing outside its own space)
*/
- public RectF getInsetsToDrawInFullscreen(boolean isMultiWindowMode) {
- // Don't show insets in multi window mode.
- return isMultiWindowMode ? EMPTY_RECT_F : mClippedInsets;
+ public RectF getInsetsToDrawInFullscreen() {
+ return mClippedInsets;
}
}
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
index aea5b8e..da9468e 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
@@ -30,7 +30,7 @@
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR;
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
-import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.TASK_LAUNCH_TAP;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_LAUNCH_TAP;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -212,7 +212,7 @@
mActivity.getUserEventDispatcher().logTaskLaunchOrDismiss(
Touch.TAP, Direction.NONE, getRecentsView().indexOfChild(this),
TaskUtils.getLaunchComponentKeyForTask(getTask().key));
- mActivity.getStatsLogManager().log(TASK_LAUNCH_TAP, buildProto());
+ mActivity.getStatsLogManager().log(LAUNCHER_TASK_LAUNCH_TAP, buildProto());
});
mCurrentFullscreenParams = new FullscreenDrawParams(context);
@@ -274,10 +274,10 @@
* TODO(b/142282126) Re-evaluate if we need to pass in isMultiWindowMode after
* that issue is fixed
*/
- public void bind(Task task, RecentsOrientedState orientedState, boolean isMultiWindowMode) {
+ public void bind(Task task, RecentsOrientedState orientedState) {
cancelPendingLoadTasks();
mTask = task;
- mSnapshotView.bind(task, isMultiWindowMode);
+ mSnapshotView.bind(task);
setOrientationState(orientedState);
}
@@ -448,14 +448,12 @@
}
public void setOrientationState(RecentsOrientedState orientationState) {
- int iconRotation = orientationState.getTouchRotation();
PagedOrientationHandler orientationHandler = orientationState.getOrientationHandler();
boolean isRtl = orientationHandler.getRecentsRtlSetting(getResources());
LayoutParams snapshotParams = (LayoutParams) mSnapshotView.getLayoutParams();
int thumbnailPadding = (int) getResources().getDimension(R.dimen.task_thumbnail_top_margin);
LayoutParams iconParams = (LayoutParams) mIconView.getLayoutParams();
- int rotation = orientationState.getTouchRotationDegrees();
- switch (iconRotation) {
+ switch (orientationHandler.getRotation()) {
case Surface.ROTATION_90:
iconParams.gravity = (isRtl ? END : START) | CENTER_VERTICAL;
iconParams.rightMargin = -thumbnailPadding;
@@ -480,7 +478,7 @@
break;
}
mIconView.setLayoutParams(iconParams);
- mIconView.setRotation(rotation);
+ mIconView.setRotation(orientationHandler.getDegreesRotated());
if (mMenuView != null) {
mMenuView.onRotationChanged();
@@ -671,7 +669,7 @@
mContextualChip.setScaleY(0f);
GradientDrawable scrimDrawable = (GradientDrawable) getResources().getDrawable(
R.drawable.chip_scrim_gradient, mActivity.getTheme());
- float cornerRadius = TaskCornerRadius.get(mActivity);
+ float cornerRadius = getTaskCornerRadius();
scrimDrawable.setCornerRadii(
new float[]{0, 0, 0, 0, cornerRadius, cornerRadius, cornerRadius,
cornerRadius});
@@ -690,6 +688,10 @@
}
}
+ public float getTaskCornerRadius() {
+ return TaskCornerRadius.get(mActivity);
+ }
+
/**
* Clears the contextual chip from TaskView.
*
@@ -1017,14 +1019,13 @@
*/
public void setProgress(float fullscreenProgress, float parentScale, int previewWidth,
DeviceProfile dp, PreviewPositionHelper pph) {
- boolean isMultiWindowMode = dp.isMultiWindowMode;
- RectF insets = pph.getInsetsToDrawInFullscreen(isMultiWindowMode);
+ RectF insets = pph.getInsetsToDrawInFullscreen();
float currentInsetsLeft = insets.left * fullscreenProgress;
float currentInsetsRight = insets.right * fullscreenProgress;
mCurrentDrawnInsets.set(currentInsetsLeft, insets.top * fullscreenProgress,
currentInsetsRight, insets.bottom * fullscreenProgress);
- float fullscreenCornerRadius = isMultiWindowMode ? 0 : mWindowCornerRadius;
+ float fullscreenCornerRadius = dp.isMultiWindowMode ? 0 : mWindowCornerRadius;
mCurrentDrawnCornerRadius =
Utilities.mapRange(fullscreenProgress, mCornerRadius, fullscreenCornerRadius)
diff --git a/quickstep/res/drawable/assistant_gesture.xml b/quickstep/res/drawable/assistant_gesture.xml
new file mode 100644
index 0000000..ba4331c
--- /dev/null
+++ b/quickstep/res/drawable/assistant_gesture.xml
@@ -0,0 +1,989 @@
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="412dp"
+ android:height="890dp"
+ android:viewportWidth="412"
+ android:viewportHeight="890">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_4_G_N_2_N_3_N_4_T_1"
+ android:rotation="-10"
+ android:translateX="661.757"
+ android:translateY="1026.235">
+ <group
+ android:name="_R_G_L_4_G_N_2_N_3_N_4_T_0"
+ android:translateX="-148.438"
+ android:translateY="-239.65">
+ <group
+ android:name="_R_G_L_4_G_N_2_N_3_T_0"
+ android:translateX="-61.73500000000001"
+ android:translateY="38.257000000000005">
+ <group
+ android:name="_R_G_L_4_G_N_2_T_0"
+ android:pivotX="83.124"
+ android:pivotY="89.259"
+ android:rotation="-16"
+ android:translateX="-50.44799999999999"
+ android:translateY="-62.925">
+ <group
+ android:name="_R_G_L_4_G"
+ android:translateX="-18.21"
+ android:translateY="-17.394">
+ <path
+ android:name="_R_G_L_4_G_D_0_P_0"
+ android:fillAlpha="0"
+ android:fillColor="#e8f0fe"
+ android:fillType="nonZero"
+ android:pathData=" M96.25 48.25 C96.25,74.76 74.76,96.25 48.25,96.25 C21.74,96.25 0.25,74.76 0.25,48.25 C0.25,21.74 21.74,0.25 48.25,0.25 C74.76,0.25 96.25,21.74 96.25,48.25c " />
+ </group>
+ </group>
+ </group>
+ </group>
+ </group>
+ <group
+ android:name="_R_G_L_3_G"
+ android:pivotX="48.25"
+ android:pivotY="48.25"
+ android:rotation="11"
+ android:translateX="227.046"
+ android:translateY="642.467">
+ <path
+ android:name="_R_G_L_3_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#e8f0fe"
+ android:fillType="nonZero"
+ android:pathData=" M96.25 48.25 C96.25,74.76 74.76,96.25 48.25,96.25 C21.74,96.25 0.25,74.76 0.25,48.25 C0.25,21.74 21.74,0.25 48.25,0.25 C74.76,0.25 96.25,21.74 96.25,48.25c " />
+ </group>
+ <group
+ android:name="_R_G_L_2_G_T_1"
+ android:rotation="-10"
+ android:translateX="661.757"
+ android:translateY="1026.235">
+ <group
+ android:name="_R_G_L_2_G"
+ android:translateX="-148.438"
+ android:translateY="-239.65">
+ <path
+ android:name="_R_G_L_2_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#d2e3fc"
+ android:fillType="nonZero"
+ android:pathData=" M14.25 224.54 C40.46,320.73 128.6,415.05 212.61,415.05 C296.63,415.05 188.65,199.66 188.65,99.96 C188.65,0.25 122.97,160.22 18.3,95.88 C1.02,85.21 0.25,173.17 14.25,224.54c " />
+ </group>
+ </group>
+ <group
+ android:name="_R_G_L_1_G_N_4_T_1"
+ android:rotation="-10"
+ android:translateX="661.757"
+ android:translateY="1026.235">
+ <group
+ android:name="_R_G_L_1_G_N_4_T_0"
+ android:translateX="-148.438"
+ android:translateY="-239.65">
+ <group
+ android:name="_R_G_L_1_G"
+ android:translateX="-61.73500000000001"
+ android:translateY="38.257000000000005">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#d2e3fc"
+ android:fillType="nonZero"
+ android:pathData=" M60.8 0.25 C60.8,0.25 76.32,20.36 105.56,60.3 C134.8,100.25 207.8,82.25 207.8,82.25 C207.8,82.25 211.01,150.18 211.01,150.18 C211.01,150.18 81.43,193.5 81.43,193.5 C81.43,193.5 31.8,174.25 31.8,174.25 C31.8,174.25 27.8,109.25 22.8,89.25 C17.8,69.25 6.15,49.9 2.17,41.17 C0.25,36.95 13.88,27.25 28.48,18.35 C44.09,8.84 60.8,0.25 60.8,0.25c " />
+ </group>
+ </group>
+ </group>
+ <group
+ android:name="_R_G_L_0_G_N_3_N_4_T_1"
+ android:rotation="-10"
+ android:translateX="661.757"
+ android:translateY="1026.235">
+ <group
+ android:name="_R_G_L_0_G_N_3_N_4_T_0"
+ android:translateX="-148.438"
+ android:translateY="-239.65">
+ <group
+ android:name="_R_G_L_0_G_N_3_T_0"
+ android:translateX="-61.73500000000001"
+ android:translateY="38.257000000000005">
+ <group
+ android:name="_R_G_L_0_G"
+ android:pivotX="83.124"
+ android:pivotY="89.259"
+ android:rotation="-16"
+ android:translateX="-50.44799999999999"
+ android:translateY="-62.925">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#d2e3fc"
+ android:fillType="nonZero"
+ android:pathData=" M19.19 14.59 C40.48,0.25 55.28,10.31 73.92,28.68 C92.56,47.05 106.44,53.33 112.22,64.44 C118,75.56 76.45,102.74 64.42,104.51 C52.38,106.27 30.98,101.06 19.76,76.77 C8.07,51.48 0.54,27.15 19.19,14.59c " />
+ <path
+ android:name="_R_G_L_0_G_D_1_P_0"
+ android:pathData=" M57.29 26.52 C59.8,29.86 61.05,33.88 55.15,38.41 C55.15,38.41 49.91,42.03 36.73,51.93 C34.96,53.26 32.72,55.37 30.64,55.46 C28.92,55.55 26.91,54.65 25.14,51.9 C19.1,42.49 15,36.09 17.17,30.02 "
+ android:strokeWidth="6"
+ android:strokeAlpha="1"
+ android:strokeColor="#a0c2f9" />
+ <path
+ android:name="_R_G_L_0_G_D_2_P_0"
+ android:pathData=" M64.41 90.04 C64.41,90.04 69.67,62.88 99.15,59.26 "
+ android:strokeWidth="6"
+ android:strokeAlpha="1"
+ android:strokeColor="#a0c2f9" />
+ </group>
+ </group>
+ </group>
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_4_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="233"
+ android:propertyName="fillAlpha"
+ android:startOffset="333"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_4_G_N_2_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="-16"
+ android:valueTo="-16"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="783"
+ android:propertyName="rotation"
+ android:startOffset="450"
+ android:valueFrom="-16"
+ android:valueTo="11"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="rotation"
+ android:startOffset="1233"
+ android:valueFrom="11"
+ android:valueTo="11"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1400"
+ android:propertyName="rotation"
+ android:startOffset="1683"
+ android:valueFrom="11"
+ android:valueTo="-16"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.205,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_4_G_N_2_N_3_N_4_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="661.757"
+ android:valueTo="661.757"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="900"
+ android:propertyName="translateX"
+ android:startOffset="333"
+ android:valueFrom="661.757"
+ android:valueTo="493.757"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="translateX"
+ android:startOffset="1233"
+ android:valueFrom="493.757"
+ android:valueTo="497.757"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1400"
+ android:propertyName="translateX"
+ android:startOffset="1683"
+ android:valueFrom="497.757"
+ android:valueTo="661.757"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.303,0 0.205,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_4_G_N_2_N_3_N_4_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="translateY"
+ android:startOffset="0"
+ android:valueFrom="1026.235"
+ android:valueTo="1026.235"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="900"
+ android:propertyName="translateY"
+ android:startOffset="333"
+ android:valueFrom="1026.235"
+ android:valueTo="933.235"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="translateY"
+ android:startOffset="1233"
+ android:valueFrom="933.235"
+ android:valueTo="939.235"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1400"
+ android:propertyName="translateY"
+ android:startOffset="1683"
+ android:valueFrom="939.235"
+ android:valueTo="1026.235"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.303,0 0.205,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_4_G_N_2_N_3_N_4_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="-10"
+ android:valueTo="-10"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="900"
+ android:propertyName="rotation"
+ android:startOffset="333"
+ android:valueFrom="-10"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="rotation"
+ android:startOffset="1233"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1400"
+ android:propertyName="rotation"
+ android:startOffset="1683"
+ android:valueFrom="0"
+ android:valueTo="-10"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.205,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_4_G_N_2_N_3_N_4_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="0"
+ android:propertyName="scaleY"
+ android:startOffset="1233"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_3_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="1233"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="383"
+ android:propertyName="fillAlpha"
+ android:startOffset="1233"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_3_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="0"
+ android:propertyName="scaleX"
+ android:startOffset="1233"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="661.757"
+ android:valueTo="661.757"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="900"
+ android:propertyName="translateX"
+ android:startOffset="333"
+ android:valueFrom="661.757"
+ android:valueTo="493.757"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="translateX"
+ android:startOffset="1233"
+ android:valueFrom="493.757"
+ android:valueTo="497.757"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1400"
+ android:propertyName="translateX"
+ android:startOffset="1683"
+ android:valueFrom="497.757"
+ android:valueTo="661.757"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.303,0 0.205,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="translateY"
+ android:startOffset="0"
+ android:valueFrom="1026.235"
+ android:valueTo="1026.235"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="900"
+ android:propertyName="translateY"
+ android:startOffset="333"
+ android:valueFrom="1026.235"
+ android:valueTo="933.235"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="translateY"
+ android:startOffset="1233"
+ android:valueFrom="933.235"
+ android:valueTo="939.235"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1400"
+ android:propertyName="translateY"
+ android:startOffset="1683"
+ android:valueFrom="939.235"
+ android:valueTo="1026.235"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.303,0 0.205,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="-10"
+ android:valueTo="-10"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="900"
+ android:propertyName="rotation"
+ android:startOffset="333"
+ android:valueFrom="-10"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="rotation"
+ android:startOffset="1233"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1400"
+ android:propertyName="rotation"
+ android:startOffset="1683"
+ android:valueFrom="0"
+ android:valueTo="-10"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.205,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_N_4_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="661.757"
+ android:valueTo="661.757"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="900"
+ android:propertyName="translateX"
+ android:startOffset="333"
+ android:valueFrom="661.757"
+ android:valueTo="493.757"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="translateX"
+ android:startOffset="1233"
+ android:valueFrom="493.757"
+ android:valueTo="497.757"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1400"
+ android:propertyName="translateX"
+ android:startOffset="1683"
+ android:valueFrom="497.757"
+ android:valueTo="661.757"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.303,0 0.205,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_N_4_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="translateY"
+ android:startOffset="0"
+ android:valueFrom="1026.235"
+ android:valueTo="1026.235"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="900"
+ android:propertyName="translateY"
+ android:startOffset="333"
+ android:valueFrom="1026.235"
+ android:valueTo="933.235"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="translateY"
+ android:startOffset="1233"
+ android:valueFrom="933.235"
+ android:valueTo="939.235"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1400"
+ android:propertyName="translateY"
+ android:startOffset="1683"
+ android:valueFrom="939.235"
+ android:valueTo="1026.235"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.303,0 0.205,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_N_4_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="-10"
+ android:valueTo="-10"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="900"
+ android:propertyName="rotation"
+ android:startOffset="333"
+ android:valueFrom="-10"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="rotation"
+ android:startOffset="1233"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1400"
+ android:propertyName="rotation"
+ android:startOffset="1683"
+ android:valueFrom="0"
+ android:valueTo="-10"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.205,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M19.19 14.59 C40.48,0.25 55.28,10.31 73.92,28.68 C92.56,47.05 106.44,53.33 112.22,64.44 C118,75.56 76.45,102.74 64.42,104.51 C52.38,106.27 30.98,101.06 19.76,76.77 C8.07,51.48 0.54,27.15 19.19,14.59c "
+ android:valueTo="M19.19 14.59 C40.48,0.25 55.28,10.31 73.92,28.68 C92.56,47.05 106.44,53.33 112.22,64.44 C118,75.56 76.45,102.74 64.42,104.51 C52.38,106.27 30.98,101.06 19.76,76.77 C8.07,51.48 0.54,27.15 19.19,14.59c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="783"
+ android:propertyName="pathData"
+ android:startOffset="450"
+ android:valueFrom="M19.19 14.59 C40.48,0.25 55.28,10.31 73.92,28.68 C92.56,47.05 106.44,53.33 112.22,64.44 C118,75.56 76.45,102.74 64.42,104.51 C52.38,106.27 30.98,101.06 19.76,76.77 C8.07,51.48 0.54,27.15 19.19,14.59c "
+ android:valueTo="M19.19 14.59 C40.48,0.25 55.28,10.31 73.92,28.68 C92.56,47.05 106.44,53.33 112.22,64.44 C118,75.56 103.84,114.98 73.16,119.19 C61.1,120.84 30.98,101.06 19.76,76.77 C8.07,51.48 0.54,27.15 19.19,14.59c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="pathData"
+ android:startOffset="1233"
+ android:valueFrom="M19.19 14.59 C40.48,0.25 55.28,10.31 73.92,28.68 C92.56,47.05 106.44,53.33 112.22,64.44 C118,75.56 103.84,114.98 73.16,119.19 C61.1,120.84 30.98,101.06 19.76,76.77 C8.07,51.48 0.54,27.15 19.19,14.59c "
+ android:valueTo="M19.19 14.59 C40.48,0.25 55.28,10.31 73.92,28.68 C92.56,47.05 106.44,53.33 112.22,64.44 C118,75.56 103.84,114.98 73.16,119.19 C61.1,120.84 30.98,101.06 19.76,76.77 C8.07,51.48 0.54,27.15 19.19,14.59c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1400"
+ android:propertyName="pathData"
+ android:startOffset="1683"
+ android:valueFrom="M19.19 14.59 C40.48,0.25 55.28,10.31 73.92,28.68 C92.56,47.05 106.44,53.33 112.22,64.44 C118,75.56 103.84,114.98 73.16,119.19 C61.1,120.84 30.98,101.06 19.76,76.77 C8.07,51.48 0.54,27.15 19.19,14.59c "
+ android:valueTo="M19.19 14.59 C40.48,0.25 55.28,10.31 73.92,28.68 C92.56,47.05 106.44,53.33 112.22,64.44 C118,75.56 76.45,102.74 64.42,104.51 C52.38,106.27 30.98,101.06 19.76,76.77 C8.07,51.48 0.54,27.15 19.19,14.59c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="-16"
+ android:valueTo="-16"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="783"
+ android:propertyName="rotation"
+ android:startOffset="450"
+ android:valueFrom="-16"
+ android:valueTo="11"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="rotation"
+ android:startOffset="1233"
+ android:valueFrom="11"
+ android:valueTo="11"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1400"
+ android:propertyName="rotation"
+ android:startOffset="1683"
+ android:valueFrom="11"
+ android:valueTo="-16"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.205,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_N_3_N_4_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="661.757"
+ android:valueTo="661.757"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="900"
+ android:propertyName="translateX"
+ android:startOffset="333"
+ android:valueFrom="661.757"
+ android:valueTo="493.757"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="translateX"
+ android:startOffset="1233"
+ android:valueFrom="493.757"
+ android:valueTo="497.757"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1400"
+ android:propertyName="translateX"
+ android:startOffset="1683"
+ android:valueFrom="497.757"
+ android:valueTo="661.757"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.303,0 0.205,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_N_3_N_4_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="translateY"
+ android:startOffset="0"
+ android:valueFrom="1026.235"
+ android:valueTo="1026.235"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="900"
+ android:propertyName="translateY"
+ android:startOffset="333"
+ android:valueFrom="1026.235"
+ android:valueTo="933.235"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="translateY"
+ android:startOffset="1233"
+ android:valueFrom="933.235"
+ android:valueTo="939.235"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1400"
+ android:propertyName="translateY"
+ android:startOffset="1683"
+ android:valueFrom="939.235"
+ android:valueTo="1026.235"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.303,0 0.205,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_N_3_N_4_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="-10"
+ android:valueTo="-10"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="900"
+ android:propertyName="rotation"
+ android:startOffset="333"
+ android:valueFrom="-10"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="rotation"
+ android:startOffset="1233"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1400"
+ android:propertyName="rotation"
+ android:startOffset="1683"
+ android:valueFrom="0"
+ android:valueTo="-10"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.205,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="3167"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector>
\ No newline at end of file
diff --git a/quickstep/res/drawable/back_gesture.xml b/quickstep/res/drawable/back_gesture.xml
index a5c57b4..18ad2cb 100644
--- a/quickstep/res/drawable/back_gesture.xml
+++ b/quickstep/res/drawable/back_gesture.xml
@@ -1,100 +1,121 @@
-<!--
- Copyright (C) 2020 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt">
<aapt:attr name="android:drawable">
<vector
- android:width="206dp"
- android:height="435dp"
- android:viewportWidth="206"
- android:viewportHeight="435">
- <group android:name="edgeGroup"
- android:translateX="197"
- android:translateY="0">
- <path
- android:name="edge"
- android:fillAlpha="0"
- android:fillType="nonZero"
- android:fillColor="#1a73eb"
- android:pathData=" M0,0 h9 v435 h-9 z " />
- </group>
- <group
- android:name="trailGroup"
- android:translateX="226"
- android:translateY="200">
- <path
- android:name="trail"
- android:fillAlpha="1"
- android:fillType="nonZero"
- android:pathData=" M0,0 h55 v36 h-55 z ">
- <aapt:attr name="android:fillColor">
- <gradient
- android:startX="0"
- android:endX="55"
- android:type="linear">
- <item
- android:color="#991a73eb"
- android:offset="0" />
- <item
- android:color="#401a73eb"
- android:offset="0.5" />
- <item
- android:color="#001a73eb"
- android:offset="1" />
- </gradient>
- </aapt:attr>
- </path>
- </group>
+ android:width="412dp"
+ android:height="890dp"
+ android:viewportWidth="412"
+ android:viewportHeight="890">
<group android:name="_R_G">
<group
- android:name="_R_G_L_0_G_T_1"
- android:rotation="11"
- android:scaleX="0.9"
- android:scaleY="0.9"
- android:translateX="309"
- android:translateY="422.5">
+ android:name="_R_G_L_3_G_T_1"
+ android:rotation="29"
+ android:translateX="400.931"
+ android:translateY="449.112">
<group
- android:name="_R_G_L_0_G"
- android:translateX="-145"
- android:translateY="-208">
+ android:name="_R_G_L_3_G"
+ android:translateX="-51.449"
+ android:translateY="-51.449">
<path
- android:name="_R_G_L_0_G_D_0_P_0"
+ android:name="_R_G_L_3_G_D_0_P_0"
+ android:fillAlpha="0"
+ android:fillColor="#e8f0fe"
+ android:fillType="nonZero"
+ android:pathData=" M98.99 58.07 C95.33,84.33 71.08,102.65 44.83,98.99 C18.57,95.33 0.25,71.08 3.91,44.83 C7.57,18.57 31.82,0.25 58.07,3.91 C84.33,7.57 102.65,31.82 98.99,58.07c " />
+ </group>
+ </group>
+ <group
+ android:name="_R_G_L_2_G_T_1"
+ android:rotation="22"
+ android:translateX="443.275"
+ android:translateY="741.789">
+ <group
+ android:name="_R_G_L_2_G"
+ android:translateX="-199.299"
+ android:translateY="-310.469">
+ <path
+ android:name="_R_G_L_2_G_D_0_P_0"
android:fillAlpha="1"
android:fillColor="#d2e3fc"
android:fillType="nonZero"
- android:pathData=" M12.5 -47 C-7.93,-41.24 -3,-20.5 -1.5,-7 C0,6.5 2.5,22 9,39.5 C13.52,51.67 17.06,63.52 19,113 C21,164 53.5,243.5 53.5,243.5 C53.5,243.5 59,275.5 123.5,326 C188,376.5 283.5,236 290.5,199 C297.5,162 194.5,80 149,73 C103.5,66 90.5,57.5 77,50 C63.5,42.5 57,27 54.5,13.5 C52,0 43.5,-15 40,-25 C36.5,-35 32,-52.5 12.5,-47c " />
- <path
- android:name="_R_G_L_0_G_D_1_P_0"
- android:pathData=" M4.45 -34.66 C4.45,-34.66 10.5,-12.66 10.5,-12.66 C11.24,-9.98 13.98,-8.38 16.67,-9.04 C16.67,-9.04 29.72,-12.27 29.72,-12.27 C32.39,-12.93 34.05,-15.59 33.47,-18.28 C33.47,-18.28 32.11,-24.57 32.11,-24.57 "
- android:strokeWidth="4"
- android:strokeAlpha="1"
- android:strokeColor="#a0c2f9" />
- <path
- android:name="_R_G_L_0_G_D_2_P_0"
- android:pathData=" M18.35 21.81 C21.41,17.24 36.97,10.77 44.63,13.55 "
- android:strokeWidth="4"
- android:strokeAlpha="1"
- android:strokeColor="#a0c2f9" />
+ android:pathData=" M98.53 346.74 C150.31,507.99 279.63,534.69 366.99,534.69 C454.35,534.69 342.13,310.99 342.13,207.18 C342.13,103.37 244.29,336.77 102.92,212.59 C84.64,201.99 83.91,293.37 98.53,346.74c " />
+ </group>
+ </group>
+ <group
+ android:name="_R_G_L_1_G_N_2_N_4_T_1"
+ android:rotation="22"
+ android:translateX="443.275"
+ android:translateY="741.789">
+ <group
+ android:name="_R_G_L_1_G_N_2_N_4_T_0"
+ android:translateX="-199.299"
+ android:translateY="-310.469">
+ <group
+ android:name="_R_G_L_1_G_N_2_T_0"
+ android:translateX="32.843"
+ android:translateY="70.37599999999998">
+ <group
+ android:name="_R_G_L_1_G"
+ android:pivotX="63.901"
+ android:pivotY="99.512"
+ android:rotation="-7"
+ android:translateX="-28.42"
+ android:translateY="-66.62700000000001">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#d2e3fc"
+ android:fillType="nonZero"
+ android:pathData=" M24.09 7.19 C24.09,7.19 24.09,7.19 24.09,7.19 C37.34,0.25 53.74,5.21 61.53,18.2 C61.53,18.2 92.06,67.99 92.06,67.99 C99.55,85.1 94.55,109.83 77.93,118.03 C77.93,118.03 73.41,119.96 73.41,119.96 C54.93,128.77 33.79,118.95 27.61,98.93 C27.61,98.93 9.41,43.77 9.41,43.77 C4.59,29.86 10.87,13.76 24.09,7.19c " />
+ <path
+ android:name="_R_G_L_1_G_D_1_P_0"
+ android:pathData=" M62.63 26.42 C64.51,30.16 64.56,33.23 61.29,34.92 C61.29,34.92 57.3,38.02 54.34,39.55 C52.36,40.56 31.95,52.96 29.89,52.69 C28.18,52.46 25.13,43.84 23.56,39.57 C19.67,28.95 23.51,23 30.85,17.22 "
+ android:strokeWidth="6"
+ android:strokeAlpha="1"
+ android:strokeColor="#a0c2f9" />
+ </group>
+ </group>
+ </group>
+ </group>
+ <group
+ android:name="_R_G_L_0_G_N_4_T_1"
+ android:rotation="22"
+ android:translateX="443.275"
+ android:translateY="741.789">
+ <group
+ android:name="_R_G_L_0_G_N_4_T_0"
+ android:translateX="-199.299"
+ android:translateY="-310.469">
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="32.843"
+ android:translateY="70.37599999999998">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#d2e3fc"
+ android:fillType="nonZero"
+ android:pathData=" M46.18 2.25 C46.18,2.25 63.07,0.46 63.07,0.46 C71.25,13.11 74.51,28.4 84.08,41.9 C107.62,73.73 129.25,98.04 175.54,101.59 C278.31,96.7 179.52,210.03 162.67,266.4 C162.67,266.4 58.91,211.6 58.91,211.6 C56.64,197.88 36.96,112.53 21.91,82.02 C12.91,63.77 2.48,47.19 -0.01,35.78 C-0.24,33.88 0.25,27.89 12.82,15.25 C21.14,6.07 34.31,0.25 46.18,2.25c " />
+ <path
+ android:name="_R_G_L_0_G_D_1_P_0"
+ android:pathData=" M37.4 46.68 C37.4,46.68 53.75,25.93 70.25,28.88 "
+ android:strokeWidth="6"
+ android:strokeAlpha="1"
+ android:strokeColor="#a0c2f9" />
+ <path
+ android:name="_R_G_L_0_G_D_2_P_0"
+ android:pathData=" M157.71 101.59 C157.71,101.59 165.04,114.63 190.3,113 "
+ android:strokeWidth="6"
+ android:strokeAlpha="1"
+ android:strokeColor="#a0c2f9" />
+ </group>
</group>
</group>
</group>
<group android:name="time_group" />
</vector>
</aapt:attr>
- <target android:name="edge">
+ <target android:name="_R_G_L_3_G_D_0_P_0">
<aapt:attr name="android:animation">
<set android:ordering="together">
<objectAnimator
@@ -102,44 +123,27 @@
android:propertyName="fillAlpha"
android:startOffset="0"
android:valueFrom="0"
- android:valueTo="0.2"
- android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
- </aapt:attr>
- </objectAnimator>
- <objectAnimator
- android:duration="917"
- android:propertyName="fillAlpha"
- android:startOffset="333"
- android:valueFrom="0.2"
- android:valueTo="0.2"
- android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
- </aapt:attr>
- </objectAnimator>
- <objectAnimator
- android:duration="583"
- android:propertyName="fillAlpha"
- android:startOffset="1250"
- android:valueFrom="0.2"
android:valueTo="0"
android:valueType="floatType">
<aapt:attr name="android:interpolator">
<pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
</aapt:attr>
</objectAnimator>
- </set>
- </aapt:attr>
- </target>
- <target android:name="trail">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
<objectAnimator
- android:duration="2000"
+ android:duration="167"
android:propertyName="fillAlpha"
- android:startOffset="0"
+ android:startOffset="333"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="500"
+ android:propertyName="fillAlpha"
+ android:startOffset="500"
android:valueFrom="1"
android:valueTo="1"
android:valueType="floatType">
@@ -148,9 +152,9 @@
</aapt:attr>
</objectAnimator>
<objectAnimator
- android:duration="850"
+ android:duration="367"
android:propertyName="fillAlpha"
- android:startOffset="2000"
+ android:startOffset="1000"
android:valueFrom="1"
android:valueTo="0"
android:valueType="floatType">
@@ -161,51 +165,468 @@
</set>
</aapt:attr>
</target>
- <target android:name="trailGroup">
+ <target android:name="_R_G_L_3_G_T_1">
<aapt:attr name="android:animation">
<set android:ordering="together">
<objectAnimator
- android:duration="83"
+ android:duration="333"
android:propertyName="translateX"
- android:startOffset="1250"
- android:valueFrom="226"
- android:valueTo="226"
+ android:startOffset="0"
+ android:valueFrom="400.931"
+ android:valueTo="400.931"
android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.285,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
</aapt:attr>
</objectAnimator>
<objectAnimator
+ android:duration="667"
+ android:propertyName="translateX"
+ android:startOffset="333"
+ android:valueFrom="400.931"
+ android:valueTo="232.931"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="443.275"
+ android:valueTo="443.275"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="667"
+ android:propertyName="translateX"
+ android:startOffset="333"
+ android:valueFrom="443.275"
+ android:valueTo="403.275"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="600"
+ android:propertyName="translateX"
+ android:startOffset="1000"
+ android:valueFrom="403.275"
+ android:valueTo="403.275"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1067"
+ android:propertyName="translateX"
+ android:startOffset="1600"
+ android:valueFrom="403.275"
+ android:valueTo="443.275"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.349,0 0.21,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="translateY"
+ android:startOffset="0"
+ android:valueFrom="741.789"
+ android:valueTo="741.789"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="667"
+ android:propertyName="translateY"
+ android:startOffset="333"
+ android:valueFrom="741.789"
+ android:valueTo="741.789"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="600"
+ android:propertyName="translateY"
+ android:startOffset="1000"
+ android:valueFrom="741.789"
+ android:valueTo="741.789"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1067"
+ android:propertyName="translateY"
+ android:startOffset="1600"
+ android:valueFrom="741.789"
+ android:valueTo="741.789"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.349,0 0.21,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="22"
+ android:valueTo="22"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="667"
+ android:propertyName="rotation"
+ android:startOffset="333"
+ android:valueFrom="22"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="600"
+ android:propertyName="rotation"
+ android:startOffset="1000"
+ android:valueFrom="0"
+ android:valueTo="2"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.324,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1067"
+ android:propertyName="rotation"
+ android:startOffset="1600"
+ android:valueFrom="2"
+ android:valueTo="22"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.349,0 0.21,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
android:duration="1000"
- android:propertyName="translateX"
- android:startOffset="1333"
- android:valueFrom="226"
- android:valueTo="151"
- android:valueType="floatType">
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M24.09 7.19 C24.09,7.19 24.09,7.19 24.09,7.19 C37.34,0.25 53.74,5.21 61.53,18.2 C61.53,18.2 92.06,67.99 92.06,67.99 C99.55,85.1 94.55,109.83 77.93,118.03 C77.93,118.03 73.41,119.96 73.41,119.96 C54.93,128.77 33.79,118.95 27.61,98.93 C27.61,98.93 9.41,43.77 9.41,43.77 C4.59,29.86 10.87,13.76 24.09,7.19c "
+ android:valueTo="M24.09 7.19 C24.09,7.19 24.09,7.19 24.09,7.19 C37.34,0.25 53.74,5.21 61.53,18.2 C61.53,18.2 92.06,67.99 92.06,67.99 C99.55,85.1 94.55,109.83 77.93,118.03 C77.93,118.03 73.41,119.96 73.41,119.96 C54.93,128.77 33.79,118.95 27.61,98.93 C27.61,98.93 9.41,43.77 9.41,43.77 C4.59,29.86 10.87,13.76 24.09,7.19c "
+ android:valueType="pathType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.285,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
</aapt:attr>
</objectAnimator>
<objectAnimator
- android:duration="517"
- android:propertyName="translateX"
- android:startOffset="2333"
- android:valueFrom="151"
- android:valueTo="151"
- android:valueType="floatType">
+ android:duration="600"
+ android:propertyName="pathData"
+ android:startOffset="1000"
+ android:valueFrom="M24.09 7.19 C24.09,7.19 24.09,7.19 24.09,7.19 C37.34,0.25 53.74,5.21 61.53,18.2 C61.53,18.2 92.06,67.99 92.06,67.99 C99.55,85.1 94.55,109.83 77.93,118.03 C77.93,118.03 73.41,119.96 73.41,119.96 C54.93,128.77 33.79,118.95 27.61,98.93 C27.61,98.93 9.41,43.77 9.41,43.77 C4.59,29.86 10.87,13.76 24.09,7.19c "
+ android:valueTo="M24.09 7.19 C24.09,7.19 24.09,7.19 24.09,7.19 C37.34,0.25 53.74,5.21 61.53,18.2 C61.53,18.2 92.06,67.99 92.06,67.99 C99.55,85.1 94.55,109.83 77.93,118.03 C77.93,118.03 73.41,119.96 73.41,119.96 C54.93,128.77 33.79,118.95 27.61,98.93 C27.61,98.93 9.41,43.77 9.41,43.77 C4.59,29.86 10.87,13.76 24.09,7.19c "
+ android:valueType="pathType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.285,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
</aapt:attr>
</objectAnimator>
<objectAnimator
- android:duration="50"
- android:propertyName="translateX"
- android:startOffset="2850"
- android:valueFrom="226"
- android:valueTo="226"
+ android:duration="1067"
+ android:propertyName="pathData"
+ android:startOffset="1600"
+ android:valueFrom="M24.09 7.19 C24.09,7.19 24.09,7.19 24.09,7.19 C37.34,0.25 53.74,5.21 61.53,18.2 C61.53,18.2 92.06,67.99 92.06,67.99 C99.55,85.1 94.55,109.83 77.93,118.03 C77.93,118.03 73.41,119.96 73.41,119.96 C54.93,128.77 33.79,118.95 27.61,98.93 C27.61,98.93 9.41,43.77 9.41,43.77 C4.59,29.86 10.87,13.76 24.09,7.19c "
+ android:valueTo="M24.09 7.19 C24.09,7.19 24.09,7.19 24.09,7.19 C37.34,0.25 53.74,5.21 61.53,18.2 C61.53,18.2 92.06,67.99 92.06,67.99 C99.55,85.1 94.55,109.83 77.93,118.03 C77.93,118.03 73.41,119.96 73.41,119.96 C54.93,128.77 33.79,118.95 27.61,98.93 C27.61,98.93 9.41,43.77 9.41,43.77 C4.59,29.86 10.87,13.76 24.09,7.19c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_D_1_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M62.63 26.42 C64.51,30.16 64.56,33.23 61.29,34.92 C61.29,34.92 57.3,38.02 54.34,39.55 C52.36,40.56 31.95,52.96 29.89,52.69 C28.18,52.46 25.13,43.84 23.56,39.57 C19.67,28.95 23.51,23 30.85,17.22 "
+ android:valueTo="M62.63 26.42 C64.51,30.16 64.56,33.23 61.29,34.92 C61.29,34.92 57.3,38.02 54.34,39.55 C52.36,40.56 31.95,52.96 29.89,52.69 C28.18,52.46 25.13,43.84 23.56,39.57 C19.67,28.95 23.51,23 30.85,17.22 "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="667"
+ android:propertyName="pathData"
+ android:startOffset="333"
+ android:valueFrom="M62.63 26.42 C64.51,30.16 64.56,33.23 61.29,34.92 C61.29,34.92 57.3,38.02 54.34,39.55 C52.36,40.56 31.95,52.96 29.89,52.69 C28.18,52.46 25.13,43.84 23.56,39.57 C19.67,28.95 23.51,23 30.85,17.22 "
+ android:valueTo="M58.31 29.65 C60.19,33.38 60.72,37.56 54.12,40.99 C54.12,40.99 48.32,43.62 33.61,51.06 C31.63,52.06 29.06,53.73 26.99,53.46 C25.28,53.24 23.46,52.01 22.2,48.99 C17.92,38.66 15,31.64 18.2,26.05 "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="600"
+ android:propertyName="pathData"
+ android:startOffset="1000"
+ android:valueFrom="M58.31 29.65 C60.19,33.38 60.72,37.56 54.12,40.99 C54.12,40.99 48.32,43.62 33.61,51.06 C31.63,52.06 29.06,53.73 26.99,53.46 C25.28,53.24 23.46,52.01 22.2,48.99 C17.92,38.66 15,31.64 18.2,26.05 "
+ android:valueTo="M58.31 29.65 C60.19,33.38 60.72,37.56 54.12,40.99 C54.12,40.99 48.32,43.62 33.61,51.06 C31.63,52.06 29.06,53.73 26.99,53.46 C25.28,53.24 23.46,52.01 22.2,48.99 C17.92,38.66 15,31.64 18.2,26.05 "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1067"
+ android:propertyName="pathData"
+ android:startOffset="1600"
+ android:valueFrom="M58.31 29.65 C60.19,33.38 60.72,37.56 54.12,40.99 C54.12,40.99 48.32,43.62 33.61,51.06 C31.63,52.06 29.06,53.73 26.99,53.46 C25.28,53.24 23.46,52.01 22.2,48.99 C17.92,38.66 15,31.64 18.2,26.05 "
+ android:valueTo="M62.63 26.42 C64.51,30.16 64.56,33.23 61.29,34.92 C61.29,34.92 57.3,38.02 54.34,39.55 C52.36,40.56 31.95,52.96 29.89,52.69 C28.18,52.46 25.13,43.84 23.56,39.57 C19.67,28.95 23.51,23 30.85,17.22 "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="-7"
+ android:valueTo="-7"
android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.285,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.315,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="667"
+ android:propertyName="rotation"
+ android:startOffset="333"
+ android:valueFrom="-7"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.315,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="600"
+ android:propertyName="rotation"
+ android:startOffset="1000"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1067"
+ android:propertyName="rotation"
+ android:startOffset="1600"
+ android:valueFrom="0"
+ android:valueTo="-7"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.349,0 0.21,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_N_2_N_4_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="443.275"
+ android:valueTo="443.275"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="667"
+ android:propertyName="translateX"
+ android:startOffset="333"
+ android:valueFrom="443.275"
+ android:valueTo="403.275"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="600"
+ android:propertyName="translateX"
+ android:startOffset="1000"
+ android:valueFrom="403.275"
+ android:valueTo="403.275"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1067"
+ android:propertyName="translateX"
+ android:startOffset="1600"
+ android:valueFrom="403.275"
+ android:valueTo="443.275"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.349,0 0.21,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_N_2_N_4_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="translateY"
+ android:startOffset="0"
+ android:valueFrom="741.789"
+ android:valueTo="741.789"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="667"
+ android:propertyName="translateY"
+ android:startOffset="333"
+ android:valueFrom="741.789"
+ android:valueTo="741.789"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="600"
+ android:propertyName="translateY"
+ android:startOffset="1000"
+ android:valueFrom="741.789"
+ android:valueTo="741.789"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1067"
+ android:propertyName="translateY"
+ android:startOffset="1600"
+ android:valueFrom="741.789"
+ android:valueTo="741.789"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.349,0 0.21,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_N_2_N_4_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="22"
+ android:valueTo="22"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="667"
+ android:propertyName="rotation"
+ android:startOffset="333"
+ android:valueFrom="22"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="600"
+ android:propertyName="rotation"
+ android:startOffset="1000"
+ android:valueFrom="0"
+ android:valueTo="2"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.324,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1067"
+ android:propertyName="rotation"
+ android:startOffset="1600"
+ android:valueFrom="2"
+ android:valueTo="22"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.349,0 0.21,1 1.0,1.0" />
</aapt:attr>
</objectAnimator>
</set>
@@ -215,25 +636,47 @@
<aapt:attr name="android:animation">
<set android:ordering="together">
<objectAnimator
- android:duration="1833"
- android:propertyName="fillAlpha"
- android:startOffset="1250"
- android:valueFrom="1"
- android:valueTo="1"
- android:valueType="floatType">
+ android:duration="333"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M46.18 2.25 C46.18,2.25 63.07,0.46 63.07,0.46 C71.25,13.11 74.51,28.4 84.08,41.9 C107.62,73.73 129.25,98.04 175.54,101.59 C278.31,96.7 179.52,210.03 162.67,266.4 C162.67,266.4 58.91,211.6 58.91,211.6 C56.64,197.88 36.96,112.53 21.91,82.02 C12.91,63.77 2.48,47.19 -0.01,35.78 C-0.24,33.88 0.25,27.89 12.82,15.25 C21.14,6.07 34.31,0.25 46.18,2.25c "
+ android:valueTo="M46.18 2.25 C46.18,2.25 63.07,0.46 63.07,0.46 C71.25,13.11 74.51,28.4 84.08,41.9 C107.62,73.73 129.25,98.04 175.54,101.59 C278.31,96.7 179.52,210.03 162.67,266.4 C162.67,266.4 58.91,211.6 58.91,211.6 C56.64,197.88 36.96,112.53 21.91,82.02 C12.91,63.77 2.48,47.19 -0.01,35.78 C-0.24,33.88 0.25,27.89 12.82,15.25 C21.14,6.07 34.31,0.25 46.18,2.25c "
+ android:valueType="pathType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
</aapt:attr>
</objectAnimator>
<objectAnimator
- android:duration="167"
- android:propertyName="fillAlpha"
- android:startOffset="3083"
- android:valueFrom="1"
- android:valueTo="0"
- android:valueType="floatType">
+ android:duration="667"
+ android:propertyName="pathData"
+ android:startOffset="333"
+ android:valueFrom="M46.18 2.25 C46.18,2.25 63.07,0.46 63.07,0.46 C71.25,13.11 74.51,28.4 84.08,41.9 C107.62,73.73 129.25,98.04 175.54,101.59 C278.31,96.7 179.52,210.03 162.67,266.4 C162.67,266.4 58.91,211.6 58.91,211.6 C56.64,197.88 36.96,112.53 21.91,82.02 C12.91,63.77 2.48,47.19 -0.01,35.78 C-0.24,33.88 0.25,27.89 12.82,15.25 C21.14,6.07 34.31,0.25 46.18,2.25c "
+ android:valueTo="M46.18 2.25 C46.18,2.25 63.07,0.46 63.07,0.46 C71.25,13.11 74.51,28.4 84.08,41.9 C107.62,73.73 129.25,98.04 175.54,101.59 C278.31,96.7 179.52,210.03 162.67,266.4 C162.67,266.4 58.91,211.6 58.91,211.6 C56.64,197.88 39,110.89 30.58,91.46 C22.47,72.8 10.93,51.25 2.97,40.51 C2.75,38.61 0.25,27.89 12.82,15.25 C21.14,6.07 34.31,0.25 46.18,2.25c "
+ android:valueType="pathType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="600"
+ android:propertyName="pathData"
+ android:startOffset="1000"
+ android:valueFrom="M46.18 2.25 C46.18,2.25 63.07,0.46 63.07,0.46 C71.25,13.11 74.51,28.4 84.08,41.9 C107.62,73.73 129.25,98.04 175.54,101.59 C278.31,96.7 179.52,210.03 162.67,266.4 C162.67,266.4 58.91,211.6 58.91,211.6 C56.64,197.88 39,110.89 30.58,91.46 C22.47,72.8 10.93,51.25 2.97,40.51 C2.75,38.61 0.25,27.89 12.82,15.25 C21.14,6.07 34.31,0.25 46.18,2.25c "
+ android:valueTo="M46.18 2.25 C46.18,2.25 63.07,0.46 63.07,0.46 C71.25,13.11 74.51,28.4 84.08,41.9 C107.62,73.73 129.25,98.04 175.54,101.59 C278.31,96.7 179.52,210.03 162.67,266.4 C162.67,266.4 58.91,211.6 58.91,211.6 C56.64,197.88 39,110.89 30.58,91.46 C22.47,72.8 10.93,51.25 2.97,40.51 C2.75,38.61 0.25,27.89 12.82,15.25 C21.14,6.07 34.31,0.25 46.18,2.25c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1067"
+ android:propertyName="pathData"
+ android:startOffset="1600"
+ android:valueFrom="M46.18 2.25 C46.18,2.25 63.07,0.46 63.07,0.46 C71.25,13.11 74.51,28.4 84.08,41.9 C107.62,73.73 129.25,98.04 175.54,101.59 C278.31,96.7 179.52,210.03 162.67,266.4 C162.67,266.4 58.91,211.6 58.91,211.6 C56.64,197.88 39,110.89 30.58,91.46 C22.47,72.8 10.93,51.25 2.97,40.51 C2.75,38.61 0.25,27.89 12.82,15.25 C21.14,6.07 34.31,0.25 46.18,2.25c "
+ android:valueTo="M46.18 2.25 C46.18,2.25 63.07,0.46 63.07,0.46 C71.25,13.11 74.51,28.4 84.08,41.9 C107.62,73.73 129.25,98.04 175.54,101.59 C278.31,96.7 179.52,210.03 162.67,266.4 C162.67,266.4 58.91,211.6 58.91,211.6 C56.64,197.88 36.96,112.53 21.91,82.02 C12.91,63.77 2.48,47.19 -0.01,35.78 C-0.24,33.88 0.25,27.89 12.82,15.25 C21.14,6.07 34.31,0.25 46.18,2.25c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.269,1 1.0,1.0" />
</aapt:attr>
</objectAnimator>
</set>
@@ -243,109 +686,197 @@
<aapt:attr name="android:animation">
<set android:ordering="together">
<objectAnimator
- android:duration="1833"
- android:propertyName="strokeAlpha"
- android:startOffset="1250"
- android:valueFrom="1"
- android:valueTo="1"
- android:valueType="floatType">
+ android:duration="333"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M37.4 46.68 C37.4,46.68 53.75,25.93 70.25,28.88 "
+ android:valueTo="M37.4 46.68 C37.4,46.68 53.75,25.93 70.25,28.88 "
+ android:valueType="pathType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
</aapt:attr>
</objectAnimator>
<objectAnimator
- android:duration="100"
- android:propertyName="strokeAlpha"
- android:startOffset="3083"
- android:valueFrom="1"
- android:valueTo="0"
- android:valueType="floatType">
+ android:duration="667"
+ android:propertyName="pathData"
+ android:startOffset="333"
+ android:valueFrom="M37.4 46.68 C37.4,46.68 53.75,25.93 70.25,28.88 "
+ android:valueTo="M29.25 53.2 C29.25,53.2 40.54,27.94 70.07,31.11 "
+ android:valueType="pathType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="600"
+ android:propertyName="pathData"
+ android:startOffset="1000"
+ android:valueFrom="M29.25 53.2 C29.25,53.2 40.54,27.94 70.07,31.11 "
+ android:valueTo="M29.25 53.2 C29.25,53.2 40.54,27.94 70.07,31.11 "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1067"
+ android:propertyName="pathData"
+ android:startOffset="1600"
+ android:valueFrom="M29.25 53.2 C29.25,53.2 40.54,27.94 70.07,31.11 "
+ android:valueTo="M37.4 46.68 C37.4,46.68 53.75,25.93 70.25,28.88 "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.269,1 1.0,1.0" />
</aapt:attr>
</objectAnimator>
</set>
</aapt:attr>
</target>
- <target android:name="_R_G_L_0_G_D_2_P_0">
+ <target android:name="_R_G_L_0_G_N_4_T_1">
<aapt:attr name="android:animation">
<set android:ordering="together">
<objectAnimator
- android:duration="1833"
- android:propertyName="strokeAlpha"
- android:startOffset="1250"
- android:valueFrom="1"
- android:valueTo="1"
- android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
- </aapt:attr>
- </objectAnimator>
- <objectAnimator
- android:duration="100"
- android:propertyName="strokeAlpha"
- android:startOffset="3083"
- android:valueFrom="1"
- android:valueTo="0"
- android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
- </aapt:attr>
- </objectAnimator>
- </set>
- </aapt:attr>
- </target>
- <target android:name="_R_G_L_0_G_T_1">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator
- android:duration="83"
+ android:duration="333"
android:propertyName="translateX"
- android:startOffset="1250"
- android:valueFrom="309"
- android:valueTo="309"
+ android:startOffset="0"
+ android:valueFrom="443.275"
+ android:valueTo="443.275"
android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.285,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
</aapt:attr>
</objectAnimator>
<objectAnimator
- android:duration="1417"
+ android:duration="667"
android:propertyName="translateX"
- android:startOffset="1333"
- android:valueFrom="309"
- android:valueTo="251"
+ android:startOffset="333"
+ android:valueFrom="443.275"
+ android:valueTo="403.275"
android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.285,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="600"
+ android:propertyName="translateX"
+ android:startOffset="1000"
+ android:valueFrom="403.275"
+ android:valueTo="403.275"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1067"
+ android:propertyName="translateX"
+ android:startOffset="1600"
+ android:valueFrom="403.275"
+ android:valueTo="443.275"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.349,0 0.21,1 1.0,1.0" />
</aapt:attr>
</objectAnimator>
</set>
</aapt:attr>
</target>
- <target android:name="_R_G_L_0_G_T_1">
+ <target android:name="_R_G_L_0_G_N_4_T_1">
<aapt:attr name="android:animation">
<set android:ordering="together">
<objectAnimator
- android:duration="83"
- android:propertyName="rotation"
- android:startOffset="1250"
- android:valueFrom="11"
- android:valueTo="11"
+ android:duration="333"
+ android:propertyName="translateY"
+ android:startOffset="0"
+ android:valueFrom="741.789"
+ android:valueTo="741.789"
android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.277,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
</aapt:attr>
</objectAnimator>
<objectAnimator
- android:duration="1417"
+ android:duration="667"
+ android:propertyName="translateY"
+ android:startOffset="333"
+ android:valueFrom="741.789"
+ android:valueTo="741.789"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="600"
+ android:propertyName="translateY"
+ android:startOffset="1000"
+ android:valueFrom="741.789"
+ android:valueTo="741.789"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1067"
+ android:propertyName="translateY"
+ android:startOffset="1600"
+ android:valueFrom="741.789"
+ android:valueTo="741.789"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.349,0 0.21,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_N_4_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
android:propertyName="rotation"
- android:startOffset="1333"
- android:valueFrom="11"
+ android:startOffset="0"
+ android:valueFrom="22"
+ android:valueTo="22"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="667"
+ android:propertyName="rotation"
+ android:startOffset="333"
+ android:valueFrom="22"
android:valueTo="0"
android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.277,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="600"
+ android:propertyName="rotation"
+ android:startOffset="1000"
+ android:valueFrom="0"
+ android:valueTo="2"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.324,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1067"
+ android:propertyName="rotation"
+ android:startOffset="1600"
+ android:valueFrom="2"
+ android:valueTo="22"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.349,0 0.21,1 1.0,1.0" />
</aapt:attr>
</objectAnimator>
</set>
@@ -355,9 +886,9 @@
<aapt:attr name="android:animation">
<set android:ordering="together">
<objectAnimator
- android:duration="2183"
+ android:duration="2667"
android:propertyName="translateX"
- android:startOffset="1250"
+ android:startOffset="0"
android:valueFrom="0"
android:valueTo="1"
android:valueType="floatType" />
diff --git a/quickstep/res/drawable/home_gesture.xml b/quickstep/res/drawable/home_gesture.xml
index c253b7e..4de29d0 100644
--- a/quickstep/res/drawable/home_gesture.xml
+++ b/quickstep/res/drawable/home_gesture.xml
@@ -1,46 +1,935 @@
-<!--
- Copyright (C) 2020 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<!-- Dummy translating rectangle until we have a proper animation. -->
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:aapt="http://schemas.android.com/aapt" >
- <aapt:attr name="android:drawable">
- <vector
- android:height="64dp"
- android:width="64dp"
- android:viewportHeight="600"
- android:viewportWidth="600" >
- <group
- android:name="translationGroup"
- android:pivotX="300.0"
- android:pivotY="300.0"
- android:rotation="180.0" >
- <path
- android:fillColor="#eeeeee"
- android:pathData="M300,70 l 0,-70 70,0 0,140 -70,0 z" />
- </group>
- </vector>
- </aapt:attr>
-
- <target android:name="translationGroup">
- <aapt:attr name="android:animation">
- <objectAnimator
- android:duration="3000"
- android:propertyName="translateY"
- android:valueFrom="0"
- android:valueTo="-100" />
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="412dp"
+ android:height="890dp"
+ android:viewportWidth="412"
+ android:viewportHeight="890">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_3_G_T_1"
+ android:translateX="206"
+ android:translateY="880.283">
+ <group
+ android:name="_R_G_L_3_G"
+ android:translateX="-48.25"
+ android:translateY="-51.643">
+ <path
+ android:name="_R_G_L_3_G_D_0_P_0"
+ android:fillAlpha="0"
+ android:fillColor="#e8f0fe"
+ android:fillType="nonZero"
+ android:pathData=" M96.25 48.25 C96.25,74.76 74.76,96.25 48.25,96.25 C21.74,96.25 0.25,74.76 0.25,48.25 C0.25,21.74 21.74,0.25 48.25,0.25 C74.76,0.25 96.25,21.74 96.25,48.25c " />
+ </group>
+ </group>
+ <group
+ android:name="_R_G_L_2_G_N_4_N_3_T_1"
+ android:rotation="-60"
+ android:translateX="513.995"
+ android:translateY="909.041">
+ <group
+ android:name="_R_G_L_2_G_N_4_N_3_T_0"
+ android:translateX="-125.282"
+ android:translateY="-222.031">
+ <group
+ android:name="_R_G_L_2_G_N_4_T_0"
+ android:translateX="-27.223000000000006"
+ android:translateY="-19.78200000000001">
+ <group
+ android:name="_R_G_L_2_G"
+ android:pivotX="49.356"
+ android:pivotY="100.997"
+ android:rotation="-4"
+ android:translateX="-12.881"
+ android:translateY="-68.965">
+ <path
+ android:name="_R_G_L_2_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#d2e3fc"
+ android:fillType="nonZero"
+ android:pathData=" M29.51 3.44 C29.51,3.44 29.51,3.44 29.51,3.44 C44.17,0.25 58.86,8.71 63.48,22.99 C63.48,22.99 95.13,76.48 95.13,76.48 C98.47,94.41 92.03,116.16 52.12,115.41 C52.12,115.41 31.32,103.09 31.32,103.09 C23.59,101.22 5.39,82.22 3.78,59.83 C3.78,59.83 3.05,36.42 3.05,36.42 C5.71,17.29 15.16,6.55 29.51,3.44c " />
+ <path
+ android:name="_R_G_L_2_G_D_1_P_0"
+ android:pathData=" M58.16 28.36 C59.49,32.32 59.42,36.53 52.4,38.99 C52.4,38.99 46.29,40.77 30.67,46.05 C28.57,46.76 25.79,48.06 23.78,47.5 C22.12,47.04 20.49,45.56 19.68,42.39 C16.89,31.56 15,24.2 18.96,19.11 "
+ android:strokeWidth="6"
+ android:strokeAlpha="1"
+ android:strokeColor="#a0c2f9" />
+ </group>
+ </group>
+ </group>
+ </group>
+ <group
+ android:name="_R_G_L_1_G_N_3_T_1"
+ android:rotation="-60"
+ android:translateX="513.995"
+ android:translateY="909.041">
+ <group
+ android:name="_R_G_L_1_G_N_3_T_0"
+ android:translateX="-125.282"
+ android:translateY="-222.031">
+ <group
+ android:name="_R_G_L_1_G"
+ android:translateX="-27.223000000000006"
+ android:translateY="-19.78200000000001">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#d2e3fc"
+ android:fillType="nonZero"
+ android:pathData=" M62.05 -4.24 C62.05,-4.24 76.43,1.82 76.43,1.82 C91.76,16.39 83.61,36.19 86.21,52.29 C92.02,88.24 84.86,126.82 117.41,193.95 C87.71,242.97 78.03,245.45 48.32,294.5 C48.32,294.5 18.2,137.31 18.2,137.31 C19.12,123.7 17.54,107.98 13.81,87.39 C10.28,67.94 10.58,45.16 10,31.95 C10.04,30.08 8.74,12.88 15.64,8.72 C26.15,2.4 40.27,-9.2 62.05,-4.24c " />
+ <path
+ android:name="_R_G_L_1_G_D_1_P_0"
+ android:pathData=" M31.4 21.98 C31.4,21.98 41.87,1.7 68.18,3.97 "
+ android:strokeWidth="6"
+ android:strokeAlpha="1"
+ android:strokeColor="#a0c2f9" />
+ </group>
+ </group>
+ </group>
+ <group
+ android:name="_R_G_L_0_G_T_1"
+ android:rotation="-60"
+ android:translateX="513.995"
+ android:translateY="909.041">
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="-125.282"
+ android:translateY="-222.031">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#d2e3fc"
+ android:fillType="nonZero"
+ android:pathData=" M5.87 164.71 C0.43,267.95 56.57,389.47 139.31,416.77 C222.04,444.07 215.7,295.51 248.09,197.33 C280.49,99.14 111.3,154.92 55.02,40.63 C41.48,24.52 8.77,109.58 5.87,164.71c " />
+ </group>
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
</aapt:attr>
- </target>
+ <target android:name="_R_G_L_3_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="133"
+ android:propertyName="fillAlpha"
+ android:startOffset="333"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="fillAlpha"
+ android:startOffset="467"
+ android:valueFrom="1"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="300"
+ android:propertyName="fillAlpha"
+ android:startOffset="917"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_3_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="translateY"
+ android:startOffset="0"
+ android:valueFrom="880.283"
+ android:valueTo="880.283"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.247,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="883"
+ android:propertyName="translateY"
+ android:startOffset="333"
+ android:valueFrom="880.283"
+ android:valueTo="486.283"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.247,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M29.51 3.44 C29.51,3.44 29.51,3.44 29.51,3.44 C44.17,0.25 58.86,8.71 63.48,22.99 C63.48,22.99 95.13,76.48 95.13,76.48 C98.47,94.41 92.03,116.16 52.12,115.41 C52.12,115.41 31.32,103.09 31.32,103.09 C23.59,101.22 5.39,82.22 3.78,59.83 C3.78,59.83 3.05,36.42 3.05,36.42 C5.71,17.29 15.16,6.55 29.51,3.44c "
+ android:valueTo="M29.51 3.44 C29.51,3.44 29.51,3.44 29.51,3.44 C44.17,0.25 58.86,8.71 63.48,22.99 C63.48,22.99 95.13,76.48 95.13,76.48 C98.47,94.41 92.03,116.16 52.12,115.41 C52.12,115.41 31.32,103.09 31.32,103.09 C23.59,101.22 5.39,82.22 3.78,59.83 C3.78,59.83 3.05,36.42 3.05,36.42 C5.71,17.29 15.16,6.55 29.51,3.44c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="583"
+ android:propertyName="pathData"
+ android:startOffset="333"
+ android:valueFrom="M29.51 3.44 C29.51,3.44 29.51,3.44 29.51,3.44 C44.17,0.25 58.86,8.71 63.48,22.99 C63.48,22.99 95.13,76.48 95.13,76.48 C98.47,94.41 92.03,116.16 52.12,115.41 C52.12,115.41 31.32,103.09 31.32,103.09 C23.59,101.22 5.39,82.22 3.78,59.83 C3.78,59.83 3.05,36.42 3.05,36.42 C5.71,17.29 15.16,6.55 29.51,3.44c "
+ android:valueTo="M29.51 3.44 C29.51,3.44 29.51,3.44 29.51,3.44 C44.17,0.25 58.86,8.71 63.48,22.99 C63.48,22.99 81.12,76.53 81.12,76.53 C84.46,94.46 74.07,117.8 56.14,121.15 C56.14,121.15 51.31,122.05 51.31,122.05 C31.42,125.74 12.82,111.19 11.57,91 C11.57,91 6.61,34.54 6.61,34.54 C5.34,19.87 15.16,6.55 29.51,3.44c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="567"
+ android:propertyName="pathData"
+ android:startOffset="917"
+ android:valueFrom="M29.51 3.44 C29.51,3.44 29.51,3.44 29.51,3.44 C44.17,0.25 58.86,8.71 63.48,22.99 C63.48,22.99 81.12,76.53 81.12,76.53 C84.46,94.46 74.07,117.8 56.14,121.15 C56.14,121.15 51.31,122.05 51.31,122.05 C31.42,125.74 12.82,111.19 11.57,91 C11.57,91 6.61,34.54 6.61,34.54 C5.34,19.87 15.16,6.55 29.51,3.44c "
+ android:valueTo="M29.51 3.44 C29.51,3.44 29.51,3.44 29.51,3.44 C44.17,0.25 58.86,8.71 63.48,22.99 C63.48,22.99 81.12,76.53 81.12,76.53 C84.46,94.46 74.07,117.8 56.14,121.15 C56.14,121.15 51.31,122.05 51.31,122.05 C31.42,125.74 12.82,111.19 11.57,91 C11.57,91 6.61,34.54 6.61,34.54 C5.34,19.87 15.16,6.55 29.51,3.44c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1350"
+ android:propertyName="pathData"
+ android:startOffset="1483"
+ android:valueFrom="M29.51 3.44 C29.51,3.44 29.51,3.44 29.51,3.44 C44.17,0.25 58.86,8.71 63.48,22.99 C63.48,22.99 81.12,76.53 81.12,76.53 C84.46,94.46 74.07,117.8 56.14,121.15 C56.14,121.15 51.31,122.05 51.31,122.05 C31.42,125.74 12.82,111.19 11.57,91 C11.57,91 6.61,34.54 6.61,34.54 C5.34,19.87 15.16,6.55 29.51,3.44c "
+ android:valueTo="M29.51 3.44 C29.51,3.44 29.51,3.44 29.51,3.44 C44.17,0.25 58.86,8.71 63.48,22.99 C63.48,22.99 95.13,76.48 95.13,76.48 C98.47,94.41 92.03,116.16 52.12,115.41 C52.12,115.41 31.32,103.09 31.32,103.09 C23.59,101.22 5.39,82.22 3.78,59.83 C3.78,59.83 3.05,36.42 3.05,36.42 C5.71,17.29 15.16,6.55 29.51,3.44c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="-4"
+ android:valueTo="-4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="200"
+ android:propertyName="rotation"
+ android:startOffset="333"
+ android:valueFrom="-4"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="2300"
+ android:propertyName="rotation"
+ android:startOffset="533"
+ android:valueFrom="0"
+ android:valueTo="-4"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_N_4_N_3_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="513.995"
+ android:valueTo="513.995"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.711,0 0.772,0.166 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="translateX"
+ android:startOffset="333"
+ android:valueFrom="513.995"
+ android:valueTo="469.109"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.711,0 0.772,0.166 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="433"
+ android:propertyName="translateX"
+ android:startOffset="483"
+ android:valueFrom="469.109"
+ android:valueTo="343.995"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.094,0.355 0.269,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="567"
+ android:propertyName="translateX"
+ android:startOffset="917"
+ android:valueFrom="343.995"
+ android:valueTo="367.995"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.307,0 0.475,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1350"
+ android:propertyName="translateX"
+ android:startOffset="1483"
+ android:valueFrom="367.995"
+ android:valueTo="513.995"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.513,0 0.219,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_N_4_N_3_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="translateY"
+ android:startOffset="0"
+ android:valueFrom="909.041"
+ android:valueTo="909.041"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="583"
+ android:propertyName="translateY"
+ android:startOffset="333"
+ android:valueFrom="909.041"
+ android:valueTo="859.041"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="567"
+ android:propertyName="translateY"
+ android:startOffset="917"
+ android:valueFrom="859.041"
+ android:valueTo="883.041"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.307,0 0.475,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1350"
+ android:propertyName="translateY"
+ android:startOffset="1483"
+ android:valueFrom="883.041"
+ android:valueTo="909.041"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.513,0 0.219,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_N_4_N_3_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="-60"
+ android:valueTo="-60"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="583"
+ android:propertyName="rotation"
+ android:startOffset="333"
+ android:valueFrom="-60"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="567"
+ android:propertyName="rotation"
+ android:startOffset="917"
+ android:valueFrom="0"
+ android:valueTo="-2"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.307,0 0.545,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1350"
+ android:propertyName="rotation"
+ android:startOffset="1483"
+ android:valueFrom="-2"
+ android:valueTo="-60"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.513,0 0.219,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M62.05 -4.24 C62.05,-4.24 76.43,1.82 76.43,1.82 C91.76,16.39 83.61,36.19 86.21,52.29 C92.02,88.24 84.86,126.82 117.41,193.95 C87.71,242.97 78.03,245.45 48.32,294.5 C48.32,294.5 18.2,137.31 18.2,137.31 C19.12,123.7 17.54,107.98 13.81,87.39 C10.28,67.94 10.58,45.16 10,31.95 C10.04,30.08 8.74,12.88 15.64,8.72 C26.15,2.4 40.27,-9.2 62.05,-4.24c "
+ android:valueTo="M62.05 -4.24 C62.05,-4.24 76.43,1.82 76.43,1.82 C91.76,16.39 83.61,36.19 86.21,52.29 C92.02,88.24 84.86,126.82 117.41,193.95 C87.71,242.97 78.03,245.45 48.32,294.5 C48.32,294.5 18.2,137.31 18.2,137.31 C19.12,123.7 17.54,107.98 13.81,87.39 C10.28,67.94 10.58,45.16 10,31.95 C10.04,30.08 8.74,12.88 15.64,8.72 C26.15,2.4 40.27,-9.2 62.05,-4.24c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="583"
+ android:propertyName="pathData"
+ android:startOffset="333"
+ android:valueFrom="M62.05 -4.24 C62.05,-4.24 76.43,1.82 76.43,1.82 C91.76,16.39 83.61,36.19 86.21,52.29 C92.02,88.24 84.86,126.82 117.41,193.95 C87.71,242.97 78.03,245.45 48.32,294.5 C48.32,294.5 18.2,137.31 18.2,137.31 C19.12,123.7 17.54,107.98 13.81,87.39 C10.28,67.94 10.58,45.16 10,31.95 C10.04,30.08 8.74,12.88 15.64,8.72 C26.15,2.4 40.27,-9.2 62.05,-4.24c "
+ android:valueTo="M51.44 5.02 C51.44,5.02 68.24,7.56 68.24,7.56 C73.26,21.67 72.7,36.77 79.13,51.76 C94.55,87.66 106.15,89.19 144.51,111.49 C114.82,160.51 78.03,245.45 48.32,294.5 C48.32,294.5 18.2,137.31 18.2,137.31 C19.12,123.7 19.02,105.73 15.29,85.14 C11.76,65.68 5.52,42.3 0.25,30.23 C0.29,28.36 0.58,17.81 15.64,8.72 C26.15,2.39 40.15,0.25 51.44,5.02c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="567"
+ android:propertyName="pathData"
+ android:startOffset="917"
+ android:valueFrom="M51.44 5.02 C51.44,5.02 68.24,7.56 68.24,7.56 C73.26,21.67 72.7,36.77 79.13,51.76 C94.55,87.66 106.15,89.19 144.51,111.49 C114.82,160.51 78.03,245.45 48.32,294.5 C48.32,294.5 18.2,137.31 18.2,137.31 C19.12,123.7 19.02,105.73 15.29,85.14 C11.76,65.68 5.52,42.3 0.25,30.23 C0.29,28.36 0.58,17.81 15.64,8.72 C26.15,2.39 40.15,0.25 51.44,5.02c "
+ android:valueTo="M51.44 5.02 C51.44,5.02 68.24,7.56 68.24,7.56 C73.26,21.67 72.7,36.77 79.13,51.76 C94.55,87.66 106.15,89.19 144.51,111.49 C114.82,160.51 78.03,245.45 48.32,294.5 C48.32,294.5 18.2,137.31 18.2,137.31 C19.12,123.7 19.02,105.73 15.29,85.14 C11.76,65.68 5.52,42.3 0.25,30.23 C0.29,28.36 0.58,17.81 15.64,8.72 C26.15,2.39 40.15,0.25 51.44,5.02c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1350"
+ android:propertyName="pathData"
+ android:startOffset="1483"
+ android:valueFrom="M51.44 5.02 C51.44,5.02 68.24,7.56 68.24,7.56 C73.26,21.67 72.7,36.77 79.13,51.76 C94.55,87.66 106.15,89.19 144.51,111.49 C114.82,160.51 78.03,245.45 48.32,294.5 C48.32,294.5 18.2,137.31 18.2,137.31 C19.12,123.7 19.02,105.73 15.29,85.14 C11.76,65.68 5.52,42.3 0.25,30.23 C0.29,28.36 0.58,17.81 15.64,8.72 C26.15,2.39 40.15,0.25 51.44,5.02c "
+ android:valueTo="M62.05 -4.24 C62.05,-4.24 76.43,1.82 76.43,1.82 C91.76,16.39 83.61,36.19 86.21,52.29 C92.02,88.24 84.86,126.82 117.41,193.95 C87.71,242.97 78.03,245.45 48.32,294.5 C48.32,294.5 18.2,137.31 18.2,137.31 C19.12,123.7 17.54,107.98 13.81,87.39 C10.28,67.94 10.58,45.16 10,31.95 C10.04,30.08 8.74,12.88 15.64,8.72 C26.15,2.4 40.27,-9.2 62.05,-4.24c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_D_1_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M31.4 21.98 C31.4,21.98 41.87,1.7 68.18,3.97 "
+ android:valueTo="M31.4 21.98 C31.4,21.98 41.87,1.7 68.18,3.97 "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="583"
+ android:propertyName="pathData"
+ android:startOffset="333"
+ android:valueFrom="M31.4 21.98 C31.4,21.98 41.87,1.7 68.18,3.97 "
+ android:valueTo="M17.9 26.98 C17.9,26.98 29.87,13.7 56.18,15.97 "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="567"
+ android:propertyName="pathData"
+ android:startOffset="917"
+ android:valueFrom="M17.9 26.98 C17.9,26.98 29.87,13.7 56.18,15.97 "
+ android:valueTo="M17.9 26.98 C17.9,26.98 29.87,13.7 56.18,15.97 "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1350"
+ android:propertyName="pathData"
+ android:startOffset="1483"
+ android:valueFrom="M17.9 26.98 C17.9,26.98 29.87,13.7 56.18,15.97 "
+ android:valueTo="M31.4 21.98 C31.4,21.98 41.87,1.7 68.18,3.97 "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_N_3_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="513.995"
+ android:valueTo="513.995"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.711,0 0.772,0.166 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="translateX"
+ android:startOffset="333"
+ android:valueFrom="513.995"
+ android:valueTo="469.109"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.711,0 0.772,0.166 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="433"
+ android:propertyName="translateX"
+ android:startOffset="483"
+ android:valueFrom="469.109"
+ android:valueTo="343.995"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.094,0.355 0.269,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="567"
+ android:propertyName="translateX"
+ android:startOffset="917"
+ android:valueFrom="343.995"
+ android:valueTo="367.995"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.307,0 0.475,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1350"
+ android:propertyName="translateX"
+ android:startOffset="1483"
+ android:valueFrom="367.995"
+ android:valueTo="513.995"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.513,0 0.219,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_N_3_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="translateY"
+ android:startOffset="0"
+ android:valueFrom="909.041"
+ android:valueTo="909.041"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="583"
+ android:propertyName="translateY"
+ android:startOffset="333"
+ android:valueFrom="909.041"
+ android:valueTo="859.041"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="567"
+ android:propertyName="translateY"
+ android:startOffset="917"
+ android:valueFrom="859.041"
+ android:valueTo="883.041"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.307,0 0.475,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1350"
+ android:propertyName="translateY"
+ android:startOffset="1483"
+ android:valueFrom="883.041"
+ android:valueTo="909.041"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.513,0 0.219,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_N_3_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="-60"
+ android:valueTo="-60"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="583"
+ android:propertyName="rotation"
+ android:startOffset="333"
+ android:valueFrom="-60"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="567"
+ android:propertyName="rotation"
+ android:startOffset="917"
+ android:valueFrom="0"
+ android:valueTo="-2"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.307,0 0.545,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1350"
+ android:propertyName="rotation"
+ android:startOffset="1483"
+ android:valueFrom="-2"
+ android:valueTo="-60"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.513,0 0.219,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M5.87 164.71 C0.43,267.95 56.57,389.47 139.31,416.77 C222.04,444.07 215.7,295.51 248.09,197.33 C280.49,99.14 111.3,154.92 55.02,40.63 C41.48,24.52 8.77,109.58 5.87,164.71c "
+ android:valueTo="M5.87 164.71 C0.43,267.95 56.57,389.47 139.31,416.77 C222.04,444.07 215.7,295.51 248.09,197.33 C280.49,99.14 111.3,154.92 55.02,40.63 C41.48,24.52 8.77,109.58 5.87,164.71c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="pathData"
+ android:startOffset="333"
+ android:valueFrom="M5.87 164.71 C0.43,267.95 56.57,389.47 139.31,416.77 C222.04,444.07 215.7,295.51 248.09,197.33 C280.49,99.14 111.3,154.92 55.02,40.63 C41.48,24.52 8.77,109.58 5.87,164.71c "
+ android:valueTo="M-9.23 115.79 C-30.45,216.96 -36.73,359.16 139.26,416.71 C222.07,443.78 220.51,278.25 244.3,175.03 C268.14,75.53 116.98,150.23 54.13,40.23 C40.58,24.12 5.18,47.09 -9.23,115.79c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="433"
+ android:propertyName="pathData"
+ android:startOffset="483"
+ android:valueFrom="M-9.23 115.79 C-30.45,216.96 -36.73,359.16 139.26,416.71 C222.07,443.78 220.51,278.25 244.3,175.03 C268.14,75.53 116.98,150.23 54.13,40.23 C40.58,24.12 5.18,47.09 -9.23,115.79c "
+ android:valueTo="M-8.56 118.7 C-9.54,222.08 56.39,389.22 139.13,416.51 C221.86,443.81 234.66,227.56 233.16,109.56 C231.84,6.17 133.65,136.44 51.49,39.06 C37.94,22.95 -7.96,56.24 -8.56,118.7c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="917"
+ android:propertyName="pathData"
+ android:startOffset="917"
+ android:valueFrom="M-8.56 118.7 C-9.54,222.08 56.39,389.22 139.13,416.51 C221.86,443.81 234.66,227.56 233.16,109.56 C231.84,6.17 133.65,136.44 51.49,39.06 C37.94,22.95 -7.96,56.24 -8.56,118.7c "
+ android:valueTo="M-8.56 118.7 C-9.54,222.08 56.39,389.22 139.13,416.51 C221.86,443.81 238.66,196.56 237.16,78.56 C235.84,-24.83 133.65,136.44 51.49,39.06 C37.94,22.95 -7.96,56.24 -8.56,118.7c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.212,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1000"
+ android:propertyName="pathData"
+ android:startOffset="1833"
+ android:valueFrom="M-8.56 118.7 C-9.54,222.08 56.39,389.22 139.13,416.51 C221.86,443.81 238.66,196.56 237.16,78.56 C235.84,-24.83 133.65,136.44 51.49,39.06 C37.94,22.95 -7.96,56.24 -8.56,118.7c "
+ android:valueTo="M5.87 164.71 C0.43,267.95 56.57,389.47 139.31,416.77 C222.04,444.07 215.7,295.51 248.09,197.33 C280.49,99.14 111.3,154.92 55.02,40.63 C41.48,24.52 8.77,109.58 5.87,164.71c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="513.995"
+ android:valueTo="513.995"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.711,0 0.772,0.166 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="translateX"
+ android:startOffset="333"
+ android:valueFrom="513.995"
+ android:valueTo="469.109"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.711,0 0.772,0.166 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="433"
+ android:propertyName="translateX"
+ android:startOffset="483"
+ android:valueFrom="469.109"
+ android:valueTo="343.995"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.094,0.355 0.269,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="567"
+ android:propertyName="translateX"
+ android:startOffset="917"
+ android:valueFrom="343.995"
+ android:valueTo="367.995"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.307,0 0.475,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1350"
+ android:propertyName="translateX"
+ android:startOffset="1483"
+ android:valueFrom="367.995"
+ android:valueTo="513.995"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.513,0 0.219,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="translateY"
+ android:startOffset="0"
+ android:valueFrom="909.041"
+ android:valueTo="909.041"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="583"
+ android:propertyName="translateY"
+ android:startOffset="333"
+ android:valueFrom="909.041"
+ android:valueTo="859.041"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="567"
+ android:propertyName="translateY"
+ android:startOffset="917"
+ android:valueFrom="859.041"
+ android:valueTo="883.041"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.307,0 0.475,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1350"
+ android:propertyName="translateY"
+ android:startOffset="1483"
+ android:valueFrom="883.041"
+ android:valueTo="909.041"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.513,0 0.219,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="-60"
+ android:valueTo="-60"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="583"
+ android:propertyName="rotation"
+ android:startOffset="333"
+ android:valueFrom="-60"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="567"
+ android:propertyName="rotation"
+ android:startOffset="917"
+ android:valueFrom="0"
+ android:valueTo="-2"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.307,0 0.545,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1350"
+ android:propertyName="rotation"
+ android:startOffset="1483"
+ android:valueFrom="-2"
+ android:valueTo="-60"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.513,0 0.219,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="2850"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
</animated-vector>
\ No newline at end of file
diff --git a/quickstep/res/drawable/overview_gesture.xml b/quickstep/res/drawable/overview_gesture.xml
new file mode 100644
index 0000000..68c48d4
--- /dev/null
+++ b/quickstep/res/drawable/overview_gesture.xml
@@ -0,0 +1,1173 @@
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="412dp"
+ android:height="890dp"
+ android:viewportWidth="412"
+ android:viewportHeight="890">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_3_G_N_4_N_3_N_2_T_0"
+ android:translateX="297.398"
+ android:translateY="721.169">
+ <group
+ android:name="_R_G_L_3_G_N_4_N_3_T_1"
+ android:rotation="-45"
+ android:translateX="110.176"
+ android:translateY="177.218">
+ <group
+ android:name="_R_G_L_3_G_N_4_N_3_T_0"
+ android:translateX="-132.239"
+ android:translateY="-133.055">
+ <group
+ android:name="_R_G_L_3_G_N_4_T_0"
+ android:pivotX="71.634"
+ android:pivotY="92.684"
+ android:rotation="-2"
+ android:translateX="-36.948"
+ android:translateY="-58.704">
+ <group
+ android:name="_R_G_L_3_G"
+ android:pivotX="48.25"
+ android:pivotY="48.25"
+ android:rotation="-47"
+ android:translateX="-20.55"
+ android:translateY="-21.306">
+ <path
+ android:name="_R_G_L_3_G_D_0_P_0"
+ android:fillAlpha="0"
+ android:fillColor="#e8f0fe"
+ android:fillType="nonZero"
+ android:pathData=" M96.25 48.25 C96.25,74.76 74.76,96.25 48.25,96.25 C21.74,96.25 0.25,74.76 0.25,48.25 C0.25,21.74 21.74,0.25 48.25,0.25 C74.76,0.25 96.25,21.74 96.25,48.25c " />
+ </group>
+ </group>
+ </group>
+ </group>
+ </group>
+ <group
+ android:name="_R_G_L_2_G"
+ android:pivotX="48.25"
+ android:pivotY="48.25"
+ android:rotation="-47"
+ android:translateX="152.837"
+ android:translateY="698.322">
+ <path
+ android:name="_R_G_L_2_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#e8f0fe"
+ android:fillType="nonZero"
+ android:pathData=" M96.25 48.25 C96.25,74.76 74.76,96.25 48.25,96.25 C21.74,96.25 0.25,74.76 0.25,48.25 C0.25,21.74 21.74,0.25 48.25,0.25 C74.76,0.25 96.25,21.74 96.25,48.25c " />
+ </group>
+ <group
+ android:name="_R_G_L_1_G_N_3_N_2_T_0"
+ android:translateX="297.398"
+ android:translateY="721.169">
+ <group
+ android:name="_R_G_L_1_G_N_3_T_1"
+ android:rotation="-45"
+ android:translateX="110.176"
+ android:translateY="177.218">
+ <group
+ android:name="_R_G_L_1_G_N_3_T_0"
+ android:translateX="-132.239"
+ android:translateY="-133.055">
+ <group
+ android:name="_R_G_L_1_G"
+ android:pivotX="71.634"
+ android:pivotY="92.684"
+ android:rotation="-2"
+ android:translateX="-36.948"
+ android:translateY="-58.704">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#d2e3fc"
+ android:fillType="nonZero"
+ android:pathData=" M20.63 8.95 C20.63,8.95 20.63,8.95 20.63,8.95 C32.8,0.25 49.72,2.9 59.23,14.69 C59.23,14.69 96.98,58.55 96.98,58.55 C113.17,83.98 104.58,100.89 89.25,111.3 C89.25,111.3 85.05,113.83 85.05,113.83 C67.95,125.12 45.66,118.31 36.77,99.32 C36.77,99.32 11.14,47.2 11.14,47.2 C4.45,34.1 8.44,17.28 20.63,8.95c " />
+ <path
+ android:name="_R_G_L_1_G_D_1_P_0"
+ android:pathData=" M50.61 24.81 C53.83,30.61 58.53,37.85 51.26,44.87 C51.26,44.87 38.64,50.25 34.66,52.09 C32.65,53.03 31.97,54.36 29.89,54.38 C28.17,54.4 26.19,53.43 24.53,50.61 C18.85,40.97 15,34.43 17.4,28.44 "
+ android:strokeWidth="6"
+ android:strokeAlpha="1"
+ android:strokeColor="#a0c2f9"/>
+ </group>
+ </group>
+ </group>
+ </group>
+ <group
+ android:name="_R_G_L_0_G_N_2_T_0"
+ android:translateX="297.398"
+ android:translateY="721.169">
+ <group
+ android:name="_R_G_L_0_G_T_1"
+ android:rotation="-45"
+ android:translateX="110.176"
+ android:translateY="177.218">
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="-132.239"
+ android:translateY="-133.055">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#d2e3fc"
+ android:fillType="nonZero"
+ android:pathData=" M42.21 4.34 C42.21,4.34 58.68,0.25 58.68,0.25 C68.53,11.64 74.12,25.6 85.21,38.39 C115.84,72.27 136.7,91.72 185.58,117.71 C221.01,256.74 312.66,319.67 166.82,292.86 C166.82,292.86 61.19,143.45 61.19,143.45 C57.04,130.17 50.08,112.95 39.06,94.86 C28.46,77.49 14.05,57.75 4.69,48.2 C4.2,46.35 0.25,36.08 10.96,21.83 C17.93,11.59 30.17,4.01 42.21,4.34c " />
+ <path
+ android:name="_R_G_L_0_G_D_1_P_0"
+ android:pathData=" M26.74 49.32 C26.74,49.32 34.17,35.86 51.22,27.28 "
+ android:strokeWidth="6"
+ android:strokeAlpha="1"
+ android:strokeColor="#a0c2f9"/>
+ </group>
+ </group>
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_3_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="217"
+ android:propertyName="fillAlpha"
+ android:startOffset="333"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_3_G_N_4_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="-2"
+ android:valueTo="-2"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="833"
+ android:propertyName="rotation"
+ android:startOffset="333"
+ android:valueFrom="-2"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1100"
+ android:propertyName="rotation"
+ android:startOffset="1167"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1233"
+ android:propertyName="rotation"
+ android:startOffset="2267"
+ android:valueFrom="0"
+ android:valueTo="-2"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.489,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_3_G_N_4_N_3_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="110.176"
+ android:valueTo="110.176"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.658,0 0.401,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="833"
+ android:propertyName="translateX"
+ android:startOffset="333"
+ android:valueFrom="110.176"
+ android:valueTo="45.176"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.658,0 0.401,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="933"
+ android:propertyName="translateX"
+ android:startOffset="1167"
+ android:valueFrom="45.176"
+ android:valueTo="45.176"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="translateX"
+ android:startOffset="2100"
+ android:valueFrom="45.176"
+ android:valueTo="45.176"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1233"
+ android:propertyName="translateX"
+ android:startOffset="2267"
+ android:valueFrom="45.176"
+ android:valueTo="110.176"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.286,0 0.489,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_3_G_N_4_N_3_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="translateY"
+ android:startOffset="0"
+ android:valueFrom="177.218"
+ android:valueTo="177.218"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.658,0 0.401,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="833"
+ android:propertyName="translateY"
+ android:startOffset="333"
+ android:valueFrom="177.218"
+ android:valueTo="190.218"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.658,0 0.401,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="600"
+ android:propertyName="translateY"
+ android:startOffset="1167"
+ android:valueFrom="190.218"
+ android:valueTo="190.218"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.401,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="translateY"
+ android:startOffset="1767"
+ android:valueFrom="190.218"
+ android:valueTo="201.218"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.539,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="translateY"
+ android:startOffset="2100"
+ android:valueFrom="201.218"
+ android:valueTo="201.218"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.539,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1233"
+ android:propertyName="translateY"
+ android:startOffset="2267"
+ android:valueFrom="201.218"
+ android:valueTo="177.218"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.286,0 0.489,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_3_G_N_4_N_3_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="-45"
+ android:valueTo="-45"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.618,0 0.348,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="833"
+ android:propertyName="rotation"
+ android:startOffset="333"
+ android:valueFrom="-45"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.618,0 0.348,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="600"
+ android:propertyName="rotation"
+ android:startOffset="1167"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.348,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="rotation"
+ android:startOffset="1767"
+ android:valueFrom="0"
+ android:valueTo="-1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.539,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="rotation"
+ android:startOffset="2100"
+ android:valueFrom="-1"
+ android:valueTo="-1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.539,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1233"
+ android:propertyName="rotation"
+ android:startOffset="2267"
+ android:valueFrom="-1"
+ android:valueTo="-45"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.286,0 0.489,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_3_G_N_4_N_3_N_2_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="0"
+ android:propertyName="scaleY"
+ android:startOffset="1167"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="1767"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="fillAlpha"
+ android:startOffset="1767"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="0"
+ android:propertyName="scaleX"
+ android:startOffset="1167"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M20.63 8.95 C20.63,8.95 20.63,8.95 20.63,8.95 C32.8,0.25 49.72,2.9 59.23,14.69 C59.23,14.69 96.98,58.55 96.98,58.55 C113.17,83.98 104.58,100.89 89.25,111.3 C89.25,111.3 85.05,113.83 85.05,113.83 C67.95,125.12 45.66,118.31 36.77,99.32 C36.77,99.32 11.14,47.2 11.14,47.2 C4.45,34.1 8.44,17.28 20.63,8.95c "
+ android:valueTo="M20.63 8.95 C20.63,8.95 20.63,8.95 20.63,8.95 C32.8,0.25 49.72,2.9 59.23,14.69 C59.23,14.69 96.98,58.55 96.98,58.55 C113.17,83.98 104.58,100.89 89.25,111.3 C89.25,111.3 85.05,113.83 85.05,113.83 C67.95,125.12 45.66,118.31 36.77,99.32 C36.77,99.32 11.14,47.2 11.14,47.2 C4.45,34.1 8.44,17.28 20.63,8.95c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="833"
+ android:propertyName="pathData"
+ android:startOffset="333"
+ android:valueFrom="M20.63 8.95 C20.63,8.95 20.63,8.95 20.63,8.95 C32.8,0.25 49.72,2.9 59.23,14.69 C59.23,14.69 96.98,58.55 96.98,58.55 C113.17,83.98 104.58,100.89 89.25,111.3 C89.25,111.3 85.05,113.83 85.05,113.83 C67.95,125.12 45.66,118.31 36.77,99.32 C36.77,99.32 11.14,47.2 11.14,47.2 C4.45,34.1 8.44,17.28 20.63,8.95c "
+ android:valueTo="M20.63 8.95 C20.63,8.95 20.63,8.95 20.63,8.95 C32.8,0.25 49.72,2.9 59.23,14.69 C59.23,14.69 94.24,55.98 94.24,55.98 C109.11,75.87 104.58,100.89 89.25,111.3 C89.25,111.3 85.05,113.83 85.05,113.83 C67.95,125.12 45.66,118.31 36.77,99.32 C36.77,99.32 11.14,47.2 11.14,47.2 C4.45,34.1 8.44,17.28 20.63,8.95c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1100"
+ android:propertyName="pathData"
+ android:startOffset="1167"
+ android:valueFrom="M20.63 8.95 C20.63,8.95 20.63,8.95 20.63,8.95 C32.8,0.25 49.72,2.9 59.23,14.69 C59.23,14.69 94.24,55.98 94.24,55.98 C109.11,75.87 104.58,100.89 89.25,111.3 C89.25,111.3 85.05,113.83 85.05,113.83 C67.95,125.12 45.66,118.31 36.77,99.32 C36.77,99.32 11.14,47.2 11.14,47.2 C4.45,34.1 8.44,17.28 20.63,8.95c "
+ android:valueTo="M20.63 8.95 C20.63,8.95 20.63,8.95 20.63,8.95 C32.8,0.25 49.72,2.9 59.23,14.69 C59.23,14.69 94.24,55.98 94.24,55.98 C109.11,75.87 104.58,100.89 89.25,111.3 C89.25,111.3 85.05,113.83 85.05,113.83 C67.95,125.12 45.66,118.31 36.77,99.32 C36.77,99.32 11.14,47.2 11.14,47.2 C4.45,34.1 8.44,17.28 20.63,8.95c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1233"
+ android:propertyName="pathData"
+ android:startOffset="2267"
+ android:valueFrom="M20.63 8.95 C20.63,8.95 20.63,8.95 20.63,8.95 C32.8,0.25 49.72,2.9 59.23,14.69 C59.23,14.69 94.24,55.98 94.24,55.98 C109.11,75.87 104.58,100.89 89.25,111.3 C89.25,111.3 85.05,113.83 85.05,113.83 C67.95,125.12 45.66,118.31 36.77,99.32 C36.77,99.32 11.14,47.2 11.14,47.2 C4.45,34.1 8.44,17.28 20.63,8.95c "
+ android:valueTo="M20.63 8.95 C20.63,8.95 20.63,8.95 20.63,8.95 C32.8,0.25 49.72,2.9 59.23,14.69 C59.23,14.69 96.98,58.55 96.98,58.55 C113.17,83.98 104.58,100.89 89.25,111.3 C89.25,111.3 85.05,113.83 85.05,113.83 C67.95,125.12 45.66,118.31 36.77,99.32 C36.77,99.32 11.14,47.2 11.14,47.2 C4.45,34.1 8.44,17.28 20.63,8.95c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_D_1_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M50.61 24.81 C53.83,30.61 58.53,37.85 51.26,44.87 C51.26,44.87 38.64,50.25 34.66,52.09 C32.65,53.03 31.97,54.36 29.89,54.38 C28.17,54.4 26.19,53.43 24.53,50.61 C18.85,40.97 15,34.43 17.4,28.44 "
+ android:valueTo="M50.61 24.81 C53.83,30.61 58.53,37.85 51.26,44.87 C51.26,44.87 38.64,50.25 34.66,52.09 C32.65,53.03 31.97,54.36 29.89,54.38 C28.17,54.4 26.19,53.43 24.53,50.61 C18.85,40.97 15,34.43 17.4,28.44 "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="833"
+ android:propertyName="pathData"
+ android:startOffset="333"
+ android:valueFrom="M50.61 24.81 C53.83,30.61 58.53,37.85 51.26,44.87 C51.26,44.87 38.64,50.25 34.66,52.09 C32.65,53.03 31.97,54.36 29.89,54.38 C28.17,54.4 26.19,53.43 24.53,50.61 C18.85,40.97 15,34.43 17.4,28.44 "
+ android:valueTo="M57.62 26.47 C60,29.91 61.1,33.98 55.03,38.28 C55.03,38.28 49.65,41.69 36.11,51.08 C34.29,52.35 31.97,54.36 29.89,54.38 C28.17,54.4 26.19,53.43 24.53,50.61 C18.85,40.97 15,34.43 17.4,28.44 "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1100"
+ android:propertyName="pathData"
+ android:startOffset="1167"
+ android:valueFrom="M57.62 26.47 C60,29.91 61.1,33.98 55.03,38.28 C55.03,38.28 49.65,41.69 36.11,51.08 C34.29,52.35 31.97,54.36 29.89,54.38 C28.17,54.4 26.19,53.43 24.53,50.61 C18.85,40.97 15,34.43 17.4,28.44 "
+ android:valueTo="M57.62 26.47 C60,29.91 61.1,33.98 55.03,38.28 C55.03,38.28 49.65,41.69 36.11,51.08 C34.29,52.35 31.97,54.36 29.89,54.38 C28.17,54.4 26.19,53.43 24.53,50.61 C18.85,40.97 15,34.43 17.4,28.44 "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1233"
+ android:propertyName="pathData"
+ android:startOffset="2267"
+ android:valueFrom="M57.62 26.47 C60,29.91 61.1,33.98 55.03,38.28 C55.03,38.28 49.65,41.69 36.11,51.08 C34.29,52.35 31.97,54.36 29.89,54.38 C28.17,54.4 26.19,53.43 24.53,50.61 C18.85,40.97 15,34.43 17.4,28.44 "
+ android:valueTo="M50.61 24.81 C53.83,30.61 58.53,37.85 51.26,44.87 C51.26,44.87 38.64,50.25 34.66,52.09 C32.65,53.03 31.97,54.36 29.89,54.38 C28.17,54.4 26.19,53.43 24.53,50.61 C18.85,40.97 15,34.43 17.4,28.44 "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="-2"
+ android:valueTo="-2"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="833"
+ android:propertyName="rotation"
+ android:startOffset="333"
+ android:valueFrom="-2"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1100"
+ android:propertyName="rotation"
+ android:startOffset="1167"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1233"
+ android:propertyName="rotation"
+ android:startOffset="2267"
+ android:valueFrom="0"
+ android:valueTo="-2"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.489,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_N_3_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="110.176"
+ android:valueTo="110.176"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.658,0 0.401,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="833"
+ android:propertyName="translateX"
+ android:startOffset="333"
+ android:valueFrom="110.176"
+ android:valueTo="45.176"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.658,0 0.401,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="933"
+ android:propertyName="translateX"
+ android:startOffset="1167"
+ android:valueFrom="45.176"
+ android:valueTo="45.176"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="translateX"
+ android:startOffset="2100"
+ android:valueFrom="45.176"
+ android:valueTo="45.176"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1233"
+ android:propertyName="translateX"
+ android:startOffset="2267"
+ android:valueFrom="45.176"
+ android:valueTo="110.176"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.286,0 0.489,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_N_3_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="translateY"
+ android:startOffset="0"
+ android:valueFrom="177.218"
+ android:valueTo="177.218"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.658,0 0.401,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="833"
+ android:propertyName="translateY"
+ android:startOffset="333"
+ android:valueFrom="177.218"
+ android:valueTo="190.218"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.658,0 0.401,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="600"
+ android:propertyName="translateY"
+ android:startOffset="1167"
+ android:valueFrom="190.218"
+ android:valueTo="190.218"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.401,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="translateY"
+ android:startOffset="1767"
+ android:valueFrom="190.218"
+ android:valueTo="201.218"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.539,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="translateY"
+ android:startOffset="2100"
+ android:valueFrom="201.218"
+ android:valueTo="201.218"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.539,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1233"
+ android:propertyName="translateY"
+ android:startOffset="2267"
+ android:valueFrom="201.218"
+ android:valueTo="177.218"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.286,0 0.489,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_N_3_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="-45"
+ android:valueTo="-45"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.618,0 0.348,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="833"
+ android:propertyName="rotation"
+ android:startOffset="333"
+ android:valueFrom="-45"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.618,0 0.348,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="600"
+ android:propertyName="rotation"
+ android:startOffset="1167"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.348,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="rotation"
+ android:startOffset="1767"
+ android:valueFrom="0"
+ android:valueTo="-1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.539,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="rotation"
+ android:startOffset="2100"
+ android:valueFrom="-1"
+ android:valueTo="-1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.539,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1233"
+ android:propertyName="rotation"
+ android:startOffset="2267"
+ android:valueFrom="-1"
+ android:valueTo="-45"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.286,0 0.489,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M42.21 4.34 C42.21,4.34 58.68,0.25 58.68,0.25 C68.53,11.64 74.12,25.6 85.21,38.39 C115.84,72.27 136.7,91.72 185.58,117.71 C221.01,256.74 312.66,319.67 166.82,292.86 C166.82,292.86 61.19,143.45 61.19,143.45 C57.04,130.17 50.08,112.95 39.06,94.86 C28.46,77.49 14.05,57.75 4.69,48.2 C4.2,46.35 0.25,36.08 10.96,21.83 C17.93,11.59 30.17,4.01 42.21,4.34c "
+ android:valueTo="M42.21 4.34 C42.21,4.34 58.68,0.25 58.68,0.25 C68.53,11.64 74.12,25.6 85.21,38.39 C115.84,72.27 136.7,91.72 185.58,117.71 C221.01,256.74 312.66,319.67 166.82,292.86 C166.82,292.86 61.19,143.45 61.19,143.45 C57.04,130.17 50.08,112.95 39.06,94.86 C28.46,77.49 14.05,57.75 4.69,48.2 C4.2,46.35 0.25,36.08 10.96,21.83 C17.93,11.59 30.17,4.01 42.21,4.34c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.425,0 0.463,0.469 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="700"
+ android:propertyName="pathData"
+ android:startOffset="333"
+ android:valueFrom="M42.21 4.34 C42.21,4.34 58.68,0.25 58.68,0.25 C68.53,11.64 74.12,25.6 85.21,38.39 C115.84,72.27 136.7,91.72 185.58,117.71 C221.01,256.74 312.66,319.67 166.82,292.86 C166.82,292.86 61.19,143.45 61.19,143.45 C57.04,130.17 50.08,112.95 39.06,94.86 C28.46,77.49 14.05,57.75 4.69,48.2 C4.2,46.35 0.25,36.08 10.96,21.83 C17.93,11.59 30.17,4.01 42.21,4.34c "
+ android:valueTo="M42.21 4.34 C42.21,4.34 58.68,0.25 58.68,0.25 C68.53,11.64 74.12,25.6 85.21,38.39 C115.84,72.27 148.67,90.67 218.58,75.71 C254.01,214.74 312.66,319.67 166.82,292.86 C166.82,292.86 61.19,143.45 61.19,143.45 C57.04,130.17 50.08,112.95 39.06,94.86 C28.46,77.49 14.05,57.75 4.69,48.2 C4.2,46.35 0.25,36.08 10.96,21.83 C17.93,11.59 30.17,4.01 42.21,4.34c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.425,0 0.463,0.469 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="733"
+ android:propertyName="pathData"
+ android:startOffset="1033"
+ android:valueFrom="M42.21 4.34 C42.21,4.34 58.68,0.25 58.68,0.25 C68.53,11.64 74.12,25.6 85.21,38.39 C115.84,72.27 148.67,90.67 218.58,75.71 C254.01,214.74 312.66,319.67 166.82,292.86 C166.82,292.86 61.19,143.45 61.19,143.45 C57.04,130.17 50.08,112.95 39.06,94.86 C28.46,77.49 14.05,57.75 4.69,48.2 C4.2,46.35 0.25,36.08 10.96,21.83 C17.93,11.59 30.17,4.01 42.21,4.34c "
+ android:valueTo="M42.21 4.34 C42.21,4.34 58.68,0.25 58.68,0.25 C68.53,11.64 74.12,25.6 85.21,38.39 C115.84,72.27 148.67,90.67 218.58,75.71 C254.01,214.74 312.66,319.67 166.82,292.86 C166.82,292.86 61.19,143.45 61.19,143.45 C57.04,130.17 50.08,112.95 39.06,94.86 C28.46,77.49 14.05,57.75 4.69,48.2 C4.2,46.35 0.25,36.08 10.96,21.83 C17.93,11.59 30.17,4.01 42.21,4.34c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.275,0.272 0.661,0.665 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="500"
+ android:propertyName="pathData"
+ android:startOffset="1767"
+ android:valueFrom="M42.21 4.34 C42.21,4.34 58.68,0.25 58.68,0.25 C68.53,11.64 74.12,25.6 85.21,38.39 C115.84,72.27 148.67,90.67 218.58,75.71 C254.01,214.74 312.66,319.67 166.82,292.86 C166.82,292.86 61.19,143.45 61.19,143.45 C57.04,130.17 50.08,112.95 39.06,94.86 C28.46,77.49 14.05,57.75 4.69,48.2 C4.2,46.35 0.25,36.08 10.96,21.83 C17.93,11.59 30.17,4.01 42.21,4.34c "
+ android:valueTo="M42.21 4.34 C42.21,4.34 58.68,0.25 58.68,0.25 C68.53,11.64 74.12,25.6 85.21,38.39 C115.84,72.27 148.67,90.67 218.58,75.71 C254.01,214.74 312.66,319.67 166.82,292.86 C166.82,292.86 61.19,143.45 61.19,143.45 C57.04,130.17 50.08,112.95 39.06,94.86 C28.46,77.49 14.05,57.75 4.69,48.2 C4.2,46.35 0.25,36.08 10.96,21.83 C17.93,11.59 30.17,4.01 42.21,4.34c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.165 0.661,0.665 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="733"
+ android:propertyName="pathData"
+ android:startOffset="2267"
+ android:valueFrom="M42.21 4.34 C42.21,4.34 58.68,0.25 58.68,0.25 C68.53,11.64 74.12,25.6 85.21,38.39 C115.84,72.27 148.67,90.67 218.58,75.71 C254.01,214.74 312.66,319.67 166.82,292.86 C166.82,292.86 61.19,143.45 61.19,143.45 C57.04,130.17 50.08,112.95 39.06,94.86 C28.46,77.49 14.05,57.75 4.69,48.2 C4.2,46.35 0.25,36.08 10.96,21.83 C17.93,11.59 30.17,4.01 42.21,4.34c "
+ android:valueTo="M42.21 4.34 C42.21,4.34 58.68,0.25 58.68,0.25 C68.53,11.64 74.12,25.6 85.21,38.39 C115.84,72.27 136.7,91.72 185.58,117.71 C221.01,256.74 312.66,319.67 166.82,292.86 C166.82,292.86 61.19,143.45 61.19,143.45 C57.04,130.17 50.08,112.95 39.06,94.86 C28.46,77.49 14.05,57.75 4.69,48.2 C4.2,46.35 0.25,36.08 10.96,21.83 C17.93,11.59 30.17,4.01 42.21,4.34c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.449,0.445 0.528,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_1_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M26.74 49.32 C26.74,49.32 34.17,35.86 51.22,27.28 "
+ android:valueTo="M26.74 49.32 C26.74,49.32 34.17,35.86 51.22,27.28 "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.55,0 0.375,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="833"
+ android:propertyName="pathData"
+ android:startOffset="333"
+ android:valueFrom="M26.74 49.32 C26.74,49.32 34.17,35.86 51.22,27.28 "
+ android:valueTo="M32.48 57.18 C32.48,57.18 40.18,30.6 69.87,29.66 "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.55,0 0.375,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="600"
+ android:propertyName="pathData"
+ android:startOffset="1167"
+ android:valueFrom="M32.48 57.18 C32.48,57.18 40.18,30.6 69.87,29.66 "
+ android:valueTo="M32.48 57.18 C32.48,57.18 40.18,30.6 69.87,29.66 "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="pathData"
+ android:startOffset="1767"
+ android:valueFrom="M32.48 57.18 C32.48,57.18 40.18,30.6 69.87,29.66 "
+ android:valueTo="M32.48 57.18 C32.48,57.18 40.18,30.6 69.87,29.66 "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="pathData"
+ android:startOffset="2100"
+ android:valueFrom="M32.48 57.18 C32.48,57.18 40.18,30.6 69.87,29.66 "
+ android:valueTo="M32.48 57.18 C32.48,57.18 40.18,30.6 69.87,29.66 "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1233"
+ android:propertyName="pathData"
+ android:startOffset="2267"
+ android:valueFrom="M32.48 57.18 C32.48,57.18 40.18,30.6 69.87,29.66 "
+ android:valueTo="M26.74 49.32 C26.74,49.32 34.17,35.86 51.22,27.28 "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="110.176"
+ android:valueTo="110.176"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.658,0 0.401,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="833"
+ android:propertyName="translateX"
+ android:startOffset="333"
+ android:valueFrom="110.176"
+ android:valueTo="45.176"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.658,0 0.401,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="933"
+ android:propertyName="translateX"
+ android:startOffset="1167"
+ android:valueFrom="45.176"
+ android:valueTo="45.176"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="translateX"
+ android:startOffset="2100"
+ android:valueFrom="45.176"
+ android:valueTo="45.176"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1233"
+ android:propertyName="translateX"
+ android:startOffset="2267"
+ android:valueFrom="45.176"
+ android:valueTo="110.176"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.286,0 0.489,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="translateY"
+ android:startOffset="0"
+ android:valueFrom="177.218"
+ android:valueTo="177.218"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.658,0 0.401,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="833"
+ android:propertyName="translateY"
+ android:startOffset="333"
+ android:valueFrom="177.218"
+ android:valueTo="190.218"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.658,0 0.401,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="600"
+ android:propertyName="translateY"
+ android:startOffset="1167"
+ android:valueFrom="190.218"
+ android:valueTo="190.218"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.401,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="translateY"
+ android:startOffset="1767"
+ android:valueFrom="190.218"
+ android:valueTo="201.218"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.539,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="translateY"
+ android:startOffset="2100"
+ android:valueFrom="201.218"
+ android:valueTo="201.218"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.539,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1233"
+ android:propertyName="translateY"
+ android:startOffset="2267"
+ android:valueFrom="201.218"
+ android:valueTo="177.218"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.286,0 0.489,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="-45"
+ android:valueTo="-45"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.618,0 0.348,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="833"
+ android:propertyName="rotation"
+ android:startOffset="333"
+ android:valueFrom="-45"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.618,0 0.348,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="600"
+ android:propertyName="rotation"
+ android:startOffset="1167"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.348,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="rotation"
+ android:startOffset="1767"
+ android:valueFrom="0"
+ android:valueTo="-1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.539,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="rotation"
+ android:startOffset="2100"
+ android:valueFrom="-1"
+ android:valueTo="-1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.539,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1233"
+ android:propertyName="rotation"
+ android:startOffset="2267"
+ android:valueFrom="-1"
+ android:valueTo="-45"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.286,0 0.489,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="3500"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector>
\ No newline at end of file
diff --git a/quickstep/res/layout/overview_actions_container.xml b/quickstep/res/layout/overview_actions_container.xml
index e163991..1ecec25 100644
--- a/quickstep/res/layout/overview_actions_container.xml
+++ b/quickstep/res/layout/overview_actions_container.xml
@@ -35,6 +35,7 @@
</Space>
<Button
android:id="@+id/action_screenshot"
+ android:theme="@style/ThemeControlHighlightWorkspaceColor"
style="@style/OverviewActionButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -48,6 +49,7 @@
<Button
android:id="@+id/action_share"
+ android:theme="@style/ThemeControlHighlightWorkspaceColor"
style="@style/OverviewActionButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/quickstep/res/values-de/strings.xml b/quickstep/res/values-de/strings.xml
index e5606a3..c1cf68e 100644
--- a/quickstep/res/values-de/strings.xml
+++ b/quickstep/res/values-de/strings.xml
@@ -20,7 +20,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_split_screen" msgid="5353188922202653570">"Splitscreen"</string>
- <string name="recent_task_option_pin" msgid="7929860679018978258">"Anpinnen"</string>
+ <string name="recent_task_option_pin" msgid="7929860679018978258">"Fixieren"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform-Modus"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Keine kürzlich verwendeten Elemente"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Einstellungen zur App-Nutzung"</string>
diff --git a/quickstep/res/values-es/strings.xml b/quickstep/res/values-es/strings.xml
index 2b7f80d..39ba152 100644
--- a/quickstep/res/values-es/strings.xml
+++ b/quickstep/res/values-es/strings.xml
@@ -45,5 +45,5 @@
<string name="hotseat_tip_gaps_filled" msgid="3035673010274223538">"Se han añadido sugerencias de aplicaciones a espacios vacíos"</string>
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Aplicación sugerida: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"Compartir"</string>
- <string name="action_screenshot" msgid="8171125848358142917">"Hacer captura de pantalla"</string>
+ <string name="action_screenshot" msgid="8171125848358142917">"Hacer captura"</string>
</resources>
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index b06dc6b..6c521fc 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -17,14 +17,16 @@
<resources>
<dimen name="task_thumbnail_top_margin">24dp</dimen>
- <dimen name="task_thumbnail_bottom_margin_with_actions">44dp</dimen>
<dimen name="task_thumbnail_half_top_margin">12dp</dimen>
<dimen name="task_thumbnail_icon_size">48dp</dimen>
<!-- For screens without rounded corners -->
<dimen name="task_corner_radius_small">2dp</dimen>
<!-- Overrideable in overlay that provides the Overview Actions. -->
- <dimen name="overview_actions_height">110dp</dimen>
+ <dimen name="overview_actions_height">66dp</dimen>
+ <dimen name="overview_actions_top_margin">44dp</dimen>
+ <dimen name="overview_actions_bottom_margin_gesture">16dp</dimen>
+ <dimen name="overview_actions_bottom_margin_three_button">8dp</dimen>
<dimen name="overview_actions_horizontal_margin">16dp</dimen>
<dimen name="recents_page_spacing">10dp</dimen>
@@ -61,7 +63,7 @@
<dimen name="task_card_menu_shadow_height">3dp</dimen>
<dimen name="task_card_menu_horizontal_padding">0dp</dimen>
<dimen name="portrait_task_card_horz_space">136dp</dimen>
- <dimen name="portrait_task_card_horz_space_big_overview">24dp</dimen>
+ <dimen name="portrait_task_card_horz_space_big_overview">96dp</dimen>
<dimen name="landscape_task_card_horz_space">200dp</dimen>
<dimen name="multi_window_task_card_horz_space">100dp</dimen>
<!-- Copied from framework resource:
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index b474a32..8368817 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -141,4 +141,6 @@
<string name="action_share">Share</string>
<!-- Label for a button that causes a screen shot of the current app to be taken. [CHAR_LIMIT=40] -->
<string name="action_screenshot">Screenshot</string>
+ <!-- Message shown when an action is blocked by a policy enforced by the app or the organization managing the device. [CHAR_LIMIT=NONE] -->
+ <string name="blocked_by_policy">This action isn\'t allowed by the app or your organization</string>
</resources>
\ No newline at end of file
diff --git a/quickstep/res/values/styles.xml b/quickstep/res/values/styles.xml
index 3926988..d3c4f4d 100644
--- a/quickstep/res/values/styles.xml
+++ b/quickstep/res/values/styles.xml
@@ -69,10 +69,18 @@
<item name="android:textColor">@color/gesture_tutorial_primary_color</item>
</style>
+ <!--
+ Can be applied to views to color things like ripples and list highlights the workspace text
+ color.
+ -->
+ <style name="ThemeControlHighlightWorkspaceColor">
+ <item name="android:colorControlHighlight">?attr/workspaceTextColor</item>
+ </style>
+
<style name="OverviewActionButton"
parent="@android:style/Widget.DeviceDefault.Button.Borderless">
- <item name="android:textColor">?attr/workspaceTextColor</item>
- <item name="android:drawableTint">?attr/workspaceTextColor</item>
+ <item name="android:textColor">@color/overview_button</item>
+ <item name="android:drawableTint">@color/overview_button</item>
<item name="android:tint">?attr/workspaceTextColor</item>
<item name="android:drawablePadding">4dp</item>
<item name="android:textAllCaps">false</item>
diff --git a/quickstep/robolectric_tests/src/com/android/quickstep/RecentsActivityTest.java b/quickstep/robolectric_tests/src/com/android/quickstep/RecentsActivityTest.java
new file mode 100644
index 0000000..93b64e6
--- /dev/null
+++ b/quickstep/robolectric_tests/src/com/android/quickstep/RecentsActivityTest.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep;
+
+import static com.android.launcher3.util.LauncherUIHelper.doLayout;
+
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+
+import com.android.quickstep.fallback.FallbackRecentsView;
+import com.android.systemui.shared.recents.model.ThumbnailData;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.Robolectric;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.android.controller.ActivityController;
+import org.robolectric.annotation.LooperMode;
+import org.robolectric.annotation.LooperMode.Mode;
+import org.robolectric.shadows.ShadowLooper;
+import org.robolectric.util.ReflectionHelpers;
+
+
+@RunWith(RobolectricTestRunner.class)
+@LooperMode(Mode.PAUSED)
+public class RecentsActivityTest {
+
+ @Test
+ public void testRecentsActivityCreates() {
+ ActivityController<RecentsActivity> controller =
+ Robolectric.buildActivity(RecentsActivity.class);
+
+ RecentsActivity launcher = controller.setup().get();
+ doLayout(launcher);
+
+ // TODO: Ensure that LauncherAppState is not created
+ }
+
+ @Test
+ public void testRecets_showCurrentTask() {
+ ActivityController<RecentsActivity> controller =
+ Robolectric.buildActivity(RecentsActivity.class);
+
+ RecentsActivity activity = controller.setup().get();
+ doLayout(activity);
+
+ FallbackRecentsView frv = activity.getOverviewPanel();
+ frv.showCurrentTask(22);
+ doLayout(activity);
+
+ ThumbnailData thumbnailData = new ThumbnailData();
+ ReflectionHelpers.setField(thumbnailData, "thumbnail",
+ Bitmap.createBitmap(300, 500, Config.ARGB_8888));
+ frv.switchToScreenshot(thumbnailData, () -> { });
+ ShadowLooper.idleMainLooper();
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
index af63a25..629a74b 100644
--- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
@@ -17,6 +17,7 @@
import static com.android.launcher3.AbstractFloatingView.TYPE_ALL;
import static com.android.launcher3.AbstractFloatingView.TYPE_HIDE_BACK_BUTTON;
+import static com.android.launcher3.LauncherState.FLAG_HIDE_BACK_BUTTON;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview;
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY;
@@ -29,7 +30,6 @@
import android.os.Bundle;
import android.os.CancellationSignal;
-import com.android.launcher3.LauncherStateManager.StateHandler;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.WellbeingModel;
import com.android.launcher3.popup.SystemShortcut;
@@ -37,6 +37,7 @@
import com.android.launcher3.proxy.StartActivityParams;
import com.android.launcher3.statehandlers.BackButtonAlphaHandler;
import com.android.launcher3.statehandlers.DepthController;
+import com.android.launcher3.statemanager.StateManager.StateHandler;
import com.android.launcher3.uioverrides.RecentsViewStateController;
import com.android.launcher3.util.OnboardingPrefs;
import com.android.launcher3.util.UiThreadHelper;
@@ -91,6 +92,9 @@
@Override
public void onNavigationModeChanged(Mode newMode) {
getDragLayer().recreateControllers();
+ if (mActionsView != null && isOverviewActionsEnabled()) {
+ mActionsView.updateVerticalMarginForNavModeChange(newMode);
+ }
}
@Override
@@ -149,6 +153,7 @@
@Override
protected void onDeferredResumed() {
+ super.onDeferredResumed();
if (mPendingActivityRequestCode != -1 && isInState(NORMAL)) {
// Remove any active ProxyActivityStarter task and send RESULT_CANCELED to Launcher.
onActivityResult(mPendingActivityRequestCode, RESULT_CANCELED, null);
@@ -166,13 +171,18 @@
mActionsView = findViewById(R.id.overview_actions_view);
((RecentsView) getOverviewPanel()).init(mActionsView);
- if (FeatureFlags.ENABLE_OVERVIEW_ACTIONS.get() && removeShelfFromOverview(this)) {
+ if (isOverviewActionsEnabled()) {
// Overview is above all other launcher elements, including qsb, so move it to the top.
getOverviewPanel().bringToFront();
mActionsView.bringToFront();
+ mActionsView.updateVerticalMarginForNavModeChange(SysUINavigationMode.getMode(this));
}
}
+ private boolean isOverviewActionsEnabled() {
+ return FeatureFlags.ENABLE_OVERVIEW_ACTIONS.get() && removeShelfFromOverview(this);
+ }
+
public <T extends OverviewActionsView> T getActionsView() {
return (T) mActionsView;
}
@@ -185,7 +195,7 @@
}
@Override
- protected StateHandler[] createStateHandlers() {
+ protected StateHandler<LauncherState>[] createStateHandlers() {
return new StateHandler[] {
getAllAppsController(),
getWorkspace(),
@@ -199,9 +209,8 @@
}
@Override
- protected OnboardingPrefs createOnboardingPrefs(SharedPreferences sharedPrefs,
- LauncherStateManager stateManager) {
- return new QuickstepOnboardingPrefs(this, sharedPrefs, stateManager);
+ protected OnboardingPrefs createOnboardingPrefs(SharedPreferences sharedPrefs) {
+ return new QuickstepOnboardingPrefs(this, sharedPrefs);
}
@Override
@@ -251,13 +260,10 @@
super.onActivityFlagsChanged(changeBits);
}
- /**
- * Sets the back button visibility based on the current state/window focus.
- */
- private void onLauncherStateOrFocusChanged() {
+ public boolean shouldBackButtonBeHidden(LauncherState toState) {
Mode mode = SysUINavigationMode.getMode(this);
boolean shouldBackButtonBeHidden = mode.hasGestures
- && getStateManager().getState().hideBackButton
+ && toState.hasFlag(FLAG_HIDE_BACK_BUTTON)
&& hasWindowFocus()
&& (getActivityFlags() & ACTIVITY_STATE_TRANSITION_ACTIVE) == 0;
if (shouldBackButtonBeHidden) {
@@ -265,6 +271,14 @@
shouldBackButtonBeHidden = AbstractFloatingView.getTopOpenViewWithType(this,
TYPE_ALL & ~TYPE_HIDE_BACK_BUTTON) == null;
}
+ return shouldBackButtonBeHidden;
+ }
+
+ /**
+ * Sets the back button visibility based on the current state/window focus.
+ */
+ private void onLauncherStateOrFocusChanged() {
+ boolean shouldBackButtonBeHidden = shouldBackButtonBeHidden(getStateManager().getState());
UiThreadHelper.setBackButtonAlphaAsync(this, SET_BACK_BUTTON_ALPHA,
shouldBackButtonBeHidden ? 0f : 1f, true /* animate */);
if (getDragLayer() != null) {
diff --git a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
index 2cb23f1..fc60434 100644
--- a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
+++ b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
@@ -26,6 +26,7 @@
import android.content.Context;
import android.os.Build;
import android.os.Handler;
+import android.util.Log;
import androidx.annotation.BinderThread;
import androidx.annotation.UiThread;
@@ -37,6 +38,8 @@
public abstract class LauncherAnimationRunner implements RemoteAnimationRunnerCompat,
WrappedAnimationRunnerImpl {
+ private static final String TAG = "LauncherAnimationRunner";
+
private final Handler mHandler;
private final boolean mStartAtFrontOfQueue;
private AnimationResult mAnimationResult;
@@ -151,7 +154,16 @@
// Because t=0 has the app icon in its original spot, we can skip the
// first frame and have the same movement one frame earlier.
- mAnimator.setCurrentPlayTime(getSingleFrameMs(context));
+ int singleFrameMs = getSingleFrameMs(context);
+ long playTime = singleFrameMs;
+ // b/153821199 Add logs to debug crash but ensure release builds do not crash.
+ if (Utilities.IS_DEBUG_DEVICE) {
+ Log.e(TAG, "Total duration=[" + mAnimator.getTotalDuration()
+ + "], singleFrameMs=[" + singleFrameMs + "], mAnimator=" + mAnimator);
+ } else {
+ playTime = Math.min(singleFrameMs, mAnimator.getTotalDuration());
+ }
+ mAnimator.setCurrentPlayTime(playTime);
}
}
}
diff --git a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
index 1cb0aa4..e718598 100644
--- a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
+++ b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
@@ -493,7 +493,7 @@
: APP_LAUNCH_ALPHA_DOWN_DURATION;
RectF targetBounds = new RectF(windowTargetBounds);
- RectF currentBounds = new RectF();
+ RectF iconBounds = new RectF();
RectF temp = new RectF();
Point tmpPos = new Point();
@@ -531,7 +531,7 @@
appAnimator.addUpdateListener(new MultiValueUpdateListener() {
FloatProp mDx = new FloatProp(0, dX, 0, xDuration, AGGRESSIVE_EASE);
FloatProp mDy = new FloatProp(0, dY, 0, yDuration, AGGRESSIVE_EASE);
- FloatProp mIconScale = new FloatProp(initialStartScale, scale, 0, APP_LAUNCH_DURATION,
+ FloatProp mScale = new FloatProp(initialStartScale, scale, 0, APP_LAUNCH_DURATION,
EXAGGERATED_EASE);
FloatProp mIconAlpha = new FloatProp(1f, 0f, APP_LAUNCH_ALPHA_START_DELAY,
alphaDuration, LINEAR);
@@ -542,40 +542,48 @@
@Override
public void onUpdate(float percent) {
- // Calculate app icon size.
- float iconWidth = bounds.width() * mIconScale.value;
- float iconHeight = bounds.height() * mIconScale.value;
+ // Calculate the size.
+ float width = bounds.width() * mScale.value;
+ float height = bounds.height() * mScale.value;
- // Animate the window crop so that it starts off as a square.
- final int windowWidth;
- final int windowHeight;
+ // Animate the crop so that it starts off as a square.
+ final int cropWidth;
+ final int cropHeight;
if (mDeviceProfile.isVerticalBarLayout()) {
- windowWidth = (int) mCroppedSize.value;
- windowHeight = windowTargetBounds.height();
+ cropWidth = (int) mCroppedSize.value;
+ cropHeight = windowTargetBounds.height();
} else {
- windowWidth = windowTargetBounds.width();
- windowHeight = (int) mCroppedSize.value;
+ cropWidth = windowTargetBounds.width();
+ cropHeight = (int) mCroppedSize.value;
}
- crop.set(0, 0, windowWidth, windowHeight);
+ crop.set(0, 0, cropWidth, cropHeight);
- // Scale the app window to match the icon size.
- float scaleX = iconWidth / windowWidth;
- float scaleY = iconHeight / windowHeight;
+ // Scale the size to match the crop.
+ float scaleX = width / cropWidth;
+ float scaleY = height / cropHeight;
float scale = Math.min(1f, Math.max(scaleX, scaleY));
- float scaledWindowWidth = windowWidth * scale;
- float scaledWindowHeight = windowHeight * scale;
+ float scaledCropWidth = cropWidth * scale;
+ float scaledCropHeight = cropHeight * scale;
+ float offsetX = (scaledCropWidth - width) / 2;
+ float offsetY = (scaledCropHeight - height) / 2;
- float offsetX = (scaledWindowWidth - iconWidth) / 2;
- float offsetY = (scaledWindowHeight - iconHeight) / 2;
-
- // Calculate the window position
+ // Calculate the window position.
temp.set(bounds);
temp.offset(dragLayerBounds[0], dragLayerBounds[1]);
temp.offset(mDx.value, mDy.value);
- Utilities.scaleRectFAboutCenter(temp, mIconScale.value);
- float transX0 = temp.left - offsetX;
- float transY0 = temp.top - offsetY;
+ Utilities.scaleRectFAboutCenter(temp, mScale.value);
+ float windowTransX0 = temp.left - offsetX;
+ float windowTransY0 = temp.top - offsetY;
+
+ // Calculate the icon position.
+ iconBounds.set(bounds);
+ iconBounds.offset(mDx.value, mDy.value);
+ Utilities.scaleRectFAboutCenter(iconBounds, mScale.value);
+ iconBounds.left -= offsetX;
+ iconBounds.top -= offsetY;
+ iconBounds.right += offsetX;
+ iconBounds.bottom += offsetY;
float croppedHeight = (windowTargetBounds.height() - crop.height()) * scale;
float croppedWidth = (windowTargetBounds.width() - crop.width()) * scale;
@@ -584,28 +592,23 @@
RemoteAnimationTargetCompat target = appTargets[i];
SurfaceParams.Builder builder = new SurfaceParams.Builder(target.leash);
- tmpPos.set(target.position.x, target.position.y);
- if (target.localBounds != null) {
- final Rect localBounds = target.localBounds;
- tmpPos.set(target.localBounds.left, target.localBounds.top);
- }
-
if (target.mode == MODE_OPENING) {
matrix.setScale(scale, scale);
- matrix.postTranslate(transX0, transY0);
- matrix.mapRect(currentBounds, targetBounds);
- if (mDeviceProfile.isVerticalBarLayout()) {
- currentBounds.right -= croppedWidth;
- } else {
- currentBounds.bottom -= croppedHeight;
- }
- floatingView.update(currentBounds, mIconAlpha.value, percent, 0f,
+ matrix.postTranslate(windowTransX0, windowTransY0);
+
+ floatingView.update(iconBounds, mIconAlpha.value, percent, 0f,
mWindowRadius.value * scale, true /* isOpening */);
builder.withMatrix(matrix)
.withWindowCrop(crop)
.withAlpha(1f - mIconAlpha.value)
.withCornerRadius(mWindowRadius.value);
} else {
+ tmpPos.set(target.position.x, target.position.y);
+ if (target.localBounds != null) {
+ final Rect localBounds = target.localBounds;
+ tmpPos.set(target.localBounds.left, target.localBounds.top);
+ }
+
matrix.setTranslate(tmpPos.x, tmpPos.y);
builder.withMatrix(matrix)
.withWindowCrop(target.screenSpaceBounds)
diff --git a/quickstep/src/com/android/launcher3/statehandlers/BackButtonAlphaHandler.java b/quickstep/src/com/android/launcher3/statehandlers/BackButtonAlphaHandler.java
index 983702a..13501a4 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/BackButtonAlphaHandler.java
+++ b/quickstep/src/com/android/launcher3/statehandlers/BackButtonAlphaHandler.java
@@ -21,8 +21,8 @@
import com.android.launcher3.BaseQuickstepLauncher;
import com.android.launcher3.LauncherState;
-import com.android.launcher3.LauncherStateManager;
import com.android.launcher3.anim.PendingAnimation;
+import com.android.launcher3.statemanager.StateManager.StateHandler;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.util.UiThreadHelper;
import com.android.quickstep.AnimatedFloat;
@@ -32,7 +32,7 @@
/**
* State handler for animating back button alpha
*/
-public class BackButtonAlphaHandler implements LauncherStateManager.StateHandler {
+public class BackButtonAlphaHandler implements StateHandler<LauncherState> {
private final BaseQuickstepLauncher mLauncher;
private final AnimatedFloat mBackAlpha = new AnimatedFloat(this::updateBackAlpha);
@@ -59,7 +59,8 @@
}
mBackAlpha.value = SystemUiProxy.INSTANCE.get(mLauncher).getLastBackButtonAlpha();
- animation.setFloat(mBackAlpha, VALUE, toState.hideBackButton ? 0 : 1, LINEAR);
+ animation.setFloat(mBackAlpha, VALUE,
+ mLauncher.shouldBackButtonBeHidden(toState) ? 0 : 1, LINEAR);
}
private void updateBackAlpha() {
diff --git a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
index 5f5d6dc..8292a92 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
+++ b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
@@ -26,10 +26,10 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
-import com.android.launcher3.LauncherStateManager;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.PendingAnimation;
+import com.android.launcher3.statemanager.StateManager.StateHandler;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.SurfaceControlCompat;
@@ -39,7 +39,7 @@
/**
* Controls blur and wallpaper zoom, for the Launcher surface only.
*/
-public class DepthController implements LauncherStateManager.StateHandler {
+public class DepthController implements StateHandler<LauncherState> {
public static final FloatProperty<DepthController> DEPTH =
new FloatProperty<DepthController>("depth") {
@@ -193,8 +193,17 @@
if (windowToken != null) {
mWallpaperManager.setWallpaperZoomOut(windowToken, mDepth);
}
+ final int blur;
+ if (mLauncher.isInState(LauncherState.ALL_APPS) && mDepth == 1) {
+ // All apps has a solid background. We don't need to draw blurs after it's fully
+ // visible. This will take us out of GPU composition, saving battery and increasing
+ // performance.
+ blur = 0;
+ } else {
+ blur = (int) (mDepth * mMaxBlurRadius);
+ }
new TransactionCompat()
- .setBackgroundBlurRadius(mSurface, (int) (mDepth * mMaxBlurRadius))
+ .setBackgroundBlurRadius(mSurface, blur)
.apply();
}
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
index ac50d6d..ec3a490 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
@@ -36,9 +36,9 @@
import com.android.launcher3.BaseQuickstepLauncher;
import com.android.launcher3.LauncherState;
-import com.android.launcher3.LauncherStateManager.StateHandler;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.graphics.OverviewScrim;
+import com.android.launcher3.statemanager.StateManager.StateHandler;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.quickstep.views.RecentsView;
@@ -49,7 +49,7 @@
* @param <T> the recents view
*/
public abstract class BaseRecentsViewStateController<T extends RecentsView>
- implements StateHandler {
+ implements StateHandler<LauncherState> {
protected final T mRecentsView;
protected final BaseQuickstepLauncher mLauncher;
@@ -107,7 +107,7 @@
setter.setFloat(
mRecentsView, getTaskModalnessProperty(),
toState.getOverviewModalness(),
- config.getInterpolator(ANIM_OVERVIEW_MODAL, AGGRESSIVE_EASE_IN_OUT));
+ config.getInterpolator(ANIM_OVERVIEW_MODAL, LINEAR));
}
abstract FloatProperty getTaskModalnessProperty();
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
index 81d4224..e7cd393 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
@@ -21,7 +21,6 @@
import android.content.Context;
-import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.allapps.AllAppsContainerView;
@@ -33,7 +32,7 @@
*/
public class AllAppsState extends LauncherState {
- private static final int STATE_FLAGS = FLAG_DISABLE_ACCESSIBILITY;
+ private static final int STATE_FLAGS = FLAG_WORKSPACE_INACCESSIBLE | FLAG_CLOSE_POPUPS;
private static final PageAlphaProvider PAGE_ALPHA_PROVIDER = new PageAlphaProvider(DEACCEL_2) {
@Override
@@ -47,23 +46,11 @@
}
@Override
- public int getTransitionDuration(Launcher launcher) {
+ public int getTransitionDuration(Context context) {
return 320;
}
@Override
- public void onStateEnabled(Launcher launcher) {
- AbstractFloatingView.closeAllOpenViews(launcher);
- dispatchWindowStateChanged(launcher);
- }
-
- @Override
- public void onStateDisabled(Launcher launcher) {
- super.onStateDisabled(launcher);
- AbstractFloatingView.closeAllOpenViews(launcher);
- }
-
- @Override
public String getDescription(Launcher launcher) {
AllAppsContainerView appsView = launcher.getAppsView();
return appsView.getDescription();
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index a7a03e5..43328b6 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -18,14 +18,11 @@
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Rect;
-import android.graphics.RectF;
import android.os.Build;
-import android.util.Pair;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Interpolator;
-import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
@@ -33,7 +30,6 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.statehandlers.DepthController;
-import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.quickstep.util.ActivityInitListener;
import com.android.quickstep.util.ShelfPeekAnim;
import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -52,24 +48,13 @@
int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context, Rect outRect);
- /**
- * @return The progress of the swipe where we start resisting the user, where 0 is fullscreen
- * and 1 is recents. These values should probably be greater than 1 to let the user swipe past
- * recents before we start resisting them.
- */
- default Pair<Float, Float> getSwipeUpPullbackStartAndMaxProgress() {
- return new Pair<>(1.4f, 1.8f);
- }
-
void onSwipeUpToRecentsComplete();
default void onSwipeUpToHomeComplete() { }
void onAssistantVisibilityChanged(float visibility);
- @NonNull HomeAnimationFactory prepareHomeUI();
-
- AnimationFactory prepareRecentsUI(boolean activityVisible, boolean animateActivity,
- Consumer<AnimatorPlaybackController> callback);
+ AnimationFactory prepareRecentsUI(
+ boolean activityVisible, Consumer<AnimatorPlaybackController> callback);
ActivityInitListener createActivityInitListener(Predicate<Boolean> onInitListener);
@@ -105,7 +90,7 @@
Rect getOverviewWindowBounds(Rect homeBounds, RemoteAnimationTargetCompat target);
- boolean shouldMinimizeSplitScreen();
+ boolean allowMinimizeSplitScreen();
default boolean deferStartingActivity(RecentsAnimationDeviceState deviceState, MotionEvent ev) {
return true;
@@ -152,35 +137,4 @@
*/
default void setRecentsAttachedToAppWindow(boolean attached, boolean animate) { }
}
-
- interface HomeAnimationFactory {
-
- /** Return the floating view that will animate in sync with the closing window. */
- default @Nullable View getFloatingView() {
- return null;
- }
-
- @NonNull RectF getWindowTargetRect();
-
- @NonNull AnimatorPlaybackController createActivityAnimationToHome();
-
- default void playAtomicAnimation(float velocity) {
- // No-op
- }
-
- static RectF getDefaultWindowTargetRect(PagedOrientationHandler orientationHandler,
- DeviceProfile dp) {
- final int halfIconSize = dp.iconSizePx / 2;
- float primaryDimension = orientationHandler
- .getPrimaryValue(dp.availableWidthPx, dp.availableHeightPx);
- float secondaryDimension = orientationHandler
- .getSecondaryValue(dp.availableWidthPx, dp.availableHeightPx);
- final float targetX = primaryDimension / 2f;
- final float targetY = secondaryDimension - dp.hotseatBarSizePx;
- // Fallback to animate to center of screen.
- return new RectF(targetX - halfIconSize, targetY - halfIconSize,
- targetX + halfIconSize, targetY + halfIconSize);
- }
-
- }
}
diff --git a/quickstep/src/com/android/quickstep/BaseRecentsActivity.java b/quickstep/src/com/android/quickstep/BaseRecentsActivity.java
deleted file mode 100644
index 1b9158b..0000000
--- a/quickstep/src/com/android/quickstep/BaseRecentsActivity.java
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.quickstep;
-
-import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
-import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
-
-import android.content.Intent;
-import android.content.res.Configuration;
-import android.os.Bundle;
-
-import com.android.launcher3.AbstractFloatingView;
-import com.android.launcher3.BaseDraggingActivity;
-import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.InvariantDeviceProfile;
-import com.android.launcher3.R;
-import com.android.launcher3.util.ActivityTracker;
-import com.android.launcher3.util.SystemUiController;
-import com.android.launcher3.util.Themes;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-
-/**
- * A base fallback recents activity that provides support for device profile changes, activity
- * lifecycle tracking, and basic input handling from recents.
- *
- * This class is only used as a fallback in case the default launcher does not have a recents
- * implementation.
- */
-public abstract class BaseRecentsActivity extends BaseDraggingActivity {
-
- public static final ActivityTracker<BaseRecentsActivity> ACTIVITY_TRACKER =
- new ActivityTracker<>();
- private Configuration mOldConfig;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- mOldConfig = new Configuration(getResources().getConfiguration());
- initDeviceProfile();
- initViews();
-
- getSystemUiController().updateUiState(SystemUiController.UI_STATE_BASE_WINDOW,
- Themes.getAttrBoolean(this, R.attr.isWorkspaceDarkText));
- ACTIVITY_TRACKER.handleCreate(this);
- }
-
- /**
- * Init drag layer and overview panel views.
- */
- abstract protected void initViews();
-
- @Override
- public void onConfigurationChanged(Configuration newConfig) {
- int diff = newConfig.diff(mOldConfig);
- if ((diff & (CONFIG_ORIENTATION | CONFIG_SCREEN_SIZE)) != 0) {
- onHandleConfigChanged();
- }
- mOldConfig.setTo(newConfig);
- super.onConfigurationChanged(newConfig);
- }
-
- /**
- * Logic for when device configuration changes (rotation, screen size change, multi-window,
- * etc.)
- */
- protected void onHandleConfigChanged() {
- mUserEventDispatcher = null;
- initDeviceProfile();
-
- AbstractFloatingView.closeOpenViews(this, true,
- AbstractFloatingView.TYPE_ALL & ~AbstractFloatingView.TYPE_REBIND_SAFE);
- dispatchDeviceProfileChanged();
-
- reapplyUi();
- }
-
- /**
- * Initialize/update the device profile.
- */
- private void initDeviceProfile() {
- mDeviceProfile = createDeviceProfile();
- onDeviceProfileInitiated();
- }
-
- /**
- * Generate the device profile to use in this activity.
- * @return device profile
- */
- protected DeviceProfile createDeviceProfile() {
- DeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(this).getDeviceProfile(this);
-
- // In case we are reusing IDP, create a copy so that we don't conflict with Launcher
- // activity.
- return dp.copy(this);
- }
-
-
- @Override
- protected void onStop() {
- super.onStop();
-
- // Workaround for b/78520668, explicitly trim memory once UI is hidden
- onTrimMemory(TRIM_MEMORY_UI_HIDDEN);
- }
-
- @Override
- public void onEnterAnimationComplete() {
- super.onEnterAnimationComplete();
- // After the transition to home, enable the high-res thumbnail loader if it wasn't enabled
- // as a part of quickstep, so that high-res thumbnails can load the next time we enter
- // overview
- RecentsModel.INSTANCE.get(this).getThumbnailCache()
- .getHighResLoadingState().setVisible(true);
- }
-
- @Override
- public void onTrimMemory(int level) {
- super.onTrimMemory(level);
- RecentsModel.INSTANCE.get(this).onTrimMemory(level);
- }
-
- @Override
- protected void onNewIntent(Intent intent) {
- super.onNewIntent(intent);
- ACTIVITY_TRACKER.handleNewIntent(this, intent);
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- ACTIVITY_TRACKER.onActivityDestroyed(this);
- }
-
- @Override
- public void onBackPressed() {
- // TODO: Launch the task we came from
- startHome();
- }
-
- public void startHome() {
- startActivity(new Intent(Intent.ACTION_MAIN)
- .addCategory(Intent.CATEGORY_HOME)
- .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
- }
-
- @Override
- public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
- super.dump(prefix, fd, writer, args);
- writer.println(prefix + "Misc:");
- dumpMisc(prefix + "\t", writer);
- }
-}
diff --git a/quickstep/src/com/android/quickstep/GestureState.java b/quickstep/src/com/android/quickstep/GestureState.java
index 544f420..9b515ae 100644
--- a/quickstep/src/com/android/quickstep/GestureState.java
+++ b/quickstep/src/com/android/quickstep/GestureState.java
@@ -110,10 +110,6 @@
public static final int STATE_RECENTS_SCROLLING_FINISHED =
getFlagForIndex("STATE_RECENTS_SCROLLING_FINISHED");
- // Called when the new task appeared from quick switching.
- public static final int STATE_TASK_APPEARED_DURING_SWITCH =
- getFlagForIndex("STATE_TASK_APPEARED_DURING_SWITCH");
-
// Needed to interact with the current activity
private final Intent mHomeIntent;
private final Intent mOverviewIntent;
@@ -123,9 +119,8 @@
private ActivityManager.RunningTaskInfo mRunningTask;
private GestureEndTarget mEndTarget;
- private RemoteAnimationTargetCompat mAnimationTarget;
- // TODO: This can be removed once we stop finishing the animation when starting a new task
- private int mFinishingRecentsAnimationTaskId = -1;
+ private RemoteAnimationTargetCompat mLastAppearedTaskTarget;
+ private int mLastStartedTaskId = -1;
public GestureState(OverviewComponentObserver componentObserver, int gestureId) {
mHomeIntent = componentObserver.getHomeIntent();
@@ -143,7 +138,8 @@
mGestureId = other.mGestureId;
mRunningTask = other.mRunningTask;
mEndTarget = other.mEndTarget;
- mFinishingRecentsAnimationTaskId = other.mFinishingRecentsAnimationTaskId;
+ mLastAppearedTaskTarget = other.mLastAppearedTaskTarget;
+ mLastStartedTaskId = other.mLastStartedTaskId;
}
public GestureState() {
@@ -226,20 +222,41 @@
}
/**
+ * Updates the last task that appeared during this gesture.
+ */
+ public void updateLastAppearedTaskTarget(RemoteAnimationTargetCompat lastAppearedTaskTarget) {
+ mLastAppearedTaskTarget = lastAppearedTaskTarget;
+ }
+
+ /**
+ * @return The id of the task that appeared during this gesture.
+ */
+ public int getLastAppearedTaskId() {
+ return mLastAppearedTaskTarget != null ? mLastAppearedTaskTarget.taskId : -1;
+ }
+
+ /**
+ * Updates the last task that we started via startActivityFromRecents() during this gesture.
+ */
+ public void updateLastStartedTaskId(int lastStartedTaskId) {
+ mLastStartedTaskId = lastStartedTaskId;
+ }
+
+ /**
+ * @return The id of the task that was most recently started during this gesture, or -1 if
+ * no task has been started yet (i.e. we haven't settled on a new task).
+ */
+ public int getLastStartedTaskId() {
+ return mLastStartedTaskId;
+ }
+
+ /**
* @return the end target for this gesture (if known).
*/
public GestureEndTarget getEndTarget() {
return mEndTarget;
}
- public void setAnimationTarget(RemoteAnimationTargetCompat target) {
- mAnimationTarget = target;
- }
-
- public RemoteAnimationTargetCompat getAnimationTarget() {
- return mAnimationTarget;
- }
-
/**
* Sets the end target of this gesture and immediately notifies the state changes.
*/
@@ -260,29 +277,8 @@
}
/**
- * @return the id for the task that was about to be launched following the finish of the recents
- * animation. Only defined between when the finish-recents call was made and the launch
- * activity call is made.
- */
- public int getFinishingRecentsAnimationTaskId() {
- return mFinishingRecentsAnimationTaskId;
- }
-
- /**
- * Sets the id for the task will be launched after the recents animation is finished. Once the
- * animation has finished then the id will be reset to -1.
- */
- public void setFinishingRecentsAnimationTaskId(int taskId) {
- mFinishingRecentsAnimationTaskId = taskId;
- mStateCallback.runOnceAtState(STATE_RECENTS_ANIMATION_FINISHED, () -> {
- mFinishingRecentsAnimationTaskId = -1;
- });
- }
-
- /**
* @return whether the current gesture is still running a recents animation to a state in the
* Launcher or Recents activity.
- * Updates the running task for the gesture to be the given {@param runningTask}.
*/
public boolean isRunningAnimationToLauncher() {
return isRecentsAnimationRunning() && mEndTarget != null && mEndTarget.isLauncher;
@@ -314,18 +310,13 @@
mStateCallback.setState(STATE_RECENTS_ANIMATION_ENDED);
}
- @Override
- public void onTaskAppeared(RemoteAnimationTargetCompat app) {
- mAnimationTarget = app;
- mStateCallback.setState(STATE_TASK_APPEARED_DURING_SWITCH);
- }
-
public void dump(PrintWriter pw) {
pw.println("GestureState:");
pw.println(" gestureID=" + mGestureId);
pw.println(" runningTask=" + mRunningTask);
pw.println(" endTarget=" + mEndTarget);
- pw.println(" finishingRecentsAnimationTaskId=" + mFinishingRecentsAnimationTaskId);
+ pw.println(" lastAppearedTaskTarget=" + mLastAppearedTaskTarget);
+ pw.println(" lastStartedTaskId=" + mLastStartedTaskId);
pw.println(" isRecentsAnimationRunning=" + isRecentsAnimationRunning());
}
}
diff --git a/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java b/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
index 2a9f32d..879fd1d 100644
--- a/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
+++ b/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
@@ -55,6 +55,8 @@
private static final boolean DEBUG = false;
private static final int MAX_ORIENTATIONS = 4;
+ private static final int QUICKSTEP_ROTATION_UNINITIALIZED = -1;
+
private final Matrix mTmpMatrix = new Matrix();
private final float[] mTmpPoint = new float[2];
@@ -69,9 +71,10 @@
private QuickStepContractInfo mContractInfo;
/**
- * Represents if we're currently in a swipe "session" of sorts. If value is -1, then user
- * has not tapped on an active nav region. Otherwise it will be the rotation of the display
- * when the user first interacted with the active nav bar region.
+ * Represents if we're currently in a swipe "session" of sorts. If value is
+ * QUICKSTEP_ROTATION_UNINITIALIZED, then user has not tapped on an active nav region.
+ * Otherwise it will be the rotation of the display when the user first interacted with the
+ * active nav bar region.
* The "session" ends when {@link #enableMultipleRegions(boolean, DefaultDisplay.Info)} is
* called - usually from a timeout or if user starts interacting w/ the foreground app.
*
@@ -79,7 +82,7 @@
* the rect is purely used for tracking touch interactions and usually this "session" will
* outlast the touch interaction.
*/
- private int mQuickStepStartingRotation = -1;
+ private int mQuickStepStartingRotation = QUICKSTEP_ROTATION_UNINITIALIZED;
/** For testability */
interface QuickStepContractInfo {
@@ -116,7 +119,7 @@
*/
void createOrAddTouchRegion(DefaultDisplay.Info info) {
mCurrentDisplayRotation = info.rotation;
- if (mQuickStepStartingRotation > -1
+ if (mQuickStepStartingRotation > QUICKSTEP_ROTATION_UNINITIALIZED
&& mCurrentDisplayRotation == mQuickStepStartingRotation) {
// User already was swiping and the current screen is same rotation as the starting one
// Remove active nav bars in other rotations except for the one we started out in
@@ -146,7 +149,7 @@
mEnableMultipleRegions = enableMultipleRegions &&
mMode != SysUINavigationMode.Mode.TWO_BUTTONS;
if (!enableMultipleRegions) {
- mQuickStepStartingRotation = -1;
+ mQuickStepStartingRotation = QUICKSTEP_ROTATION_UNINITIALIZED;
resetSwipeRegions(info);
}
}
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
index 7d568a4..a21c714 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
@@ -19,13 +19,11 @@
import android.graphics.Rect;
import android.util.ArraySet;
-import android.util.Log;
import androidx.annotation.BinderThread;
import androidx.annotation.UiThread;
import com.android.launcher3.Utilities;
-import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.util.Preconditions;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
@@ -41,15 +39,15 @@
com.android.systemui.shared.system.RecentsAnimationListener {
private final Set<RecentsAnimationListener> mListeners = new ArraySet<>();
- private final boolean mShouldMinimizeSplitScreen;
+ private final boolean mAllowMinimizeSplitScreen;
// TODO(141886704): Remove these references when they are no longer needed
private RecentsAnimationController mController;
private boolean mCancelled;
- public RecentsAnimationCallbacks(boolean shouldMinimizeSplitScreen) {
- mShouldMinimizeSplitScreen = shouldMinimizeSplitScreen;
+ public RecentsAnimationCallbacks(boolean allowMinimizeSplitScreen) {
+ mAllowMinimizeSplitScreen = allowMinimizeSplitScreen;
}
@UiThread
@@ -94,7 +92,7 @@
RecentsAnimationTargets targets = new RecentsAnimationTargets(appTargets,
wallpaperTargets, homeContentInsets, minimizedHomeBounds);
mController = new RecentsAnimationController(animationController,
- mShouldMinimizeSplitScreen, this::onAnimationFinished);
+ mAllowMinimizeSplitScreen, this::onAnimationFinished);
if (mCancelled) {
Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(),
@@ -161,6 +159,6 @@
/**
* Callback made when a task started from the recents is ready for an app transition.
*/
- default void onTaskAppeared(RemoteAnimationTargetCompat app) {}
+ default void onTaskAppeared(RemoteAnimationTargetCompat appearedTaskTarget) {}
}
}
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationController.java b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
index 5ece2d7..76a81eb 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationController.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
@@ -49,21 +49,22 @@
private final RecentsAnimationControllerCompat mController;
private final Consumer<RecentsAnimationController> mOnFinishedListener;
- private final boolean mShouldMinimizeSplitScreen;
+ private final boolean mAllowMinimizeSplitScreen;
private InputConsumerController mInputConsumerController;
private Supplier<InputConsumer> mInputProxySupplier;
private InputConsumer mInputConsumer;
- private boolean mWindowThresholdCrossed = false;
+ private boolean mUseLauncherSysBarFlags = false;
+ private boolean mSplitScreenMinimized = false;
private boolean mTouchInProgress;
private boolean mFinishPending;
public RecentsAnimationController(RecentsAnimationControllerCompat controller,
- boolean shouldMinimizeSplitScreen,
+ boolean allowMinimizeSplitScreen,
Consumer<RecentsAnimationController> onFinishedListener) {
mController = controller;
mOnFinishedListener = onFinishedListener;
- mShouldMinimizeSplitScreen = shouldMinimizeSplitScreen;
+ mAllowMinimizeSplitScreen = allowMinimizeSplitScreen;
}
/**
@@ -76,16 +77,31 @@
/**
* Indicates that the gesture has crossed the window boundary threshold and system UI can be
- * update the represent the window behind
+ * update the system bar flags accordingly.
*/
- public void setWindowThresholdCrossed(boolean windowThresholdCrossed) {
- if (mWindowThresholdCrossed != windowThresholdCrossed) {
- mWindowThresholdCrossed = windowThresholdCrossed;
+ public void setUseLauncherSystemBarFlags(boolean useLauncherSysBarFlags) {
+ if (mUseLauncherSysBarFlags != useLauncherSysBarFlags) {
+ mUseLauncherSysBarFlags = useLauncherSysBarFlags;
UI_HELPER_EXECUTOR.execute(() -> {
- mController.setAnimationTargetsBehindSystemBars(!windowThresholdCrossed);
+ mController.setAnimationTargetsBehindSystemBars(!useLauncherSysBarFlags);
+ });
+ }
+ }
+
+ /**
+ * Indicates that the gesture has crossed the window boundary threshold and we should minimize
+ * if we are in splitscreen.
+ */
+ public void setSplitScreenMinimized(boolean splitScreenMinimized) {
+ if (!mAllowMinimizeSplitScreen) {
+ return;
+ }
+ if (mSplitScreenMinimized != splitScreenMinimized) {
+ mSplitScreenMinimized = splitScreenMinimized;
+ UI_HELPER_EXECUTOR.execute(() -> {
SystemUiProxy p = SystemUiProxy.INSTANCE.getNoCreate();
- if (p != null && mShouldMinimizeSplitScreen) {
- p.setSplitScreenMinimized(windowThresholdCrossed);
+ if (p != null) {
+ p.setSplitScreenMinimized(splitScreenMinimized);
}
});
}
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
index a6ce2b5..8ac15e8 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
@@ -17,6 +17,7 @@
import static android.content.Intent.ACTION_USER_UNLOCKED;
+import static com.android.launcher3.util.DefaultDisplay.CHANGE_ALL;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
import static com.android.quickstep.SysUINavigationMode.Mode.THREE_BUTTONS;
@@ -216,6 +217,7 @@
mDefaultDisplay.removeChangeListener(this);
if (newMode.hasGestures) {
mDefaultDisplay.addChangeListener(this);
+ onDisplayInfoChanged(mDefaultDisplay.getInfo(), CHANGE_ALL);
}
if (newMode == NO_BUTTON) {
@@ -511,14 +513,12 @@
void enableMultipleRegions(boolean enable) {
mOrientationTouchTransformer.enableMultipleRegions(enable, mDefaultDisplay.getInfo());
- if (enable) {
- UI_HELPER_EXECUTOR.execute(() -> {
- int quickStepStartingRotation =
- mOrientationTouchTransformer.getQuickStepStartingRotation();
- SystemUiProxy.INSTANCE.get(mContext)
- .onQuickSwitchToNewTask(quickStepStartingRotation);
- });
- }
+ UI_HELPER_EXECUTOR.execute(() -> {
+ int quickStepStartingRotation =
+ mOrientationTouchTransformer.getQuickStepStartingRotation();
+ SystemUiProxy.INSTANCE.get(mContext)
+ .onQuickSwitchToNewTask(quickStepStartingRotation);
+ });
}
public int getCurrentActiveRotation() {
diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
index bbca568..cad51f4 100644
--- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java
+++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
@@ -18,6 +18,7 @@
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.quickstep.GestureState.STATE_RECENTS_ANIMATION_INITIALIZED;
+import static com.android.quickstep.GestureState.STATE_RECENTS_ANIMATION_STARTED;
import android.content.Intent;
import android.util.Log;
@@ -26,9 +27,9 @@
import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.testing.TestProtocol;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAnimationListener {
@@ -37,6 +38,7 @@
private RecentsAnimationTargets mTargets;
// Temporary until we can hook into gesture state events
private GestureState mLastGestureState;
+ private RemoteAnimationTargetCompat mLastAppearedTaskTarget;
/**
* Preloads the recents animation.
@@ -67,13 +69,21 @@
final BaseActivityInterface activityInterface = gestureState.getActivityInterface();
mLastGestureState = gestureState;
- mCallbacks = new RecentsAnimationCallbacks(activityInterface.shouldMinimizeSplitScreen());
+ mCallbacks = new RecentsAnimationCallbacks(activityInterface.allowMinimizeSplitScreen());
mCallbacks.addListener(new RecentsAnimationCallbacks.RecentsAnimationListener() {
@Override
public void onRecentsAnimationStart(RecentsAnimationController controller,
RecentsAnimationTargets targets) {
+ if (mCallbacks == null) {
+ // It's possible for the recents animation to have finished and be cleaned up
+ // by the time we process the start callback, and in that case, just we can skip
+ // handling this call entirely
+ return;
+ }
mController = controller;
mTargets = targets;
+ mLastAppearedTaskTarget = mTargets.findTask(mLastGestureState.getRunningTaskId());
+ mLastGestureState.updateLastAppearedTaskTarget(mLastAppearedTaskTarget);
}
@Override
@@ -91,6 +101,20 @@
public void onRecentsAnimationFinished(RecentsAnimationController controller) {
cleanUpRecentsAnimation(null /* canceledThumbnail */);
}
+
+ @Override
+ public void onTaskAppeared(RemoteAnimationTargetCompat appearedTaskTarget) {
+ if (mController != null) {
+ if (mLastAppearedTaskTarget == null
+ || appearedTaskTarget.taskId != mLastAppearedTaskTarget.taskId) {
+ if (mLastAppearedTaskTarget != null) {
+ mController.removeTaskTarget(mLastAppearedTaskTarget);
+ }
+ mLastAppearedTaskTarget = appearedTaskTarget;
+ mLastGestureState.updateLastAppearedTaskTarget(mLastAppearedTaskTarget);
+ }
+ }
+ }
});
mCallbacks.addListener(gestureState);
mCallbacks.addListener(listener);
@@ -107,6 +131,9 @@
mCallbacks.removeListener(mLastGestureState);
mLastGestureState = gestureState;
mCallbacks.addListener(gestureState);
+ gestureState.setState(STATE_RECENTS_ANIMATION_INITIALIZED
+ | STATE_RECENTS_ANIMATION_STARTED);
+ gestureState.updateLastAppearedTaskTarget(mLastAppearedTaskTarget);
return mCallbacks;
}
@@ -166,6 +193,7 @@
mCallbacks = null;
mTargets = null;
mLastGestureState = null;
+ mLastAppearedTaskTarget = null;
}
public void dump() {
diff --git a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
index fe95e83..f3cefb9 100644
--- a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
@@ -75,9 +75,6 @@
@Override
Integer getActionTextButtonStringId() {
- if (mTutorialType == BACK_NAVIGATION_COMPLETE) {
- return R.string.gesture_tutorial_action_text_button_label;
- }
return null;
}
diff --git a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
index ac2200d..a98aad1 100644
--- a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
+++ b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
@@ -16,17 +16,17 @@
package com.android.quickstep.logging;
-import static android.stats.launcher.nano.Launcher.ALLAPPS;
-import static android.stats.launcher.nano.Launcher.BACKGROUND;
-import static android.stats.launcher.nano.Launcher.HOME;
-import static android.stats.launcher.nano.Launcher.OVERVIEW;
+import static com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.FOLDER;
+import static com.android.launcher3.logger.LauncherAtom.ItemInfo.ItemCase.WIDGET;
import android.content.Context;
+import android.util.Log;
import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.Utilities;
import com.android.launcher3.logger.LauncherAtom;
+import com.android.launcher3.logging.InstanceId;
import com.android.launcher3.logging.StatsLogManager;
-import com.android.launcher3.logging.StatsLogUtils;
import com.android.launcher3.model.AllAppsList;
import com.android.launcher3.model.BaseModelUpdateTask;
import com.android.launcher3.model.BgDataModel;
@@ -34,11 +34,13 @@
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.util.IntSparseArrayMap;
+import com.android.launcher3.util.LogConfig;
+import com.android.systemui.shared.system.SysUiStatsLog;
import java.util.ArrayList;
/**
- * This method calls the StatsLog hidden method until they are made available public.
+ * This class calls StatsLog compile time generated methods.
*
* To see if the logs are properly sent to statsd, execute following command.
* $ adb root && adb shell statsd
@@ -47,34 +49,69 @@
*/
public class StatsLogCompatManager extends StatsLogManager {
- private static final int SUPPORTED_TARGET_DEPTH = 2;
private static final String TAG = "StatsLog";
- private static final boolean DEBUG = false;
+ private static final boolean IS_VERBOSE = Utilities.isPropertyEnabled(LogConfig.STATSLOG);
+
private static Context sContext;
+ private static final int DEFAULT_WIDGET_SPAN_XY = 1;
+ private static final int DEFAULT_WORKSPACE_GRID_XY = -1;
+ private static final int DEFAULT_PAGE_INDEX = -2;
+ private static final InstanceId DEFAULT_INSTANCE_ID = InstanceId.fakeInstanceId(0);
+
public StatsLogCompatManager(Context context) {
sContext = context;
}
- @Override
- public void log(LauncherEvent eventId, LauncherAtom.ItemInfo item) {
- // Call StatsLog method
+ /**
+ * Logs an event and accompanying {@link ItemInfo}
+ */
+ public void log(LauncherEvent event, LauncherAtom.ItemInfo itemInfo) {
+ log(event, DEFAULT_INSTANCE_ID, itemInfo);
}
+ /**
+ * Logs an event and accompanying {@link LauncherAtom.ItemInfo}
+ */
@Override
- public void verify() {
- if (!(StatsLogUtils.LAUNCHER_STATE_ALLAPPS == ALLAPPS
- && StatsLogUtils.LAUNCHER_STATE_BACKGROUND == BACKGROUND
- && StatsLogUtils.LAUNCHER_STATE_OVERVIEW == OVERVIEW
- && StatsLogUtils.LAUNCHER_STATE_HOME == HOME)) {
- throw new IllegalStateException(
- "StatsLogUtil constants doesn't match enums in launcher.proto");
+ public void log(LauncherEvent event, InstanceId instanceId, LauncherAtom.ItemInfo itemInfo) {
+ if (IS_VERBOSE) {
+ Log.d(TAG, String.format("\n%s\n%s", event.name(), itemInfo));
}
+ if (!Utilities.ATLEAST_R) {
+ return;
+ }
+ SysUiStatsLog.write(SysUiStatsLog.LAUNCHER_EVENT,
+ SysUiStatsLog.LAUNCHER_UICHANGED__ACTION__DEFAULT_ACTION /* deprecated */,
+ SysUiStatsLog.LAUNCHER_UICHANGED__DST_STATE__HOME /* TODO */,
+ SysUiStatsLog.LAUNCHER_UICHANGED__DST_STATE__BACKGROUND /* TODO */,
+ null /* launcher extensions, deprecated */,
+ false /* quickstep_enabled, deprecated */,
+ event.getId() /* event_id */,
+ itemInfo.getItemCase().getNumber() /* target_id */,
+ instanceId.getId() /* instance_id TODO */,
+ 0 /* uid TODO */,
+ getPackageName(itemInfo) /* package_name */,
+ getComponentName(itemInfo) /* component_name */,
+ getGridX(itemInfo, false) /* grid_x */,
+ getGridY(itemInfo, false) /* grid_y */,
+ getPageId(itemInfo, false) /* page_id */,
+ getGridX(itemInfo, true) /* grid_x_parent */,
+ getGridY(itemInfo, true) /* grid_y_parent */,
+ getPageId(itemInfo, true) /* page_id_parent */,
+ getHierarchy(itemInfo) /* hierarchy */,
+ itemInfo.getIsWork() /* is_work_profile */,
+ itemInfo.getRank() /* rank */,
+ 0 /* fromState */,
+ 0 /* toState */,
+ null /* edittext */,
+ 0 /* cardinality */);
}
/**
* Logs the workspace layout information on the model thread.
*/
+ @Override
public void logSnapshot() {
LauncherAppState.getInstance(sContext).getModel().enqueueModelUpdateTask(
new SnapshotWorker());
@@ -88,19 +125,161 @@
ArrayList<LauncherAppWidgetInfo> appWidgets = (ArrayList) dataModel.appWidgets.clone();
for (ItemInfo info : workspaceItems) {
- LauncherAtom.ItemInfo atomInfo = info.buildProto(null, null);
- // call StatsLog method
+ LauncherAtom.ItemInfo atomInfo = info.buildProto(null);
+ writeSnapshot(atomInfo);
}
for (FolderInfo fInfo : folders) {
for (ItemInfo info : fInfo.contents) {
- LauncherAtom.ItemInfo atomInfo = info.buildProto(null, fInfo);
- // call StatsLog method
+ LauncherAtom.ItemInfo atomInfo = info.buildProto(fInfo);
+ writeSnapshot(atomInfo);
}
}
for (ItemInfo info : appWidgets) {
- LauncherAtom.ItemInfo atomInfo = info.buildProto(null, null);
- // call StatsLog method
+ LauncherAtom.ItemInfo atomInfo = info.buildProto(null);
+ writeSnapshot(atomInfo);
}
}
}
+ private static void writeSnapshot(LauncherAtom.ItemInfo itemInfo) {
+ if (IS_VERBOSE) {
+ Log.d(TAG, "\nwriteSnapshot:" + itemInfo);
+ }
+ if (!Utilities.ATLEAST_R) {
+ return;
+ }
+ SysUiStatsLog.write(SysUiStatsLog.LAUNCHER_SNAPSHOT,
+ 0 /* event_id */,
+ itemInfo.getItemCase().getNumber() /* target_id */,
+ 0 /* instance_id */,
+ 0 /* uid */,
+ getPackageName(itemInfo) /* package_name */,
+ getComponentName(itemInfo) /* component_name */,
+ getGridX(itemInfo, false) /* grid_x */,
+ getGridY(itemInfo, false) /* grid_y */,
+ getPageId(itemInfo, false) /* page_id */,
+ getGridX(itemInfo, true) /* grid_x_parent */,
+ getGridY(itemInfo, true) /* grid_y_parent */,
+ getPageId(itemInfo, true) /* page_id_parent */,
+ getHierarchy(itemInfo) /* hierarchy */,
+ itemInfo.getIsWork() /* is_work_profile */,
+ 0 /* origin TODO */,
+ 0 /* cardinality */,
+ getSpanX(itemInfo),
+ getSpanY(itemInfo));
+ }
+
+ private static int getSpanX(LauncherAtom.ItemInfo atomInfo) {
+ if (atomInfo.getItemCase() != WIDGET) {
+ return DEFAULT_WIDGET_SPAN_XY;
+ }
+ return atomInfo.getWidget().getSpanX();
+ }
+
+ private static int getSpanY(LauncherAtom.ItemInfo atomInfo) {
+ if (atomInfo.getItemCase() != WIDGET) {
+ return DEFAULT_WIDGET_SPAN_XY;
+ }
+ return atomInfo.getWidget().getSpanY();
+ }
+
+ private static String getPackageName(LauncherAtom.ItemInfo atomInfo) {
+ switch (atomInfo.getItemCase()) {
+ case APPLICATION:
+ return atomInfo.getApplication().getPackageName();
+ case SHORTCUT:
+ return atomInfo.getShortcut().getShortcutName();
+ case WIDGET:
+ return atomInfo.getWidget().getPackageName();
+ case TASK:
+ return atomInfo.getTask().getPackageName();
+ default:
+ return null;
+ }
+ }
+
+ private static String getComponentName(LauncherAtom.ItemInfo atomInfo) {
+ switch (atomInfo.getItemCase()) {
+ case APPLICATION:
+ return atomInfo.getApplication().getComponentName();
+ case SHORTCUT:
+ return atomInfo.getShortcut().getShortcutName();
+ case WIDGET:
+ return atomInfo.getWidget().getComponentName();
+ case TASK:
+ return atomInfo.getTask().getComponentName();
+ default:
+ return null;
+ }
+ }
+
+ private static int getGridX(LauncherAtom.ItemInfo info, boolean parent) {
+ switch (info.getContainerInfo().getContainerCase()) {
+ case WORKSPACE:
+ if (parent) {
+ return DEFAULT_WORKSPACE_GRID_XY;
+ } else {
+ return info.getContainerInfo().getWorkspace().getGridX();
+ }
+ case FOLDER:
+ if (parent) {
+ switch (info.getContainerInfo().getFolder().getParentContainerCase()) {
+ case WORKSPACE:
+ return info.getContainerInfo().getFolder().getWorkspace().getGridX();
+ default:
+ return DEFAULT_WORKSPACE_GRID_XY;
+ }
+ } else {
+ return info.getContainerInfo().getFolder().getGridX();
+ }
+ default:
+ return DEFAULT_WORKSPACE_GRID_XY;
+ }
+ }
+
+ private static int getGridY(LauncherAtom.ItemInfo info, boolean parent) {
+ switch (info.getContainerInfo().getContainerCase()) {
+ case WORKSPACE:
+ if (parent) {
+ return DEFAULT_WORKSPACE_GRID_XY;
+ } else {
+ return info.getContainerInfo().getWorkspace().getGridY();
+ }
+ case FOLDER:
+ if (parent) {
+ switch (info.getContainerInfo().getFolder().getParentContainerCase()) {
+ case WORKSPACE:
+ return info.getContainerInfo().getFolder().getWorkspace().getGridY();
+ default:
+ return DEFAULT_WORKSPACE_GRID_XY;
+ }
+ } else {
+ return info.getContainerInfo().getFolder().getGridY();
+ }
+ default:
+ return DEFAULT_WORKSPACE_GRID_XY;
+ }
+ }
+
+ private static int getPageId(LauncherAtom.ItemInfo info, boolean parent) {
+ switch (info.getContainerInfo().getContainerCase()) {
+ case HOTSEAT:
+ return info.getContainerInfo().getHotseat().getIndex();
+ case WORKSPACE:
+ return info.getContainerInfo().getWorkspace().getPageIndex();
+ default:
+ return DEFAULT_PAGE_INDEX;
+ }
+ }
+
+ /**
+ *
+ */
+ private static int getHierarchy(LauncherAtom.ItemInfo info) {
+ // TODO
+ if (info.getContainerInfo().getContainerCase() == FOLDER) {
+ return info.getContainerInfo().getFolder().getParentContainerCase().getNumber() + 100;
+ } else {
+ return info.getContainerInfo().getContainerCase().getNumber();
+ }
+ }
}
diff --git a/quickstep/src/com/android/quickstep/util/LayoutUtils.java b/quickstep/src/com/android/quickstep/util/LayoutUtils.java
index 4edf2fb..fa53be2 100644
--- a/quickstep/src/com/android/quickstep/util/LayoutUtils.java
+++ b/quickstep/src/com/android/quickstep/util/LayoutUtils.java
@@ -17,31 +17,19 @@
import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS;
import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview;
-
-import static java.lang.annotation.RetentionPolicy.SOURCE;
+import static com.android.quickstep.util.WindowSizeStrategy.LAUNCHER_ACTIVITY_SIZE_STRATEGY;
import android.content.Context;
-import android.content.res.Resources;
import android.graphics.Rect;
-
-import androidx.annotation.AnyThread;
-import androidx.annotation.IntDef;
+import android.view.View;
+import android.view.ViewGroup;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.quickstep.SysUINavigationMode;
-import java.lang.annotation.Retention;
-
public class LayoutUtils {
- private static final int MULTI_WINDOW_STRATEGY_HALF_SCREEN = 1;
- private static final int MULTI_WINDOW_STRATEGY_DEVICE_PROFILE = 2;
-
- @Retention(SOURCE)
- @IntDef({MULTI_WINDOW_STRATEGY_HALF_SCREEN, MULTI_WINDOW_STRATEGY_DEVICE_PROFILE})
- private @interface MultiWindowStrategy {}
-
/**
* The height for the swipe up motion
*/
@@ -53,112 +41,11 @@
return swipeHeight;
}
- public static void calculateLauncherTaskSize(Context context, DeviceProfile dp, Rect outRect) {
- float extraSpace;
- if (dp.isVerticalBarLayout()) {
- extraSpace = 0;
- } else {
- Resources res = context.getResources();
-
- if (ENABLE_OVERVIEW_ACTIONS.get() && removeShelfFromOverview(context)) {
- //TODO: this needs to account for the swipe gesture height and accessibility
- // UI when shown.
- extraSpace = res.getDimensionPixelSize(R.dimen.overview_actions_height);
- } else {
- extraSpace = getDefaultSwipeHeight(context, dp) + dp.workspacePageIndicatorHeight
- + res.getDimensionPixelSize(
- R.dimen.dynamic_grid_hotseat_extra_vertical_size)
- + res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_bottom_padding);
- }
- }
- calculateTaskSize(context, dp, extraSpace, MULTI_WINDOW_STRATEGY_HALF_SCREEN, outRect);
- }
-
- public static void calculateFallbackTaskSize(Context context, DeviceProfile dp, Rect outRect) {
- float extraSpace;
- if (ENABLE_OVERVIEW_ACTIONS.get() && removeShelfFromOverview(context)) {
- extraSpace = context.getResources()
- .getDimensionPixelSize(R.dimen.overview_actions_height);
- } else {
- extraSpace = 0;
- }
- calculateTaskSize(context, dp, extraSpace, MULTI_WINDOW_STRATEGY_DEVICE_PROFILE, outRect);
- }
-
- @AnyThread
- public static void calculateTaskSize(Context context, DeviceProfile dp,
- float extraVerticalSpace, @MultiWindowStrategy int multiWindowStrategy, Rect outRect) {
- float taskWidth, taskHeight, paddingHorz;
- Resources res = context.getResources();
- Rect insets = dp.getInsets();
- final boolean overviewActionsEnabled = ENABLE_OVERVIEW_ACTIONS.get();
-
- if (dp.isMultiWindowMode) {
- if (multiWindowStrategy == MULTI_WINDOW_STRATEGY_HALF_SCREEN) {
- DeviceProfile fullDp = dp.getFullScreenProfile();
- // Use availableWidthPx and availableHeightPx instead of widthPx and heightPx to
- // account for system insets
- taskWidth = fullDp.availableWidthPx;
- taskHeight = fullDp.availableHeightPx;
- float halfDividerSize = res.getDimension(R.dimen.multi_window_task_divider_size)
- / 2;
-
- if (fullDp.isLandscape) {
- taskWidth = taskWidth / 2 - halfDividerSize;
- } else {
- taskHeight = taskHeight / 2 - halfDividerSize;
- }
- } else {
- // multiWindowStrategy == MULTI_WINDOW_STRATEGY_DEVICE_PROFILE
- taskWidth = dp.widthPx;
- taskHeight = dp.heightPx;
- }
- paddingHorz = res.getDimension(R.dimen.multi_window_task_card_horz_space);
- } else {
- taskWidth = dp.availableWidthPx;
- taskHeight = dp.availableHeightPx;
-
- final int paddingResId;
- if (dp.isVerticalBarLayout()) {
- paddingResId = R.dimen.landscape_task_card_horz_space;
- } else if (overviewActionsEnabled && removeShelfFromOverview(context)) {
- paddingResId = R.dimen.portrait_task_card_horz_space_big_overview;
- } else {
- paddingResId = R.dimen.portrait_task_card_horz_space;
- }
- paddingHorz = res.getDimension(paddingResId);
- }
-
- float topIconMargin = res.getDimension(R.dimen.task_thumbnail_top_margin);
- float paddingVert = overviewActionsEnabled && removeShelfFromOverview(context)
- ? 0 : res.getDimension(R.dimen.task_card_vert_space);
-
- // Note this should be same as dp.availableWidthPx and dp.availableHeightPx unless
- // we override the insets ourselves.
- int launcherVisibleWidth = dp.widthPx - insets.left - insets.right;
- int launcherVisibleHeight = dp.heightPx - insets.top - insets.bottom;
-
- float availableHeight = launcherVisibleHeight
- - topIconMargin - extraVerticalSpace - paddingVert;
- float availableWidth = launcherVisibleWidth - paddingHorz;
-
- float scale = Math.min(availableWidth / taskWidth, availableHeight / taskHeight);
- float outWidth = scale * taskWidth;
- float outHeight = scale * taskHeight;
-
- // Center in the visible space
- float x = insets.left + (launcherVisibleWidth - outWidth) / 2;
- float y = insets.top + Math.max(topIconMargin,
- (launcherVisibleHeight - extraVerticalSpace - outHeight) / 2);
- outRect.set(Math.round(x), Math.round(y),
- Math.round(x) + Math.round(outWidth), Math.round(y) + Math.round(outHeight));
- }
-
public static int getShelfTrackingDistance(Context context, DeviceProfile dp) {
// Track the bottom of the window.
if (ENABLE_OVERVIEW_ACTIONS.get() && removeShelfFromOverview(context)) {
Rect taskSize = new Rect();
- calculateLauncherTaskSize(context, dp, taskSize);
+ LAUNCHER_ACTIVITY_SIZE_STRATEGY.calculateTaskSize(context, dp, taskSize);
return (dp.heightPx - taskSize.height()) / 2;
}
int shelfHeight = dp.hotseatBarSizePx + dp.getInsets().bottom;
@@ -169,6 +56,7 @@
/**
* Gets the scale that should be applied to the TaskView so that it matches the target
+ * TODO: Remove this method
*/
public static float getTaskScale(RecentsOrientedState orientedState,
float srcWidth, float srcHeight, float targetWidth, float targetHeight) {
@@ -180,4 +68,21 @@
return srcHeight / targetHeight;
}
}
+
+ /**
+ * Recursively sets view and all children enabled/disabled.
+ * @param viewGroup Top most parent view to change.
+ * @param enabled True = enable, False = disable.
+ */
+ public static void setViewEnabled(ViewGroup viewGroup, boolean enabled) {
+ viewGroup.setEnabled(enabled);
+ for (int i = 0; i < viewGroup.getChildCount(); i++) {
+ View child = viewGroup.getChildAt(i);
+ if (child instanceof ViewGroup) {
+ setViewEnabled((ViewGroup) child, enabled);
+ } else {
+ child.setEnabled(enabled);
+ }
+ }
+ }
}
diff --git a/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java b/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java
index 7d52571..a5d4568 100644
--- a/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java
+++ b/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java
@@ -19,11 +19,13 @@
import android.content.Context;
import android.content.res.Resources;
+import android.util.Log;
import android.view.MotionEvent;
import com.android.launcher3.Alarm;
import com.android.launcher3.R;
import com.android.launcher3.compat.AccessibilityManagerCompat;
+import com.android.launcher3.testing.TestProtocol;
/**
* Given positions along x- or y-axis, tracks velocity and acceleration and determines when there is
@@ -84,6 +86,9 @@
mSpeedSlow = res.getDimension(R.dimen.motion_pause_detector_speed_slow);
mSpeedSomewhatFast = res.getDimension(R.dimen.motion_pause_detector_speed_somewhat_fast);
mSpeedFast = res.getDimension(R.dimen.motion_pause_detector_speed_fast);
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.PAUSE_NOT_DETECTED, "creating alarm");
+ }
mForcePauseTimeout = new Alarm();
mForcePauseTimeout.setOnAlarmListener(alarm -> updatePaused(true /* isPaused */));
mMakePauseHarderToTrigger = makePauseHarderToTrigger;
@@ -120,6 +125,9 @@
* @param pointerIndex Index for the pointer being tracked in the motion event
*/
public void addPosition(MotionEvent ev, int pointerIndex) {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.PAUSE_NOT_DETECTED, "setting alarm");
+ }
mForcePauseTimeout.setAlarm(mMakePauseHarderToTrigger
? HARDER_TRIGGER_TIMEOUT
: FORCE_PAUSE_TIMEOUT);
@@ -167,6 +175,9 @@
}
private void updatePaused(boolean isPaused) {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.PAUSE_NOT_DETECTED, "updatePaused: " + isPaused);
+ }
if (mDisallowPause) {
isPaused = false;
}
@@ -188,6 +199,9 @@
setOnMotionPauseListener(null);
mIsPaused = mHasEverBeenPaused = false;
mSlowStartTime = 0;
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.PAUSE_NOT_DETECTED, "canceling alarm");
+ }
mForcePauseTimeout.cancelAlarm();
}
diff --git a/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java b/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java
index aa6d56a..2d8bba2 100644
--- a/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java
+++ b/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java
@@ -25,8 +25,8 @@
import com.android.launcher3.BaseQuickstepLauncher;
import com.android.launcher3.LauncherState;
-import com.android.launcher3.LauncherStateManager;
-import com.android.launcher3.LauncherStateManager.StateListener;
+import com.android.launcher3.statemanager.StateManager;
+import com.android.launcher3.statemanager.StateManager.StateListener;
import com.android.launcher3.util.OnboardingPrefs;
import com.android.quickstep.SysUINavigationMode;
@@ -35,23 +35,23 @@
*/
public class QuickstepOnboardingPrefs extends OnboardingPrefs<BaseQuickstepLauncher> {
- public QuickstepOnboardingPrefs(BaseQuickstepLauncher launcher, SharedPreferences sharedPrefs,
- LauncherStateManager stateManager) {
- super(launcher, sharedPrefs, stateManager);
+ public QuickstepOnboardingPrefs(BaseQuickstepLauncher launcher, SharedPreferences sharedPrefs) {
+ super(launcher, sharedPrefs);
+ StateManager<LauncherState> stateManager = launcher.getStateManager();
if (!getBoolean(HOME_BOUNCE_SEEN)) {
- mStateManager.addStateListener(new StateListener() {
+ stateManager.addStateListener(new StateListener<LauncherState>() {
@Override
public void onStateTransitionComplete(LauncherState finalState) {
boolean swipeUpEnabled = SysUINavigationMode.INSTANCE
.get(mLauncher).getMode().hasGestures;
- LauncherState prevState = mStateManager.getLastState();
+ LauncherState prevState = stateManager.getLastState();
if (((swipeUpEnabled && finalState == OVERVIEW) || (!swipeUpEnabled
&& finalState == ALL_APPS && prevState == NORMAL) ||
hasReachedMaxCount(HOME_BOUNCE_COUNT))) {
mSharedPrefs.edit().putBoolean(HOME_BOUNCE_SEEN, true).apply();
- mStateManager.removeStateListener(this);
+ stateManager.removeStateListener(this);
}
}
});
@@ -65,27 +65,27 @@
mSharedPrefs.edit().putBoolean(SHELF_BOUNCE_SEEN, shelfBounceSeen).apply();
}
if (!shelfBounceSeen) {
- mStateManager.addStateListener(new StateListener() {
+ stateManager.addStateListener(new StateListener<LauncherState>() {
@Override
public void onStateTransitionComplete(LauncherState finalState) {
- LauncherState prevState = mStateManager.getLastState();
+ LauncherState prevState = stateManager.getLastState();
if ((finalState == ALL_APPS && prevState == OVERVIEW) ||
hasReachedMaxCount(SHELF_BOUNCE_COUNT)) {
mSharedPrefs.edit().putBoolean(SHELF_BOUNCE_SEEN, true).apply();
- mStateManager.removeStateListener(this);
+ stateManager.removeStateListener(this);
}
}
});
}
if (!hasReachedMaxCount(ALL_APPS_COUNT)) {
- mStateManager.addStateListener(new StateListener() {
+ stateManager.addStateListener(new StateListener<LauncherState>() {
@Override
public void onStateTransitionComplete(LauncherState finalState) {
if (finalState == ALL_APPS) {
if (incrementEventCount(ALL_APPS_COUNT)) {
- mStateManager.removeStateListener(this);
+ stateManager.removeStateListener(this);
mLauncher.getScrimView().updateDragHandleVisibility();
}
}
diff --git a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
index 74daeca..fffbb34 100644
--- a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
+++ b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
@@ -17,11 +17,13 @@
package com.android.quickstep.util;
import static android.util.DisplayMetrics.DENSITY_DEVICE_STABLE;
+import static android.view.OrientationEventListener.ORIENTATION_UNKNOWN;
import static android.view.Surface.ROTATION_0;
import static android.view.Surface.ROTATION_180;
import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;
+import static com.android.launcher3.logging.LoggerUtils.extractObjectNameAndAddress;
import static com.android.launcher3.states.RotationHelper.ALLOW_ROTATION_PREFERENCE_KEY;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
@@ -35,7 +37,6 @@
import android.graphics.Matrix;
import android.graphics.PointF;
import android.graphics.Rect;
-import android.graphics.RectF;
import android.os.Handler;
import android.provider.Settings;
import android.util.Log;
@@ -44,6 +45,7 @@
import android.view.Surface;
import androidx.annotation.IntDef;
+import androidx.annotation.NonNull;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Utilities;
@@ -64,7 +66,7 @@
public final class RecentsOrientedState implements SharedPreferences.OnSharedPreferenceChangeListener {
private static final String TAG = "RecentsOrientedState";
- private static final boolean DEBUG = false;
+ private static final boolean DEBUG = true;
private static final String FIXED_ROTATION_TRANSFORM_SETTING_NAME = "fixed_rotation_transform";
@@ -82,7 +84,7 @@
private @SurfaceRotation int mTouchRotation = ROTATION_0;
private @SurfaceRotation int mDisplayRotation = ROTATION_0;
- private @SurfaceRotation int mLauncherRotation = Surface.ROTATION_0;
+ private @SurfaceRotation int mLauncherRotation = ROTATION_0;
// Launcher activity supports multiple orientation, but fallback activity does not
private static final int FLAG_MULTIPLE_ORIENTATION_SUPPORTED_BY_ACTIVITY = 1 << 0;
@@ -94,31 +96,33 @@
private static final int FLAG_HOME_ROTATION_ALLOWED_IN_PREFS = 1 << 3;
// If the user has enabled system rotation
private static final int FLAG_SYSTEM_ROTATION_ALLOWED = 1 << 4;
+ // Multiple orientation is not supported in multiwindow mode
+ private static final int FLAG_MULTIWINDOW_ROTATION_ALLOWED = 1 << 5;
// Whether to rotation sensor is supported on the device
- private static final int FLAG_ROTATION_WATCHER_SUPPORTED = 1 << 5;
+ private static final int FLAG_ROTATION_WATCHER_SUPPORTED = 1 << 6;
// Whether to enable rotation watcher when multi-rotation is supported
- private static final int FLAG_ROTATION_WATCHER_ENABLED = 1 << 6;
+ private static final int FLAG_ROTATION_WATCHER_ENABLED = 1 << 7;
+ // Enable home rotation for UI tests, ignoring home rotation value from prefs
+ private static final int FLAG_HOME_ROTATION_FORCE_ENABLED_FOR_TESTING = 1 << 8;
private static final int MASK_MULTIPLE_ORIENTATION_SUPPORTED_BY_DEVICE =
FLAG_MULTIPLE_ORIENTATION_SUPPORTED_BY_ACTIVITY
| FLAG_MULTIPLE_ORIENTATION_SUPPORTED_BY_DENSITY
| FLAG_MULTIPLE_ORIENTATION_SUPPORTED_BY_FLAG;
- private static final int MASK_ACTIVITY_ROTATING =
- FLAG_HOME_ROTATION_ALLOWED_IN_PREFS | FLAG_SYSTEM_ROTATION_ALLOWED;
-
- // State for which rotation watcher will be enabled.
- // We skip it when home rotation is enabled as in that case, activity itself rotates
+ // State for which rotation watcher will be enabled. We skip it when home rotation or
+ // multi-window is enabled as in that case, activity itself rotates.
private static final int VALUE_ROTATION_WATCHER_ENABLED =
MASK_MULTIPLE_ORIENTATION_SUPPORTED_BY_DEVICE | FLAG_SYSTEM_ROTATION_ALLOWED
| FLAG_ROTATION_WATCHER_SUPPORTED | FLAG_ROTATION_WATCHER_ENABLED;
+ private final Context mContext;
private final ContentResolver mContentResolver;
private final SharedPreferences mSharedPrefs;
private final OrientationEventListener mOrientationListener;
+ private final WindowSizeStrategy mSizeStrategy;
private final Matrix mTmpMatrix = new Matrix();
- private final Matrix mTmpInverseMatrix = new Matrix();
private int mFlags;
private int mPreviousRotation = ROTATION_0;
@@ -128,14 +132,16 @@
* is enabled
* @see #setRotationWatcherEnabled(boolean)
*/
- public RecentsOrientedState(Context context, boolean rotationSupportedByActivity,
+ public RecentsOrientedState(Context context, WindowSizeStrategy sizeStrategy,
IntConsumer rotationChangeListener) {
+ mContext = context;
mContentResolver = context.getContentResolver();
mSharedPrefs = Utilities.getPrefs(context);
+ mSizeStrategy = sizeStrategy;
mOrientationListener = new OrientationEventListener(context) {
@Override
public void onOrientationChanged(int degrees) {
- int newRotation = getRotationForUserDegreesRotated(degrees);
+ int newRotation = getRotationForUserDegreesRotated(degrees, mPreviousRotation);
if (newRotation != mPreviousRotation) {
mPreviousRotation = newRotation;
rotationChangeListener.accept(newRotation);
@@ -143,7 +149,8 @@
}
};
- mFlags = rotationSupportedByActivity ? FLAG_MULTIPLE_ORIENTATION_SUPPORTED_BY_ACTIVITY : 0;
+ mFlags = sizeStrategy.rotationSupportedByActivity
+ ? FLAG_MULTIPLE_ORIENTATION_SUPPORTED_BY_ACTIVITY : 0;
Resources res = context.getResources();
int originalSmallestWidth = res.getConfiguration().smallestScreenWidthDp
@@ -157,6 +164,17 @@
if (mOrientationListener.canDetectOrientation()) {
mFlags |= FLAG_ROTATION_WATCHER_SUPPORTED;
}
+
+ // initialize external flags
+ updateAutoRotateSetting();
+ updateHomeRotationSetting();
+ }
+
+ /**
+ * Sets if the host is in multi-window mode
+ */
+ public void setMultiWindowMode(boolean isMultiWindow) {
+ setFlag(FLAG_MULTIWINDOW_ROTATION_ALLOWED, isMultiWindow);
}
/**
@@ -168,13 +186,15 @@
* false otherwise
*/
public boolean update(
- @SurfaceRotation int touchRotation, @SurfaceRotation int displayRotation,
- @SurfaceRotation int launcherRotation) {
+ @SurfaceRotation int touchRotation, @SurfaceRotation int displayRotation) {
if (!isMultipleOrientationSupportedByDevice()) {
return false;
}
- if (mDisplayRotation == displayRotation && mTouchRotation == touchRotation
- && launcherRotation == mLauncherRotation) {
+
+ int launcherRotation = inferLauncherRotation(displayRotation);
+ if (mDisplayRotation == displayRotation
+ && mTouchRotation == touchRotation
+ && mLauncherRotation == launcherRotation) {
return false;
}
@@ -182,11 +202,10 @@
mDisplayRotation = displayRotation;
mTouchRotation = touchRotation;
- if (canLauncherRotate() || mLauncherRotation == mTouchRotation) {
- // TODO(b/153476489) Need to determine when launcher is rotated
+ if (mLauncherRotation == mTouchRotation) {
mOrientationHandler = PagedOrientationHandler.HOME_ROTATED;
if (DEBUG) {
- Log.d(TAG, "Set Orientation Handler: " + mOrientationHandler);
+ Log.d(TAG, "current RecentsOrientedState: " + this);
}
return true;
}
@@ -199,11 +218,20 @@
mOrientationHandler = PagedOrientationHandler.PORTRAIT;
}
if (DEBUG) {
- Log.d(TAG, "Set Orientation Handler: " + mOrientationHandler);
+ Log.d(TAG, "current RecentsOrientedState: " + this);
}
return true;
}
+ @SurfaceRotation
+ private int inferLauncherRotation(@SurfaceRotation int displayRotation) {
+ if (!isMultipleOrientationSupportedByDevice() || isHomeRotationAllowed()) {
+ return displayRotation;
+ } else {
+ return ROTATION_0;
+ }
+ }
+
private void setFlag(int mask, boolean enabled) {
boolean wasRotationEnabled = !TestProtocol.sDisableSensorRotation
&& mFlags == VALUE_ROTATION_WATCHER_ENABLED;
@@ -228,7 +256,9 @@
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) {
- updateHomeRotationSetting();
+ if (ALLOW_ROTATION_PREFERENCE_KEY.equals(s)) {
+ updateHomeRotationSetting();
+ }
}
private void updateAutoRotateSetting() {
@@ -242,23 +272,24 @@
}
/**
- * Initializes aany system values and registers corresponding change listeners. It must be
- * paired with {@link #destroy()} call
+ * Initializes any system values and registers corresponding change listeners. It must be
+ * paired with {@link #destroyListeners()} call
*/
- public void init() {
+ public void initListeners() {
if (isMultipleOrientationSupportedByDevice()) {
mSharedPrefs.registerOnSharedPreferenceChangeListener(this);
mContentResolver.registerContentObserver(
Settings.System.getUriFor(Settings.System.ACCELEROMETER_ROTATION),
false, mSystemAutoRotateObserver);
}
- initWithoutListeners();
+ updateAutoRotateSetting();
+ updateHomeRotationSetting();
}
/**
* Unregisters any previously registered listeners.
*/
- public void destroy() {
+ public void destroyListeners() {
if (isMultipleOrientationSupportedByDevice()) {
mSharedPrefs.unregisterOnSharedPreferenceChangeListener(this);
mContentResolver.unregisterContentObserver(mSystemAutoRotateObserver);
@@ -266,13 +297,8 @@
setRotationWatcherEnabled(false);
}
- /**
- * Initializes the OrientationState without attaching any listeners. This can be used when
- * the object is short lived.
- */
- public void initWithoutListeners() {
- updateAutoRotateSetting();
- updateHomeRotationSetting();
+ public void forceAllowRotationForTesting(boolean forceAllow) {
+ setFlag(FLAG_HOME_ROTATION_FORCE_ENABLED_FOR_TESTING, forceAllow);
}
@SurfaceRotation
@@ -296,11 +322,13 @@
}
public boolean isHomeRotationAllowed() {
- return (mFlags & FLAG_HOME_ROTATION_ALLOWED_IN_PREFS) != 0;
+ return (mFlags & (FLAG_HOME_ROTATION_ALLOWED_IN_PREFS | FLAG_MULTIWINDOW_ROTATION_ALLOWED))
+ != 0 ||
+ (mFlags & FLAG_HOME_ROTATION_FORCE_ENABLED_FOR_TESTING) != 0;
}
public boolean canLauncherRotate() {
- return (mFlags & MASK_ACTIVITY_ROTATING) == MASK_ACTIVITY_ROTATING;
+ return (mFlags & FLAG_SYSTEM_ROTATION_ALLOWED) != 0 && isHomeRotationAllowed();
}
/**
@@ -331,11 +359,26 @@
Rect insets = dp.getInsets();
float fullWidth = dp.widthPx - insets.left - insets.right;
float fullHeight = dp.heightPx - insets.top - insets.bottom;
- final float scale = LayoutUtils.getTaskScale(this,
- fullWidth, fullHeight, taskView.width(), taskView.height());
+
+ if (dp.isMultiWindowMode) {
+ mSizeStrategy.getMultiWindowSize(mContext, dp, outPivot);
+ } else {
+ outPivot.set(fullWidth, fullHeight);
+ }
+ float scale = Math.min(outPivot.x / taskView.width(), outPivot.y / taskView.height());
+ // We also scale the preview as part of fullScreenParams, so account for that as well.
+ if (fullWidth > 0) {
+ scale = scale * dp.widthPx / fullWidth;
+ }
if (scale == 1) {
outPivot.set(fullWidth / 2, fullHeight / 2);
+ } else if (dp.isMultiWindowMode) {
+ float denominator = 1 / (scale - 1);
+ // Ensure that the task aligns to right bottom for the root view
+ float y = (scale * taskView.bottom - fullHeight) * denominator;
+ float x = (scale * taskView.right - fullWidth) * denominator;
+ outPivot.set(x, y);
} else {
float factor = scale / (scale - 1);
outPivot.set(taskView.left * factor, taskView.top * factor);
@@ -374,35 +417,57 @@
*/
}
- public void mapRectFromNormalOrientation(RectF src, int screenWidth, int screenHeight) {
- mapRectFromRotation(mDisplayRotation, src, screenWidth, screenHeight);
- }
-
- public void mapRectFromRotation(int rotation, RectF src, int screenWidth, int screenHeight) {
- mTmpMatrix.reset();
- postDisplayRotation(rotation, screenWidth, screenHeight, mTmpMatrix);
- mTmpMatrix.mapRect(src);
- }
-
- public void mapInverseRectFromNormalOrientation(RectF src, int screenWidth, int screenHeight) {
- mTmpMatrix.reset();
- postDisplayRotation(mDisplayRotation, screenWidth, screenHeight, mTmpMatrix);
- mTmpMatrix.invert(mTmpInverseMatrix);
- mTmpInverseMatrix.mapRect(src);
- }
-
@SurfaceRotation
- public static int getRotationForUserDegreesRotated(float degrees) {
- int threshold = 70;
- if (degrees >= (360 - threshold) || degrees < (threshold)) {
- return ROTATION_0;
- } else if (degrees < (90 + threshold)) {
- return ROTATION_270;
- } else if (degrees < 180 + threshold) {
- return ROTATION_180;
- } else {
- return ROTATION_90;
+ public static int getRotationForUserDegreesRotated(float degrees, int currentRotation) {
+ if (degrees == ORIENTATION_UNKNOWN) {
+ return currentRotation;
}
+
+ int threshold = 70;
+ switch (currentRotation) {
+ case ROTATION_0:
+ if (degrees > 180 && degrees < (360 - threshold)) {
+ return ROTATION_90;
+ }
+ if (degrees < 180 && degrees > threshold) {
+ return ROTATION_270;
+ }
+ break;
+ case ROTATION_270:
+ if (degrees < (90 - threshold)) {
+ return ROTATION_0;
+ }
+ if (degrees > (90 + threshold) && degrees < 180) {
+ return ROTATION_180;
+ }
+ // flip from seascape to landscape
+ if (degrees > (180 + threshold) && degrees < 360) {
+ return ROTATION_90;
+ }
+ break;
+ case ROTATION_180:
+ if (degrees < (180 - threshold)) {
+ return ROTATION_270;
+ }
+ if (degrees > (180 + threshold)) {
+ return ROTATION_90;
+ }
+ break;
+ case ROTATION_90:
+ if (degrees < (270 - threshold) && degrees > 90) {
+ return ROTATION_180;
+ }
+ if (degrees > (270 + threshold) && degrees < 360) {
+ return ROTATION_0;
+ }
+ // flip from landscape to seascape
+ if (degrees > threshold && degrees < 180) {
+ return ROTATION_270;
+ }
+ break;
+ }
+
+ return currentRotation;
}
public boolean isDisplayPhoneNatural() {
@@ -440,4 +505,21 @@
return Settings.Global.getInt(
context.getContentResolver(), FIXED_ROTATION_TRANSFORM_SETTING_NAME, 1) == 1;
}
+
+ @NonNull
+ @Override
+ public String toString() {
+ boolean systemRotationOn = (mFlags & FLAG_SYSTEM_ROTATION_ALLOWED) != 0;
+ return "["
+ + "this=" + extractObjectNameAndAddress(super.toString())
+ + " mOrientationHandler=" +
+ extractObjectNameAndAddress(mOrientationHandler.toString())
+ + " mDisplayRotation=" + mDisplayRotation
+ + " mTouchRotation=" + mTouchRotation
+ + " mLauncherRotation=" + mLauncherRotation
+ + " mHomeRotation=" + isHomeRotationAllowed()
+ + " mSystemRotation=" + systemRotationOn
+ + " mFlags=" + mFlags
+ + "]";
+ }
}
diff --git a/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java b/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java
index 4cd0206..04308c8 100644
--- a/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java
+++ b/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java
@@ -25,12 +25,10 @@
import com.android.systemui.shared.system.ActivityOptionsCompat;
import com.android.systemui.shared.system.RemoteAnimationAdapterCompat;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
-import com.android.systemui.shared.system.TransactionCompat;
public abstract class RemoteAnimationProvider {
LauncherAnimationRunner mAnimationRunner;
- static final int Z_BOOST_BASE = 800570000;
public abstract AnimatorSet createWindowAnimation(RemoteAnimationTargetCompat[] appTargets,
RemoteAnimationTargetCompat[] wallpaperTargets);
@@ -53,24 +51,6 @@
}
/**
- * Prepares the given {@param targets} for a remote animation, and should be called with the
- * transaction from the first frame of animation.
- *
- * @param boostModeTargets The mode indicating which targets to boost in z-order above other
- * targets.
- */
- static void prepareTargetsForFirstFrame(RemoteAnimationTargetCompat[] targets,
- TransactionCompat t, int boostModeTargets) {
- for (RemoteAnimationTargetCompat target : targets) {
- t.show(target.leash);
- }
- }
-
- public static int getLayer(RemoteAnimationTargetCompat target, int boostModeTarget) {
- return target.prefixOrderIndex;
- }
-
- /**
* @return the target with the lowest opaque layer for a certain app animation, or null.
*/
public static RemoteAnimationTargetCompat findLowestOpaqueLayerTarget(
@@ -80,7 +60,7 @@
for (int i = appTargets.length - 1; i >= 0; i--) {
RemoteAnimationTargetCompat target = appTargets[i];
if (target.mode == mode && !target.isTranslucent) {
- int layer = getLayer(target, mode);
+ int layer = target.prefixOrderIndex;
if (layer < lowestLayer) {
lowestLayer = layer;
lowestLayerIndex = i;
diff --git a/quickstep/src/com/android/quickstep/util/RemoteFadeOutAnimationListener.java b/quickstep/src/com/android/quickstep/util/RemoteFadeOutAnimationListener.java
index fa2d338..958ee24 100644
--- a/quickstep/src/com/android/quickstep/util/RemoteFadeOutAnimationListener.java
+++ b/quickstep/src/com/android/quickstep/util/RemoteFadeOutAnimationListener.java
@@ -15,7 +15,6 @@
*/
package com.android.quickstep.util;
-import static com.android.quickstep.util.RemoteAnimationProvider.prepareTargetsForFirstFrame;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
import android.animation.ValueAnimator;
@@ -42,7 +41,9 @@
public void onAnimationUpdate(ValueAnimator valueAnimator) {
TransactionCompat t = new TransactionCompat();
if (mFirstFrame) {
- prepareTargetsForFirstFrame(mTarget.unfilteredApps, t, MODE_CLOSING);
+ for (RemoteAnimationTargetCompat target : mTarget.unfilteredApps) {
+ t.show(target.leash);
+ }
mFirstFrame = false;
}
diff --git a/quickstep/src/com/android/quickstep/util/WindowSizeStrategy.java b/quickstep/src/com/android/quickstep/util/WindowSizeStrategy.java
new file mode 100644
index 0000000..1557dfc
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/WindowSizeStrategy.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.util;
+
+import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS;
+import static com.android.quickstep.SysUINavigationMode.getMode;
+import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview;
+import static com.android.quickstep.util.LayoutUtils.getDefaultSwipeHeight;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.PointF;
+import android.graphics.Rect;
+
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.R;
+import com.android.quickstep.SysUINavigationMode.Mode;
+
+/**
+ * Utility class to wrap different layout behavior for Launcher and RecentsView
+ * TODO: Merge is with {@link com.android.quickstep.BaseActivityInterface} once we remove the
+ * state dependent members from {@link com.android.quickstep.LauncherActivityInterface}
+ */
+public abstract class WindowSizeStrategy {
+
+ private final PointF mTempPoint = new PointF();
+ public final boolean rotationSupportedByActivity;
+
+ private WindowSizeStrategy(boolean rotationSupportedByActivity) {
+ this.rotationSupportedByActivity = rotationSupportedByActivity;
+ }
+
+ /**
+ * Sets the expected window size in multi-window mode
+ */
+ public abstract void getMultiWindowSize(Context context, DeviceProfile dp, PointF out);
+
+ /**
+ * Calculates the taskView size for the provided device configuration
+ */
+ public final void calculateTaskSize(Context context, DeviceProfile dp, Rect outRect) {
+ calculateTaskSize(context, dp, getExtraSpace(context, dp), outRect);
+ }
+
+ abstract float getExtraSpace(Context context, DeviceProfile dp);
+
+ private void calculateTaskSize(
+ Context context, DeviceProfile dp, float extraVerticalSpace, Rect outRect) {
+ float taskWidth, taskHeight, paddingHorz;
+ Resources res = context.getResources();
+ Rect insets = dp.getInsets();
+ final boolean showLargeTaskSize = showOverviewActions(context);
+
+ if (dp.isMultiWindowMode) {
+ getMultiWindowSize(context, dp, mTempPoint);
+ taskWidth = mTempPoint.x;
+ taskHeight = mTempPoint.y;
+ paddingHorz = res.getDimension(R.dimen.multi_window_task_card_horz_space);
+ } else {
+ taskWidth = dp.availableWidthPx;
+ taskHeight = dp.availableHeightPx;
+
+ final int paddingResId;
+ if (dp.isVerticalBarLayout()) {
+ paddingResId = R.dimen.landscape_task_card_horz_space;
+ } else if (showLargeTaskSize) {
+ paddingResId = R.dimen.portrait_task_card_horz_space_big_overview;
+ } else {
+ paddingResId = R.dimen.portrait_task_card_horz_space;
+ }
+ paddingHorz = res.getDimension(paddingResId);
+ }
+
+ float topIconMargin = res.getDimension(R.dimen.task_thumbnail_top_margin);
+ float paddingVert = showLargeTaskSize
+ ? 0 : res.getDimension(R.dimen.task_card_vert_space);
+
+ // Note this should be same as dp.availableWidthPx and dp.availableHeightPx unless
+ // we override the insets ourselves.
+ int launcherVisibleWidth = dp.widthPx - insets.left - insets.right;
+ int launcherVisibleHeight = dp.heightPx - insets.top - insets.bottom;
+
+ float availableHeight = launcherVisibleHeight
+ - topIconMargin - extraVerticalSpace - paddingVert;
+ float availableWidth = launcherVisibleWidth - paddingHorz;
+
+ float scale = Math.min(availableWidth / taskWidth, availableHeight / taskHeight);
+ float outWidth = scale * taskWidth;
+ float outHeight = scale * taskHeight;
+
+ // Center in the visible space
+ float x = insets.left + (launcherVisibleWidth - outWidth) / 2;
+ float y = insets.top + Math.max(topIconMargin,
+ (launcherVisibleHeight - extraVerticalSpace - outHeight) / 2);
+ outRect.set(Math.round(x), Math.round(y),
+ Math.round(x) + Math.round(outWidth), Math.round(y) + Math.round(outHeight));
+ }
+
+
+ public static final WindowSizeStrategy LAUNCHER_ACTIVITY_SIZE_STRATEGY =
+ new WindowSizeStrategy(true) {
+
+ @Override
+ public void getMultiWindowSize(Context context, DeviceProfile dp, PointF out) {
+ DeviceProfile fullDp = dp.getFullScreenProfile();
+ // Use availableWidthPx and availableHeightPx instead of widthPx and heightPx to
+ // account for system insets
+ out.set(fullDp.availableWidthPx, fullDp.availableHeightPx);
+ float halfDividerSize = context.getResources()
+ .getDimension(R.dimen.multi_window_task_divider_size) / 2;
+
+ if (fullDp.isLandscape) {
+ out.x = out.x / 2 - halfDividerSize;
+ } else {
+ out.y = out.y / 2 - halfDividerSize;
+ }
+ }
+
+ @Override
+ float getExtraSpace(Context context, DeviceProfile dp) {
+ if (dp.isVerticalBarLayout()) {
+ return 0;
+ } else {
+ Resources res = context.getResources();
+ if (showOverviewActions(context)) {
+ //TODO: this needs to account for the swipe gesture height and accessibility
+ // UI when shown.
+ float actionsBottomMargin = 0;
+ if (getMode(context) == Mode.THREE_BUTTONS) {
+ actionsBottomMargin = res.getDimensionPixelSize(
+ R.dimen.overview_actions_bottom_margin_three_button);
+ } else {
+ actionsBottomMargin = res.getDimensionPixelSize(
+ R.dimen.overview_actions_bottom_margin_gesture);
+ }
+ float actionsHeight = actionsBottomMargin
+ + res.getDimensionPixelSize(R.dimen.overview_actions_height);
+ return actionsHeight;
+ } else {
+ return getDefaultSwipeHeight(context, dp) + dp.workspacePageIndicatorHeight
+ + res.getDimensionPixelSize(
+ R.dimen.dynamic_grid_hotseat_extra_vertical_size)
+ + res.getDimensionPixelSize(
+ R.dimen.dynamic_grid_hotseat_bottom_padding);
+ }
+ }
+ }
+ };
+
+ public static final WindowSizeStrategy FALLBACK_RECENTS_SIZE_STRATEGY =
+ new WindowSizeStrategy(false) {
+ @Override
+ public void getMultiWindowSize(Context context, DeviceProfile dp, PointF out) {
+ out.set(dp.widthPx, dp.heightPx);
+ }
+
+ @Override
+ float getExtraSpace(Context context, DeviceProfile dp) {
+ return showOverviewActions(context)
+ ? context.getResources().getDimensionPixelSize(R.dimen.overview_actions_height)
+ : 0;
+ }
+ };
+
+ static boolean showOverviewActions(Context context) {
+ return ENABLE_OVERVIEW_ACTIONS.get() && removeShelfFromOverview(context);
+ }
+}
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index 75fcfe2..bf093fd 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -42,6 +42,7 @@
import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
import com.android.quickstep.views.RecentsView;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -53,6 +54,18 @@
public void setUp() throws Exception {
super.setUp();
TaplTestsLauncher3.initialize(this);
+ executeOnLauncher(launcher -> {
+ RecentsView recentsView = launcher.getOverviewPanel();
+ recentsView.getPagedViewOrientedState().forceAllowRotationForTesting(true);
+ });
+ }
+
+ @After
+ public void tearDown() {
+ executeOnLauncher(launcher -> {
+ RecentsView recentsView = launcher.getOverviewPanel();
+ recentsView.getPagedViewOrientedState().forceAllowRotationForTesting(false);
+ });
}
private void startTestApps() throws Exception {
diff --git a/res/color/overview_button.xml b/res/color/overview_button.xml
new file mode 100644
index 0000000..6ac36bf
--- /dev/null
+++ b/res/color/overview_button.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:alpha="1"
+ android:color="?attr/workspaceTextColor"
+ android:state_enabled="true" />
+ <item
+ android:alpha="?android:disabledAlpha"
+ android:color="?attr/workspaceTextColor"
+ android:state_enabled="false" />
+</selector>
\ No newline at end of file
diff --git a/res/layout/work_profile_edu.xml b/res/layout/work_profile_edu.xml
index 5506b94..c3c7010 100644
--- a/res/layout/work_profile_edu.xml
+++ b/res/layout/work_profile_edu.xml
@@ -23,13 +23,13 @@
android:layout_width="match_parent"
android:layout_height="32dp"
android:background="@drawable/bottom_sheet_top_border"
- android:backgroundTint="?android:attr/colorAccent" />
+ android:backgroundTint="?attr/eduHalfSheetBGColor" />
<LinearLayout
android:id="@+id/view_wrapper"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:background="?android:attr/colorAccent"
+ android:background="?attr/eduHalfSheetBGColor"
android:orientation="vertical"
android:paddingLeft="@dimen/bottom_sheet_edu_padding"
android:paddingRight="@dimen/bottom_sheet_edu_padding">
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index 07739c5..b8a8818 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -133,14 +133,14 @@
<string name="notification_dismissed" msgid="6002233469409822874">"Obaveštenje je odbačeno"</string>
<string name="all_apps_personal_tab" msgid="4190252696685155002">"Lične"</string>
<string name="all_apps_work_tab" msgid="4884822796154055118">"Poslovne"</string>
- <string name="work_profile_toggle_label" msgid="3081029915775481146">"Profil za Work"</string>
+ <string name="work_profile_toggle_label" msgid="3081029915775481146">"Poslovni profil"</string>
<string name="work_profile_edu_personal_apps" msgid="4155536355149317441">"Lični podaci su odvojeni i sakriveni od aplikacija za posao"</string>
- <string name="work_profile_edu_work_apps" msgid="237051938268703058">"IT administrator vidi aplikacije za posao i podatke"</string>
+ <string name="work_profile_edu_work_apps" msgid="237051938268703058">"IT administrator vidi poslovne aplikacije i podatke"</string>
<string name="work_profile_edu_next" msgid="8783418929296503629">"Dalje"</string>
<string name="work_profile_edu_accept" msgid="6069788082535149071">"Važi"</string>
- <string name="work_apps_paused_title" msgid="2389865654362803723">"Profil za Work je pauziran"</string>
- <string name="work_apps_paused_body" msgid="5388070126389079077">"Aplikacije za posao ne mogu da vam šalju obaveštenja, koriste bateriju ni pristupaju lokaciji"</string>
- <string name="work_apps_paused_content_description" msgid="7553586952985486433">"Profil za Work je pauziran. Aplikacije za posao ne mogu da vam šalju obaveštenja, koriste bateriju niti pristupaju lokaciji"</string>
- <string name="work_switch_tip" msgid="808075064383839144">"Pauzirajte aplikacije za posao i obaveštenja"</string>
+ <string name="work_apps_paused_title" msgid="2389865654362803723">"Poslovni profil je pauziran"</string>
+ <string name="work_apps_paused_body" msgid="5388070126389079077">"Poslovne aplikacije ne mogu da vam šalju obaveštenja, koriste bateriju ni pristupaju lokaciji"</string>
+ <string name="work_apps_paused_content_description" msgid="7553586952985486433">"Poslovni profil je pauziran. Poslovne aplikacije ne mogu da vam šalju obaveštenja, koriste bateriju niti pristupaju lokaciji"</string>
+ <string name="work_switch_tip" msgid="808075064383839144">"Pauzirajte poslovne aplikacije i obaveštenja"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Nije uspelo: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml
index 53d8794..1a118ad 100644
--- a/res/values-bn/strings.xml
+++ b/res/values-bn/strings.xml
@@ -134,12 +134,12 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"অফিস"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"অফিসের প্রোফাইল"</string>
<string name="work_profile_edu_personal_apps" msgid="4155536355149317441">"অফিসের অ্যাপের থেকে ব্যক্তিগত ডেটা আলাদা করে লুকিয়ে রাখা হয়"</string>
- <string name="work_profile_edu_work_apps" msgid="237051938268703058">"অফিসের অ্যাপ এবং ডেটা আপনার আইটি অ্যাডমিন দেখতে পাবেন"</string>
+ <string name="work_profile_edu_work_apps" msgid="237051938268703058">"আপনার আইটি অ্যাডমিন অফিস অ্যাপ এবং ডেটা দেখতে পাবেন"</string>
<string name="work_profile_edu_next" msgid="8783418929296503629">"পরের"</string>
<string name="work_profile_edu_accept" msgid="6069788082535149071">"বুঝেছি"</string>
<string name="work_apps_paused_title" msgid="2389865654362803723">"অফিস প্রোফাইল বন্ধ করা আছে"</string>
- <string name="work_apps_paused_body" msgid="5388070126389079077">"অফিসের অ্যাপ আপনাকে বিজ্ঞপ্তি পাঠাতে, আপনার ব্যাটারি ব্যবহার করতে বা লোকেশন অ্যাক্সেস করতে পারে না"</string>
+ <string name="work_apps_paused_body" msgid="5388070126389079077">"অফিস অ্যাপ আপনাকে বিজ্ঞপ্তি পাঠাতে, আপনার ব্যাটারি ব্যবহার করতে বা লোকেশন অ্যাক্সেস করতে পারে না"</string>
<string name="work_apps_paused_content_description" msgid="7553586952985486433">"অফিসের প্রোফাইল পজ করা আছে। অফিসের অ্যাপ আপনাকে বিজ্ঞপ্তি পাঠাতে, ব্যাটারি ব্যবহার করতে বা লোকেশন অ্যাক্সেস করতে পারবে না"</string>
- <string name="work_switch_tip" msgid="808075064383839144">"অফিসের অ্যাপ এবং বিজ্ঞপ্তি বন্ধ করুন"</string>
+ <string name="work_switch_tip" msgid="808075064383839144">"অফিস অ্যাপ এবং বিজ্ঞপ্তি বন্ধ করুন"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"কাজটি করা যায়নি: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index e899d49..43e7d03 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -139,7 +139,7 @@
<string name="work_profile_edu_next" msgid="8783418929296503629">"Sljedeće"</string>
<string name="work_profile_edu_accept" msgid="6069788082535149071">"Razumijem"</string>
<string name="work_apps_paused_title" msgid="2389865654362803723">"Radni profil je pauziran"</string>
- <string name="work_apps_paused_body" msgid="5388070126389079077">"Poslovne aplikacije ne mogu vam slati obavještenja, koristiti bateriju ili pristupiti vašoj lokaciji"</string>
+ <string name="work_apps_paused_body" msgid="5388070126389079077">"Poslovne aplikacije vam ne mogu slati obavještenja, koristiti bateriju ili pristupiti vašoj lokaciji"</string>
<string name="work_apps_paused_content_description" msgid="7553586952985486433">"Radni profil je pauziran. Poslovne aplikacije vam ne mogu slati obavještenja, koristiti bateriju ili pristupiti vašoj lokaciji"</string>
<string name="work_switch_tip" msgid="808075064383839144">"Pauzirajte poslovne aplikacije i obavještenja"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Nije uspjelo: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index ca3dfe1..be5945f 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -133,12 +133,12 @@
<string name="all_apps_personal_tab" msgid="4190252696685155002">"Privat"</string>
<string name="all_apps_work_tab" msgid="4884822796154055118">"Geschäftlich"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Arbeitsprofil"</string>
- <string name="work_profile_edu_personal_apps" msgid="4155536355149317441">"Personenbezogene Daten sind separat und für geschäftliche Apps nicht sichtbar"</string>
+ <string name="work_profile_edu_personal_apps" msgid="4155536355149317441">"Personenbezogene Daten sind für geschäftlichen Apps nicht sichtbar oder zugänglich"</string>
<string name="work_profile_edu_work_apps" msgid="237051938268703058">"Geschäftliche Apps und Daten können von deinem IT-Administrator eingesehen werden"</string>
<string name="work_profile_edu_next" msgid="8783418929296503629">"Weiter"</string>
<string name="work_profile_edu_accept" msgid="6069788082535149071">"OK"</string>
<string name="work_apps_paused_title" msgid="2389865654362803723">"Arbeitsprofil pausiert"</string>
- <string name="work_apps_paused_body" msgid="5388070126389079077">"Geschäftliche Apps können dir Benachrichtigungen senden, deinen Akku verbrauchen oder auf deinen Standort zugreifen"</string>
+ <string name="work_apps_paused_body" msgid="5388070126389079077">"Geschäftliche Apps können dir keine Benachrichtigungen senden, deinen Akku nicht nutzen und nicht auf deinen Standort zugreifen"</string>
<string name="work_apps_paused_content_description" msgid="7553586952985486433">"Das Arbeitsprofil ist pausiert. Geschäftliche Apps können dir keine Benachrichtigungen senden, deinen Akku nicht beanspruchen und nicht auf deinen Standort zugreifen."</string>
<string name="work_switch_tip" msgid="808075064383839144">"Geschäftliche Apps und Benachrichtigungen pausieren"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Fehler: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index fc7603a..e3dc671 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -133,13 +133,13 @@
<string name="all_apps_personal_tab" msgid="4190252696685155002">"Προσωπικές"</string>
<string name="all_apps_work_tab" msgid="4884822796154055118">"Εργασίας"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Προφίλ εργασίας"</string>
- <string name="work_profile_edu_personal_apps" msgid="4155536355149317441">"Τα προσωπικά δεδομένα βρίσκονται σε ξεχωριστή θέση και δεν είναι ορατά από τις εφαρμογές εργασιών"</string>
- <string name="work_profile_edu_work_apps" msgid="237051938268703058">"Οι εφαρμογές εργασιών και τα δεδομένα τους είναι ορατά στον διαχειριστή IT"</string>
+ <string name="work_profile_edu_personal_apps" msgid="4155536355149317441">"Τα προσωπικά δεδομένα βρίσκονται σε ξεχωριστή θέση και δεν είναι ορατά από τις εφαρμογές εργασίας"</string>
+ <string name="work_profile_edu_work_apps" msgid="237051938268703058">"Οι εφαρμογές εργασίας και τα δεδομένα τους είναι ορατά στον διαχειριστή IT"</string>
<string name="work_profile_edu_next" msgid="8783418929296503629">"Επόμενο"</string>
<string name="work_profile_edu_accept" msgid="6069788082535149071">"Το κατάλαβα"</string>
<string name="work_apps_paused_title" msgid="2389865654362803723">"Το προφίλ εργασίας έχει τεθεί σε παύση"</string>
- <string name="work_apps_paused_body" msgid="5388070126389079077">"Οι εφαρμογές εργασιών δεν μπορούν να σας στέλνουν ειδοποιήσεις, να χρησιμοποιούν την μπαταρία ή να έχουν πρόσβαση στην τοποθεσία σας"</string>
+ <string name="work_apps_paused_body" msgid="5388070126389079077">"Οι εφαρμογές εργασίας δεν μπορούν να σας στέλνουν ειδοποιήσεις, να χρησιμοποιούν την μπαταρία ή να έχουν πρόσβαση στην τοποθεσία σας"</string>
<string name="work_apps_paused_content_description" msgid="7553586952985486433">"Το προφίλ εργασίας έχει τεθεί σε παύση. Οι εφαρμογές εργασιών δεν μπορούν να σας στέλνουν ειδοποιήσεις, να χρησιμοποιούν την μπαταρία ή να έχουν πρόσβαση στην τοποθεσία σας."</string>
- <string name="work_switch_tip" msgid="808075064383839144">"Παύση εφαρμογών εργασιών και ειδοποιήσεων"</string>
+ <string name="work_switch_tip" msgid="808075064383839144">"Παύση εφαρμογών εργασίας και ειδοποιήσεων"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Αποτυχία: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index 1eca60f..6a2d292 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -138,7 +138,7 @@
<string name="work_profile_edu_next" msgid="8783418929296503629">"Next"</string>
<string name="work_profile_edu_accept" msgid="6069788082535149071">"OK"</string>
<string name="work_apps_paused_title" msgid="2389865654362803723">"Work profile is paused"</string>
- <string name="work_apps_paused_body" msgid="5388070126389079077">"Work apps cant send you notifications, use your battery or access your location"</string>
+ <string name="work_apps_paused_body" msgid="5388070126389079077">"Work apps can\'t send you notifications, use your battery or access your location"</string>
<string name="work_apps_paused_content_description" msgid="7553586952985486433">"Work profile is paused. Work apps can\'t send you notifications, use your battery or access your location"</string>
<string name="work_switch_tip" msgid="808075064383839144">"Pause work apps and notifications"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Failed: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
diff --git a/res/values-en-rCA/strings.xml b/res/values-en-rCA/strings.xml
index 1eca60f..6a2d292 100644
--- a/res/values-en-rCA/strings.xml
+++ b/res/values-en-rCA/strings.xml
@@ -138,7 +138,7 @@
<string name="work_profile_edu_next" msgid="8783418929296503629">"Next"</string>
<string name="work_profile_edu_accept" msgid="6069788082535149071">"OK"</string>
<string name="work_apps_paused_title" msgid="2389865654362803723">"Work profile is paused"</string>
- <string name="work_apps_paused_body" msgid="5388070126389079077">"Work apps cant send you notifications, use your battery or access your location"</string>
+ <string name="work_apps_paused_body" msgid="5388070126389079077">"Work apps can\'t send you notifications, use your battery or access your location"</string>
<string name="work_apps_paused_content_description" msgid="7553586952985486433">"Work profile is paused. Work apps can\'t send you notifications, use your battery or access your location"</string>
<string name="work_switch_tip" msgid="808075064383839144">"Pause work apps and notifications"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Failed: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index 1eca60f..6a2d292 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -138,7 +138,7 @@
<string name="work_profile_edu_next" msgid="8783418929296503629">"Next"</string>
<string name="work_profile_edu_accept" msgid="6069788082535149071">"OK"</string>
<string name="work_apps_paused_title" msgid="2389865654362803723">"Work profile is paused"</string>
- <string name="work_apps_paused_body" msgid="5388070126389079077">"Work apps cant send you notifications, use your battery or access your location"</string>
+ <string name="work_apps_paused_body" msgid="5388070126389079077">"Work apps can\'t send you notifications, use your battery or access your location"</string>
<string name="work_apps_paused_content_description" msgid="7553586952985486433">"Work profile is paused. Work apps can\'t send you notifications, use your battery or access your location"</string>
<string name="work_switch_tip" msgid="808075064383839144">"Pause work apps and notifications"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Failed: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index 1eca60f..6a2d292 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -138,7 +138,7 @@
<string name="work_profile_edu_next" msgid="8783418929296503629">"Next"</string>
<string name="work_profile_edu_accept" msgid="6069788082535149071">"OK"</string>
<string name="work_apps_paused_title" msgid="2389865654362803723">"Work profile is paused"</string>
- <string name="work_apps_paused_body" msgid="5388070126389079077">"Work apps cant send you notifications, use your battery or access your location"</string>
+ <string name="work_apps_paused_body" msgid="5388070126389079077">"Work apps can\'t send you notifications, use your battery or access your location"</string>
<string name="work_apps_paused_content_description" msgid="7553586952985486433">"Work profile is paused. Work apps can\'t send you notifications, use your battery or access your location"</string>
<string name="work_switch_tip" msgid="808075064383839144">"Pause work apps and notifications"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Failed: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index db60954..56ae3bd 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -133,13 +133,13 @@
<string name="all_apps_personal_tab" msgid="4190252696685155002">"Personal"</string>
<string name="all_apps_work_tab" msgid="4884822796154055118">"Trabajo"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Perfil de trabajo"</string>
- <string name="work_profile_edu_personal_apps" msgid="4155536355149317441">"Los datos personales están separados y ocultos de las aplicaciones de trabajo, que no pueden acceder a ellos"</string>
+ <string name="work_profile_edu_personal_apps" msgid="4155536355149317441">"Los datos personales están separados y ocultos de las aplicaciones de trabajo"</string>
<string name="work_profile_edu_work_apps" msgid="237051938268703058">"Tu administrador de TI puede ver tus aplicaciones y datos de trabajo"</string>
<string name="work_profile_edu_next" msgid="8783418929296503629">"Siguiente"</string>
<string name="work_profile_edu_accept" msgid="6069788082535149071">"Listo"</string>
<string name="work_apps_paused_title" msgid="2389865654362803723">"El perfil de trabajo está en pausa"</string>
- <string name="work_apps_paused_body" msgid="5388070126389079077">"Las aplicaciones de trabajo no pueden enviarte notificaciones, gastar tu batería ni acceder a tu ubicación"</string>
+ <string name="work_apps_paused_body" msgid="5388070126389079077">"Las aplicaciones de trabajo no pueden enviarte notificaciones, gastar batería ni acceder a tu ubicación"</string>
<string name="work_apps_paused_content_description" msgid="7553586952985486433">"El perfil de trabajo está en pausa. Las aplicaciones de trabajo no pueden enviarte notificaciones, consumir tu batería ni acceder a tu ubicación"</string>
- <string name="work_switch_tip" msgid="808075064383839144">"Pausar notificaciones y aplicaciones de trabajo"</string>
+ <string name="work_switch_tip" msgid="808075064383839144">"Pausa apps y notificaciones de trabajo"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Se ha producido un error: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml
index 27ac2fb..cee265d 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -138,7 +138,7 @@
<string name="work_profile_edu_next" msgid="8783418929296503629">"Järgmine"</string>
<string name="work_profile_edu_accept" msgid="6069788082535149071">"Selge"</string>
<string name="work_apps_paused_title" msgid="2389865654362803723">"Tööprofiil on peatatud"</string>
- <string name="work_apps_paused_body" msgid="5388070126389079077">"Töörakendused ei saa teile märguandeid saata, akut kasutada ega teie asukohale juurdepääseda"</string>
+ <string name="work_apps_paused_body" msgid="5388070126389079077">"Töörakendused ei saa teile märguandeid saata, akut kasutada ega teie asukohale juurde pääseda"</string>
<string name="work_apps_paused_content_description" msgid="7553586952985486433">"Tööprofiil on peatatud. Töörakendused ei saa teile märguandeid saata, akut kasutada ega teie asukohale juurde pääseda"</string>
<string name="work_switch_tip" msgid="808075064383839144">"Peatage töörakendused ja märguanded"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Nurjus: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index 87b329c..af40f5c 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -131,9 +131,9 @@
<string name="accessibility_close" msgid="2277148124685870734">"بستن"</string>
<string name="notification_dismissed" msgid="6002233469409822874">"اعلان رد شد"</string>
<string name="all_apps_personal_tab" msgid="4190252696685155002">"شخصی"</string>
- <string name="all_apps_work_tab" msgid="4884822796154055118">"محل کار"</string>
+ <string name="all_apps_work_tab" msgid="4884822796154055118">"کاری"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"نمایه کاری"</string>
- <string name="work_profile_edu_personal_apps" msgid="4155536355149317441">"دادههای شخصی مجزا هستند و از دسترس برنامههای کاری پنهان هستند"</string>
+ <string name="work_profile_edu_personal_apps" msgid="4155536355149317441">"دادههای شخصی از برنامههای کاری جدا است و از آن پنهان است"</string>
<string name="work_profile_edu_work_apps" msgid="237051938268703058">"برنامههای کاری و دادهها برای سرپرست فناوری اطلاعات نمایان هستند"</string>
<string name="work_profile_edu_next" msgid="8783418929296503629">"بعدی"</string>
<string name="work_profile_edu_accept" msgid="6069788082535149071">"متوجهام"</string>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index d72f3bb..c8b2876 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -80,7 +80,7 @@
<string name="widget_button_text" msgid="2880537293434387943">"Widgets"</string>
<string name="wallpaper_button_text" msgid="8404103075899945851">"Fonds d\'écran"</string>
<string name="styles_wallpaper_button_text" msgid="4342122323125579619">"Styles et fonds d\'écran"</string>
- <string name="settings_button_text" msgid="8873672322605444408">"Paramètres d\'écran d\'accueil"</string>
+ <string name="settings_button_text" msgid="8873672322605444408">"Paramètres d\'accueil"</string>
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Désactivé par votre administrateur"</string>
<string name="allow_rotation_title" msgid="7728578836261442095">"Autoriser la rotation de l\'écran d\'accueil"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"Lorsque vous faites pivoter le téléphone"</string>
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
index 8dbf0fd..0aa2f1b 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -20,7 +20,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="649227358658669779">"Launcher3"</string>
- <string name="work_folder_name" msgid="3753320833950115786">"કાર્યાલય"</string>
+ <string name="work_folder_name" msgid="3753320833950115786">"ઑફિસ"</string>
<string name="activity_not_found" msgid="8071924732094499514">"ઍપ્લિકેશન ઇન્સ્ટોલ થઈ નથી."</string>
<string name="activity_not_available" msgid="7456344436509528827">"ઍપ્લિકેશન ઉપલબ્ધ નથી"</string>
<string name="safemode_shortcut_error" msgid="9160126848219158407">"સુરક્ષિત મોડમાં ડાઉનલોડ કરેલ ઍપ્લિકેશન અક્ષમ કરી"</string>
@@ -131,13 +131,13 @@
<string name="accessibility_close" msgid="2277148124685870734">"બંધ કરો"</string>
<string name="notification_dismissed" msgid="6002233469409822874">"સૂચના છોડી દીધી"</string>
<string name="all_apps_personal_tab" msgid="4190252696685155002">"મનગમતી ઍપ"</string>
- <string name="all_apps_work_tab" msgid="4884822796154055118">"કાર્યાલયની ઍપ"</string>
- <string name="work_profile_toggle_label" msgid="3081029915775481146">"કાર્યાલયની પ્રોફાઇલ"</string>
+ <string name="all_apps_work_tab" msgid="4884822796154055118">"ઑફિસની ઍપ"</string>
+ <string name="work_profile_toggle_label" msgid="3081029915775481146">"ઑફિસની પ્રોફાઇલ"</string>
<string name="work_profile_edu_personal_apps" msgid="4155536355149317441">"વ્યક્તિગત ડેટા ઑફિસ માટેની ઍપથી અલગ અને છુપાવીને રાખેલો છે"</string>
<string name="work_profile_edu_work_apps" msgid="237051938268703058">"ઑફિસ માટેની ઍપ અને ડેટા તમારા IT વ્યવસ્થાપકને દેખાય છે"</string>
<string name="work_profile_edu_next" msgid="8783418929296503629">"આગળ"</string>
<string name="work_profile_edu_accept" msgid="6069788082535149071">"સમજાઈ ગયું"</string>
- <string name="work_apps_paused_title" msgid="2389865654362803723">"કાર્યાલયની પ્રોફાઇલ થોભાવી છે"</string>
+ <string name="work_apps_paused_title" msgid="2389865654362803723">"ઑફિસની પ્રોફાઇલ થોભાવી છે"</string>
<string name="work_apps_paused_body" msgid="5388070126389079077">"ઑફિસ માટેની ઍપ તમને નોટિફિકેશન મોકલી શકતી નથી, તમારી બૅટરી વાપરી શકતી નથી કે તમારું સ્થાન ઍક્સેસ કરી શકતી નથી"</string>
<string name="work_apps_paused_content_description" msgid="7553586952985486433">"કાર્યાલયની પ્રોફાઇલ થોભાવી છે. ઑફિસ માટેની ઍપ તમને નોટિફિકેશન મોકલી શકતી નથી, તમારી બૅટરી વાપરી શકતી નથી કે તમારું સ્થાન ઍક્સેસ કરી શકતી નથી"</string>
<string name="work_switch_tip" msgid="808075064383839144">"ઑફિસ માટેની ઍપ અને નોટિફિકેશન થોભાવો"</string>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index cef3b49..246f236 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -133,8 +133,8 @@
<string name="all_apps_personal_tab" msgid="4190252696685155002">"निजी ऐप"</string>
<string name="all_apps_work_tab" msgid="4884822796154055118">"काम से जुड़े ऐप"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"वर्क प्रोफ़ाइल"</string>
- <string name="work_profile_edu_personal_apps" msgid="4155536355149317441">"निजी डेटा को अलग और ऑफ़िस के काम से जुड़े ऐप्लिकेशन से छिपा कर रखा जाता है"</string>
- <string name="work_profile_edu_work_apps" msgid="237051938268703058">"ऑफ़िस के काम से जुड़े ऐप्लिकेशन और डेटा आपके आईटी एडमिन को दिखते हैं"</string>
+ <string name="work_profile_edu_personal_apps" msgid="4155536355149317441">"निजी डेटा को अलग रखा जाता है. साथ ही, ऑफ़िस के काम से जुड़े ऐप्लिकेशन से छिपा कर रखा जाता है"</string>
+ <string name="work_profile_edu_work_apps" msgid="237051938268703058">"ऑफ़िस के काम से जुड़े ऐप्लिकेशन और डेटा, आपके आईटी एडमिन को दिखते हैं"</string>
<string name="work_profile_edu_next" msgid="8783418929296503629">"आगे बढ़ें"</string>
<string name="work_profile_edu_accept" msgid="6069788082535149071">"ठीक है"</string>
<string name="work_apps_paused_title" msgid="2389865654362803723">"वर्क प्रोफ़ाइल रोक दी गई है"</string>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index fe9a359..46e9cba 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -137,9 +137,9 @@
<string name="work_profile_edu_work_apps" msgid="237051938268703058">"A munkahelyi alkalmazásokat és adatokat látja a rendszergazda"</string>
<string name="work_profile_edu_next" msgid="8783418929296503629">"Tovább"</string>
<string name="work_profile_edu_accept" msgid="6069788082535149071">"Értem"</string>
- <string name="work_apps_paused_title" msgid="2389865654362803723">"A munkaprofil szüneteltetve van"</string>
+ <string name="work_apps_paused_title" msgid="2389865654362803723">"A munkaprofil használata szünetel"</string>
<string name="work_apps_paused_body" msgid="5388070126389079077">"A munkahelyi alkalmazások nem küldhetnek értesítéseket, nem használhatják az akkumulátort, és nem férhetnek hozzá az Ön tartózkodási helyéhez"</string>
- <string name="work_apps_paused_content_description" msgid="7553586952985486433">"A munkaprofil szüneteltetve van. A munkahelyi alkalmazások nem küldhetnek értesítéseket, nem használhatják az akkumulátort, és nem férhetnek hozzá az Ön tartózkodási helyéhez"</string>
+ <string name="work_apps_paused_content_description" msgid="7553586952985486433">"A munkaprofil használata szünetel. A munkahelyi alkalmazások nem küldhetnek értesítéseket, nem használhatják az akkumulátort, és nem férhetnek hozzá az Ön tartózkodási helyéhez"</string>
<string name="work_switch_tip" msgid="808075064383839144">"Munkahelyi alkalmazások és értesítések szüneteltetése"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Sikertelen: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml
index 33294e1..923f504 100644
--- a/res/values-hy/strings.xml
+++ b/res/values-hy/strings.xml
@@ -133,13 +133,13 @@
<string name="all_apps_personal_tab" msgid="4190252696685155002">"Անձնական"</string>
<string name="all_apps_work_tab" msgid="4884822796154055118">"Աշխատանքային"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Աշխատանքային պրոֆիլ"</string>
- <string name="work_profile_edu_personal_apps" msgid="4155536355149317441">"Անձնական հավելվածները առանձնացված են և թաքցված աշխատանքային հավելվածներից։"</string>
+ <string name="work_profile_edu_personal_apps" msgid="4155536355149317441">"Անձնական հավելվածները թաքցված են և առանձնացված աշխատանքային հավելվածներից։"</string>
<string name="work_profile_edu_work_apps" msgid="237051938268703058">"Աշխատանքային հավելվածներն ու դրանց տվյալները տեսանելի են ձեր ադմինիստրատորին"</string>
<string name="work_profile_edu_next" msgid="8783418929296503629">"Առաջ"</string>
<string name="work_profile_edu_accept" msgid="6069788082535149071">"Եղավ"</string>
<string name="work_apps_paused_title" msgid="2389865654362803723">"Աշխատանքային պրոֆիլը դադարեցված է"</string>
- <string name="work_apps_paused_body" msgid="5388070126389079077">"Աշխատանքային հավելվածները չեն կարող օգտագործել ձեր մարտկոցը, գտնվելու վայրի մասին տվյալները և ուղարկել ձեզ ծանուցումներ։"</string>
- <string name="work_apps_paused_content_description" msgid="7553586952985486433">"Աշխատանքային պրոֆիլը դադարեցված է։ Աշխատանքային հավելվածները չեն կարող օգտագործել ձեր մարտկոցը, գտնվելու վայրի մասին տվյալները և ուղարկել ձեզ ծանուցումներ։"</string>
+ <string name="work_apps_paused_body" msgid="5388070126389079077">"Աշխատանքային հավելվածները չեն կարող ձեզ ծանուցումներ ուղարկել և օգտագործել ձեր մարտկոցն ու տեղադրության տվյալները։"</string>
+ <string name="work_apps_paused_content_description" msgid="7553586952985486433">"Աշխատանքային պրոֆիլը դադարեցված է։ Աշխատանքային հավելվածները չեն կարող ձեզ ծանուցումներ ուղարկել և օգտագործել ձեր մարտկոցն ու տեղադրության տվյալները։"</string>
<string name="work_switch_tip" msgid="808075064383839144">"Դադարեցնել աշխատանքային հավելվածներն ու ծանուցումները"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Չհաջողվեց կատարել գործողությունը (<xliff:g id="WHAT">%1$s</xliff:g>)"</string>
</resources>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index 1d83d64..8999506 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -133,7 +133,7 @@
<string name="all_apps_personal_tab" msgid="4190252696685155002">"Personali"</string>
<string name="all_apps_work_tab" msgid="4884822796154055118">"Lavoro"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Profilo di lavoro"</string>
- <string name="work_profile_edu_personal_apps" msgid="4155536355149317441">"I dati personali sono separati e sono nascosti alle app di lavoro"</string>
+ <string name="work_profile_edu_personal_apps" msgid="4155536355149317441">"I dati personali sono separati e non sono visibili nelle app di lavoro"</string>
<string name="work_profile_edu_work_apps" msgid="237051938268703058">"I dati e le app di lavoro sono visibili all\'amministratore IT"</string>
<string name="work_profile_edu_next" msgid="8783418929296503629">"Avanti"</string>
<string name="work_profile_edu_accept" msgid="6069788082535149071">"OK"</string>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index b5c3c0b..87bafc8 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -133,7 +133,7 @@
<string name="all_apps_personal_tab" msgid="4190252696685155002">"個人用"</string>
<string name="all_apps_work_tab" msgid="4884822796154055118">"仕事用"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"仕事用プロファイル"</string>
- <string name="work_profile_edu_personal_apps" msgid="4155536355149317441">"個人データは仕事用アプリとは別個に保存され、一緒に表示されません"</string>
+ <string name="work_profile_edu_personal_apps" msgid="4155536355149317441">"個人データは仕事用アプリとは別に保存され、一緒に表示されません"</string>
<string name="work_profile_edu_work_apps" msgid="237051938268703058">"仕事用アプリと仕事用データは IT 管理者に公開されます"</string>
<string name="work_profile_edu_next" msgid="8783418929296503629">"次へ"</string>
<string name="work_profile_edu_accept" msgid="6069788082535149071">"OK"</string>
diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml
index 01a6b25..47ef01d 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/strings.xml
@@ -138,8 +138,8 @@
<string name="work_profile_edu_next" msgid="8783418929296503629">"Кийинки"</string>
<string name="work_profile_edu_accept" msgid="6069788082535149071">"Түшүндүм"</string>
<string name="work_apps_paused_title" msgid="2389865654362803723">"Жумуш профили тындырылган"</string>
- <string name="work_apps_paused_body" msgid="5388070126389079077">"Жумуш колдонмолору билдирмелерди жөнөтүп, батареяңызды колдонуп же кайда жүргөнүңүздү көрө албайт"</string>
- <string name="work_apps_paused_content_description" msgid="7553586952985486433">"Жумуш профили тындырылган. Жумуш колдонмолору билдирмелерди жөнөтүп, батареяңызды колдонуп же кайда жүргөнүңүздү көрө албайт"</string>
+ <string name="work_apps_paused_body" msgid="5388070126389079077">"Жумуш колдонмолору билдирмелерди жөнөтүп, түзмөгүңүздүн батареясын керектеп же кайда жүргөнүңүздү көрө албайт"</string>
+ <string name="work_apps_paused_content_description" msgid="7553586952985486433">"Жумуш профили тындырылган. Жумуш колдонмолору билдирмелерди жөнөтүп, түзмөгүңүздүн батареясын керектеп же кайда жүргөнүңүздү көрө албайт"</string>
<string name="work_switch_tip" msgid="808075064383839144">"Жумуш колдонмолорун жана билдирмелерди тындыруу"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Аткарылган жок: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml
index f69248c..4667ede 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -53,11 +53,11 @@
<string name="app_info_drop_target_label" msgid="692894985365717661">"अनुप्रयोगको जानकारी"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"स्थापना गर्नुहोस्"</string>
<string name="permlab_install_shortcut" msgid="5632423390354674437">"सर्टकट स्थापना गर्नेहोस्"</string>
- <string name="permdesc_install_shortcut" msgid="923466509822011139">"प्रयोगकर्ताको हस्तक्षेप बिना एउटा अनुप्रयोगलाई सर्टकटमा थप्नको लागि अनुमति दिनुहोस्।"</string>
+ <string name="permdesc_install_shortcut" msgid="923466509822011139">"प्रयोगकर्ताको हस्तक्षेप बिना एउटा एपलाई सर्टकटमा थप्नको लागि अनुमति दिनुहोस्।"</string>
<string name="permlab_read_settings" msgid="1941457408239617576">"गृह सेटिङहरू र सर्टकटहरू पढ्नुहोस्"</string>
- <string name="permdesc_read_settings" msgid="5833423719057558387">"गृहमा एउटा अनुप्रयोगलाई सेटिङहरू र सर्टकटहरू पढ्न अनुमति दिनुहोस्।"</string>
+ <string name="permdesc_read_settings" msgid="5833423719057558387">"गृहमा एउटा एपलाई सेटिङहरू र सर्टकटहरू पढ्न अनुमति दिनुहोस्।"</string>
<string name="permlab_write_settings" msgid="3574213698004620587">"गृह सेटिङहरू र सर्टकटहरू लेख्नुहोस्"</string>
- <string name="permdesc_write_settings" msgid="5440712911516509985">"गृहमा एउटा अनुप्रयोगलाई सेटिङ र सर्टकट बदल्न अनुमति दिनुहोस्।"</string>
+ <string name="permdesc_write_settings" msgid="5440712911516509985">"गृहमा एउटा एपलाई सेटिङ र सर्टकट बदल्न अनुमति दिनुहोस्।"</string>
<string name="msg_no_phone_permission" msgid="9208659281529857371">"<xliff:g id="APP_NAME">%1$s</xliff:g> ले फोन कलहरू गर्न अनुमति छैन"</string>
<string name="gadget_error_text" msgid="6081085226050792095">"समस्या लोडिङ गर्ने विजेट"</string>
<string name="gadget_setup_text" msgid="8274003207686040488">"सेटअप"</string>
@@ -139,8 +139,7 @@
<string name="work_profile_edu_accept" msgid="6069788082535149071">"बुझेँ"</string>
<string name="work_apps_paused_title" msgid="2389865654362803723">"कार्यालयको प्रोफाइल अस्थायी रूपमा रोक्का गरिएको छ"</string>
<string name="work_apps_paused_body" msgid="5388070126389079077">"कामसम्बन्धी एपहरूले तपाईंलाई सूचना पठाउन, तपाईंको ब्याट्री प्रयोग गर्न वा तपाईंको स्थानसम्बन्धी जानकारीमाथि पहुँच राख्न सक्दैनन्"</string>
- <!-- no translation found for work_apps_paused_content_description (7553586952985486433) -->
- <skip />
+ <string name="work_apps_paused_content_description" msgid="7553586952985486433">"कार्यालयको प्रोफाइल अस्थायी रूपमा रोक्का गरिएको छ। कामसम्बन्धी एपहरूले तपाईंलाई सूचना पठाउन, तपाईंको यन्त्रको ब्याट्री प्रयोग गर्न वा तपाईंको स्थान हेर्न सक्दैनन्"</string>
<string name="work_switch_tip" msgid="808075064383839144">"कामसम्बन्धी एप र सूचनाहरू अस्थायी रूपमा रोक्का गर्नुहोस्"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"कार्य पूरा गर्न सकिएन: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index b2cf426..87a1948 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -20,7 +20,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="649227358658669779">"ଲଞ୍ଚର୍3"</string>
- <string name="work_folder_name" msgid="3753320833950115786">"କାମ"</string>
+ <string name="work_folder_name" msgid="3753320833950115786">"ୱାର୍କ"</string>
<string name="activity_not_found" msgid="8071924732094499514">"ଆପ୍ ଇନଷ୍ଟଲ୍ ହୋଇନାହିଁ"</string>
<string name="activity_not_available" msgid="7456344436509528827">"ଆପ୍ ଉପଲବ୍ଧ ନାହିଁ"</string>
<string name="safemode_shortcut_error" msgid="9160126848219158407">"ନିରାପଦ ମୋଡରେ ଡାଉନଲୋଡ୍ ହେଇଥିବା ଆପ୍ ଅକ୍ଷମ କରାଗଲା"</string>
@@ -131,7 +131,7 @@
<string name="accessibility_close" msgid="2277148124685870734">"ବନ୍ଦ କରନ୍ତୁ"</string>
<string name="notification_dismissed" msgid="6002233469409822874">"ବିଜ୍ଞପ୍ତି ଖାରଜ କରାଗଲା"</string>
<string name="all_apps_personal_tab" msgid="4190252696685155002">"ବ୍ୟକ୍ତିଗତ"</string>
- <string name="all_apps_work_tab" msgid="4884822796154055118">"କାମ"</string>
+ <string name="all_apps_work_tab" msgid="4884822796154055118">"ୱାର୍କ"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"ୱର୍କ ପ୍ରୋଫାଇଲ୍"</string>
<string name="work_profile_edu_personal_apps" msgid="4155536355149317441">"ବ୍ୟକ୍ତିଗତ ଡାଟା କାର୍ଯ୍ୟସ୍ଥଳୀ ଆପଗୁଡ଼ିକ ଠାରୁ ପୃଥକ୍ ଓ ଲୁକ୍କାୟିତ ଅଟେ"</string>
<string name="work_profile_edu_work_apps" msgid="237051938268703058">"କାର୍ଯ୍ୟସ୍ଥଳୀ ଆପଗୁଡ଼ିକ ଓ ଡାଟା ଆପଣଙ୍କ IT ଆଡମିନଙ୍କୁ ଦେଖାଯାଏ"</string>
@@ -139,7 +139,7 @@
<string name="work_profile_edu_accept" msgid="6069788082535149071">"ବୁଝିଗଲି"</string>
<string name="work_apps_paused_title" msgid="2389865654362803723">"ୱାର୍କ ପ୍ରୋଫାଇଲକୁ ବିରତ କରାଯାଇଛି"</string>
<string name="work_apps_paused_body" msgid="5388070126389079077">"କାର୍ଯ୍ୟସ୍ଥଳୀ ଆପ୍ ଆପଣଙ୍କୁ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ପଠାଇପାରିବ ନାହିଁ, ଆପଣଙ୍କ ବ୍ୟାଟେରୀକୁ ବ୍ୟବହାର କରିପାରିବ ନାହିଁ କିମ୍ବା ଆପଣଙ୍କ ଲୋକେସନକୁ ଆକ୍ସେସ୍ କରିପାରିବ ନାହିଁ"</string>
- <string name="work_apps_paused_content_description" msgid="7553586952985486433">"ୱାର୍କ ପ୍ରୋଫାଇଲ୍ ବିରତ କରାଯାଇଛି। କାର୍ଯ୍ୟସ୍ଥଳୀ ଆପ୍ ଆପଣଙ୍କୁ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକୁ ପଠାଇପାରିବ ନାହିଁ, ଆପଣଙ୍କ ବ୍ୟାଟେରୀ ବ୍ୟବହାର କରନ୍ତୁ କିମ୍ବା ଆପଣଙ୍କ ଲୋକେସନ୍ ଆକ୍ସେସ୍ କରନ୍ତୁ"</string>
+ <string name="work_apps_paused_content_description" msgid="7553586952985486433">"ୱାର୍କ ପ୍ରୋଫାଇଲ୍ ବିରତ କରାଯାଇଛି। କାର୍ଯ୍ୟସ୍ଥଳୀ ଆପ୍ ଆପଣଙ୍କୁ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ପଠାଇପାରିବ ନାହିଁ, ଆପଣଙ୍କ ବ୍ୟାଟେରୀ ବ୍ୟବହାର କରନ୍ତୁ କିମ୍ବା ଆପଣଙ୍କ ଲୋକେସନ୍ ଆକ୍ସେସ୍ କରନ୍ତୁ"</string>
<string name="work_switch_tip" msgid="808075064383839144">"କାର୍ଯ୍ୟସ୍ଥଳୀ ଆପ୍ ଏବଂ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକୁ ବିରତ କରନ୍ତୁ"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"ବିଫଳ ହୋଇଛି: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index ff4acfa..bfaef66 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -133,10 +133,10 @@
<string name="accessibility_close" msgid="2277148124685870734">"Zamknij"</string>
<string name="notification_dismissed" msgid="6002233469409822874">"Powiadomienie odrzucone"</string>
<string name="all_apps_personal_tab" msgid="4190252696685155002">"Osobiste"</string>
- <string name="all_apps_work_tab" msgid="4884822796154055118">"Służbowe"</string>
- <string name="work_profile_toggle_label" msgid="3081029915775481146">"Profil służbowy"</string>
+ <string name="all_apps_work_tab" msgid="4884822796154055118">"Do pracy"</string>
+ <string name="work_profile_toggle_label" msgid="3081029915775481146">"Profil do pracy"</string>
<string name="work_profile_edu_personal_apps" msgid="4155536355149317441">"Dane osobowe znajdują się w innym miejscu i są niewidoczne dla aplikacji do pracy"</string>
- <string name="work_profile_edu_work_apps" msgid="237051938268703058">"Dane z profilu do pracy są widoczne dla Twojego administratora IT"</string>
+ <string name="work_profile_edu_work_apps" msgid="237051938268703058">"Dane i aplikacje z profilu do pracy są widoczne dla Twojego administratora IT"</string>
<string name="work_profile_edu_next" msgid="8783418929296503629">"Dalej"</string>
<string name="work_profile_edu_accept" msgid="6069788082535149071">"OK"</string>
<string name="work_apps_paused_title" msgid="2389865654362803723">"Wstrzymano profil do pracy"</string>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index b8b4b3d..c6dcc6f 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -21,8 +21,8 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="649227358658669779">"Launcher3"</string>
<string name="work_folder_name" msgid="3753320833950115786">"Trabalho"</string>
- <string name="activity_not_found" msgid="8071924732094499514">"A aplicação não está instalada."</string>
- <string name="activity_not_available" msgid="7456344436509528827">"A aplicação não está disponível"</string>
+ <string name="activity_not_found" msgid="8071924732094499514">"A app não está instalada."</string>
+ <string name="activity_not_available" msgid="7456344436509528827">"A app não está disponível"</string>
<string name="safemode_shortcut_error" msgid="9160126848219158407">"Aplicação transferida desativada no Modo de segurança"</string>
<string name="safemode_widget_error" msgid="4863470563535682004">"Widgets desativados no Modo de segurança"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"O atalho não está disponível"</string>
@@ -36,7 +36,7 @@
<string name="place_automatically" msgid="8064208734425456485">"Adicionar automaticamente"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Pesquisar aplicações"</string>
<string name="all_apps_loading_message" msgid="5813968043155271636">"A carregar aplicações…"</string>
- <string name="all_apps_no_search_results" msgid="3200346862396363786">"Nenhuma aplicação correspondente a \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
+ <string name="all_apps_no_search_results" msgid="3200346862396363786">"Nenhuma app correspondente a \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
<string name="all_apps_search_market_message" msgid="1366263386197059176">"Pesquisar mais aplicações"</string>
<string name="label_application" msgid="8531721983832654978">"Aplicação"</string>
<string name="notifications_header" msgid="1404149926117359025">"Notificações"</string>
@@ -50,23 +50,23 @@
<string name="all_apps_home_button_label" msgid="252062713717058851">"Ecrã principal"</string>
<string name="remove_drop_target_label" msgid="7812859488053230776">"Remover"</string>
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Desinstalar"</string>
- <string name="app_info_drop_target_label" msgid="692894985365717661">"Info. da aplicação"</string>
+ <string name="app_info_drop_target_label" msgid="692894985365717661">"Info. da app"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Instalar"</string>
<string name="permlab_install_shortcut" msgid="5632423390354674437">"instalar atalhos"</string>
- <string name="permdesc_install_shortcut" msgid="923466509822011139">"Permite a uma aplicação adicionar atalhos sem a intervenção do utilizador."</string>
+ <string name="permdesc_install_shortcut" msgid="923466509822011139">"Permite a uma app adicionar atalhos sem a intervenção do utilizador."</string>
<string name="permlab_read_settings" msgid="1941457408239617576">"ler definições e atalhos do Ecrã Principal"</string>
- <string name="permdesc_read_settings" msgid="5833423719057558387">"Permite à aplicação ler as definições e os atalhos no Ecrã Principal."</string>
+ <string name="permdesc_read_settings" msgid="5833423719057558387">"Permite à app ler as definições e os atalhos no Ecrã Principal."</string>
<string name="permlab_write_settings" msgid="3574213698004620587">"escrever definições e atalhos do Ecrã principal"</string>
- <string name="permdesc_write_settings" msgid="5440712911516509985">"Permite à aplicação alterar as definições e os atalhos no Ecrã Principal."</string>
+ <string name="permdesc_write_settings" msgid="5440712911516509985">"Permite à app alterar as definições e os atalhos no Ecrã Principal."</string>
<string name="msg_no_phone_permission" msgid="9208659281529857371">"O <xliff:g id="APP_NAME">%1$s</xliff:g> não tem autorização para efetuar chamadas telefónicas"</string>
<string name="gadget_error_text" msgid="6081085226050792095">"Problema ao carregar o widget"</string>
<string name="gadget_setup_text" msgid="8274003207686040488">"Configuração"</string>
- <string name="uninstall_system_app_text" msgid="4172046090762920660">"É uma aplicação de sistema e não pode ser desinstalada."</string>
+ <string name="uninstall_system_app_text" msgid="4172046090762920660">"É uma app de sistema e não pode ser desinstalada."</string>
<string name="folder_hint_text" msgid="5174843001373488816">"Edite o nome"</string>
<string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> desativado"</string>
<plurals name="dotted_app_label" formatted="false" msgid="5194538107138265416">
- <item quantity="other">A aplicação <xliff:g id="APP_NAME_2">%1$s</xliff:g> tem <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> notificações.</item>
- <item quantity="one">A aplicação <xliff:g id="APP_NAME_0">%1$s</xliff:g> tem <xliff:g id="NOTIFICATION_COUNT_1">%2$d</xliff:g> notificação</item>
+ <item quantity="other">A app <xliff:g id="APP_NAME_2">%1$s</xliff:g> tem <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> notificações.</item>
+ <item quantity="one">A app <xliff:g id="APP_NAME_0">%1$s</xliff:g> tem <xliff:g id="NOTIFICATION_COUNT_1">%2$d</xliff:g> notificação</item>
</plurals>
<string name="default_scroll_format" msgid="7475544710230993317">"Página %1$d de %2$d"</string>
<string name="workspace_scroll_format" msgid="8458889198184077399">"Ecrã principal %1$d de %2$d"</string>
@@ -96,8 +96,8 @@
<string name="package_state_unknown" msgid="7592128424511031410">"Desconhecido"</string>
<string name="abandoned_clean_this" msgid="7610119707847920412">"Remover"</string>
<string name="abandoned_search" msgid="891119232568284442">"Pesquisar"</string>
- <string name="abandoned_promises_title" msgid="7096178467971716750">"Esta aplicação não está instalada"</string>
- <string name="abandoned_promise_explanation" msgid="3990027586878167529">"A aplicação deste ícone não está instalada. Pode removê-lo ou pesquisar a aplicação e instalá-la manualmente."</string>
+ <string name="abandoned_promises_title" msgid="7096178467971716750">"Esta app não está instalada"</string>
+ <string name="abandoned_promise_explanation" msgid="3990027586878167529">"A app deste ícone não está instalada. Pode removê-lo ou pesquisar a app e instalá-la manualmente."</string>
<string name="app_downloading_title" msgid="8336702962104482644">"A transferir o <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="PROGRESS">%2$s</xliff:g> concluído"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"A aguardar a instalação do <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"Widgets de <xliff:g id="NAME">%1$s</xliff:g>"</string>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index 656ef2b..bf0b837 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -131,7 +131,7 @@
<string name="accessibility_close" msgid="2277148124685870734">"Fechar"</string>
<string name="notification_dismissed" msgid="6002233469409822874">"Notificação dispensada"</string>
<string name="all_apps_personal_tab" msgid="4190252696685155002">"Pessoais"</string>
- <string name="all_apps_work_tab" msgid="4884822796154055118">"Comerciais"</string>
+ <string name="all_apps_work_tab" msgid="4884822796154055118">"Trabalho"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Perfil de trabalho"</string>
<string name="work_profile_edu_personal_apps" msgid="4155536355149317441">"Os dados pessoais ficam separados e ocultos dos apps de trabalho"</string>
<string name="work_profile_edu_work_apps" msgid="237051938268703058">"Os dados de apps de trabalho ficam visíveis para seu administrador de TI"</string>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index 12ccaf6..084bbdb 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -136,7 +136,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Рабочие"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Рабочий профиль"</string>
<string name="work_profile_edu_personal_apps" msgid="4155536355149317441">"Личные данные скрыты от рабочих приложений и недоступны им"</string>
- <string name="work_profile_edu_work_apps" msgid="237051938268703058">"Рабочие приложения и данные видны системному администратору"</string>
+ <string name="work_profile_edu_work_apps" msgid="237051938268703058">"Рабочие приложения и данные видны системному администратору."</string>
<string name="work_profile_edu_next" msgid="8783418929296503629">"Далее"</string>
<string name="work_profile_edu_accept" msgid="6069788082535149071">"ОК"</string>
<string name="work_apps_paused_title" msgid="2389865654362803723">"Рабочий профиль приостановлен"</string>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index 4bbc9b3..12e58fc 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -135,13 +135,13 @@
<string name="all_apps_personal_tab" msgid="4190252696685155002">"Osobné"</string>
<string name="all_apps_work_tab" msgid="4884822796154055118">"Pracovné"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Pracovný profil"</string>
- <string name="work_profile_edu_personal_apps" msgid="4155536355149317441">"Osobné údaje sú od pracovných aplikácií oddelené a nie je ich vidieť"</string>
- <string name="work_profile_edu_work_apps" msgid="237051938268703058">"Pracovné aplikácie a údaje vidí správca IT"</string>
+ <string name="work_profile_edu_personal_apps" msgid="4155536355149317441">"Osobné údaje sú oddelené a sú pred pracovnými aplikáciami skryté"</string>
+ <string name="work_profile_edu_work_apps" msgid="237051938268703058">"Pracovné aplikácie a údaje môže vidieť váš správca IT"</string>
<string name="work_profile_edu_next" msgid="8783418929296503629">"Ďalej"</string>
<string name="work_profile_edu_accept" msgid="6069788082535149071">"Dobre"</string>
<string name="work_apps_paused_title" msgid="2389865654362803723">"Pracovný profil je pozastavený"</string>
<string name="work_apps_paused_body" msgid="5388070126389079077">"Pracovné aplikácie nemôžu posielať upozornenia, používať batériu ani polohu"</string>
<string name="work_apps_paused_content_description" msgid="7553586952985486433">"Pracovný profil je pozastavený. Pracovné aplikácie nemôžu posielať upozornenia, používať batériu ani polohu"</string>
- <string name="work_switch_tip" msgid="808075064383839144">"Pozastavenie pracovných aplikácií a upozornení"</string>
+ <string name="work_switch_tip" msgid="808075064383839144">"Pozastavte pracovné aplikácie a upozornenia"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Zlyhalo: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index eaa6bce..c41f12b 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -133,14 +133,14 @@
<string name="notification_dismissed" msgid="6002233469409822874">"Обавештење је одбачено"</string>
<string name="all_apps_personal_tab" msgid="4190252696685155002">"Личне"</string>
<string name="all_apps_work_tab" msgid="4884822796154055118">"Пословне"</string>
- <string name="work_profile_toggle_label" msgid="3081029915775481146">"Профил за Work"</string>
+ <string name="work_profile_toggle_label" msgid="3081029915775481146">"Пословни профил"</string>
<string name="work_profile_edu_personal_apps" msgid="4155536355149317441">"Лични подаци су одвојени и сакривени од апликација за посао"</string>
- <string name="work_profile_edu_work_apps" msgid="237051938268703058">"ИТ администратор види апликације за посао и податке"</string>
+ <string name="work_profile_edu_work_apps" msgid="237051938268703058">"ИТ администратор види пословне апликације и податке"</string>
<string name="work_profile_edu_next" msgid="8783418929296503629">"Даље"</string>
<string name="work_profile_edu_accept" msgid="6069788082535149071">"Важи"</string>
- <string name="work_apps_paused_title" msgid="2389865654362803723">"Профил за Work је паузиран"</string>
- <string name="work_apps_paused_body" msgid="5388070126389079077">"Апликације за посао не могу да вам шаљу обавештења, користе батерију ни приступају локацији"</string>
- <string name="work_apps_paused_content_description" msgid="7553586952985486433">"Профил за Work је паузиран. Апликације за посао не могу да вам шаљу обавештења, користе батерију нити приступају локацији"</string>
- <string name="work_switch_tip" msgid="808075064383839144">"Паузирајте апликације за посао и обавештења"</string>
+ <string name="work_apps_paused_title" msgid="2389865654362803723">"Пословни профил је паузиран"</string>
+ <string name="work_apps_paused_body" msgid="5388070126389079077">"Пословне апликације не могу да вам шаљу обавештења, користе батерију ни приступају локацији"</string>
+ <string name="work_apps_paused_content_description" msgid="7553586952985486433">"Пословни профил је паузиран. Пословне апликације не могу да вам шаљу обавештења, користе батерију нити приступају локацији"</string>
+ <string name="work_switch_tip" msgid="808075064383839144">"Паузирајте пословне апликације и обавештења"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Није успело: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index 6a6bb76..77c6aad 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -136,7 +136,7 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Kazini"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Wasifu wa kazini"</string>
<string name="work_profile_edu_personal_apps" msgid="4155536355149317441">"Data ya binafsi ni tofauti na haionyeshwi kwenye programu za kazini"</string>
- <string name="work_profile_edu_work_apps" msgid="237051938268703058">"Programu na data ya kazini huonyeshwa kwa msimamizi wako wa TEHAMA"</string>
+ <string name="work_profile_edu_work_apps" msgid="237051938268703058">"Programu na data ya kazini huonekana kwa msimamizi wako wa TEHAMA"</string>
<string name="work_profile_edu_next" msgid="8783418929296503629">"Endelea"</string>
<string name="work_profile_edu_accept" msgid="6069788082535149071">"Nimeelewa"</string>
<string name="work_apps_paused_title" msgid="2389865654362803723">"Wasifu wa kazini umesimamishwa"</string>
diff --git a/res/values-sw600dp/config.xml b/res/values-sw600dp/config.xml
index eb9af97..09bdaaf 100644
--- a/res/values-sw600dp/config.xml
+++ b/res/values-sw600dp/config.xml
@@ -1,4 +1,3 @@
<resources>
- <bool name="is_tablet">true</bool>
<bool name="allow_rotation">true</bool>
</resources>
diff --git a/res/values-sw720dp/config.xml b/res/values-sw720dp/config.xml
index 94cffcb..1f401c4 100644
--- a/res/values-sw720dp/config.xml
+++ b/res/values-sw720dp/config.xml
@@ -1,6 +1,5 @@
<resources>
<bool name="config_largeHeap">true</bool>
- <bool name="is_large_tablet">true</bool>
<!-- All Apps & Widgets -->
<!-- Out of 100, the percent to shrink the workspace during spring loaded mode. -->
diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml
index 08f987e..eb8823d 100644
--- a/res/values-uz/strings.xml
+++ b/res/values-uz/strings.xml
@@ -46,7 +46,7 @@
<string name="hotseat_out_of_space" msgid="7448809638125333693">"Ajratilganlarda birorta ham xona yo‘q"</string>
<string name="all_apps_button_label" msgid="8130441508702294465">"Ilovalar ro‘yxati"</string>
<string name="all_apps_button_personal_label" msgid="1315764287305224468">"Shaxsiy ilovalar ro‘yxati"</string>
- <string name="all_apps_button_work_label" msgid="7270707118948892488">"Ishchi ilovalar ro‘yxati"</string>
+ <string name="all_apps_button_work_label" msgid="7270707118948892488">"Ishga oid ilovalar ro‘yxati"</string>
<string name="all_apps_home_button_label" msgid="252062713717058851">"Bosh sahifa"</string>
<string name="remove_drop_target_label" msgid="7812859488053230776">"Olib tashlash"</string>
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"O‘chirib tashlash"</string>
@@ -131,8 +131,8 @@
<string name="accessibility_close" msgid="2277148124685870734">"Yopish"</string>
<string name="notification_dismissed" msgid="6002233469409822874">"Bildirishnoma yopildi"</string>
<string name="all_apps_personal_tab" msgid="4190252696685155002">"Shaxsiy"</string>
- <string name="all_apps_work_tab" msgid="4884822796154055118">"Ishchi"</string>
- <string name="work_profile_toggle_label" msgid="3081029915775481146">"Ishchi profil"</string>
+ <string name="all_apps_work_tab" msgid="4884822796154055118">"Ish"</string>
+ <string name="work_profile_toggle_label" msgid="3081029915775481146">"Ish profili"</string>
<string name="work_profile_edu_personal_apps" msgid="4155536355149317441">"Shaxsiy maʼlumotlar ishga oid ilovalardan alohida va berkitilgan"</string>
<string name="work_profile_edu_work_apps" msgid="237051938268703058">"Ishga oid ilovalar va maʼlumotlarni AT administratoringiz koʻra oladi"</string>
<string name="work_profile_edu_next" msgid="8783418929296503629">"Keyingisi"</string>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index 314195e..e9b6db1 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -134,11 +134,11 @@
<string name="all_apps_work_tab" msgid="4884822796154055118">"Cơ quan"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Hồ sơ công việc"</string>
<string name="work_profile_edu_personal_apps" msgid="4155536355149317441">"Dữ liệu cá nhân được lưu trữ riêng biệt và ẩn khỏi các ứng dụng công việc"</string>
- <string name="work_profile_edu_work_apps" msgid="237051938268703058">"Quản trị viên CNTT của bạn có thể xem ứng dụng công việc và dữ liệu"</string>
+ <string name="work_profile_edu_work_apps" msgid="237051938268703058">"Quản trị viên CNTT của bạn có thể xem dữ liệu và các ứng dụng công việc"</string>
<string name="work_profile_edu_next" msgid="8783418929296503629">"Tiếp theo"</string>
<string name="work_profile_edu_accept" msgid="6069788082535149071">"OK"</string>
<string name="work_apps_paused_title" msgid="2389865654362803723">"Hồ sơ công việc của bạn đã bị tạm dừng"</string>
- <string name="work_apps_paused_body" msgid="5388070126389079077">"Ứng dụng công việc không thể gửi thông báo cho bạn, sử dụng pin hoặc xem dữ liệu vị trí"</string>
+ <string name="work_apps_paused_body" msgid="5388070126389079077">"Các ứng dụng công việc không thể gửi thông báo cho bạn, sử dụng pin hoặc truy cập thông tin vị trí của bạn"</string>
<string name="work_apps_paused_content_description" msgid="7553586952985486433">"Hồ sơ công việc của bạn đã bị tạm dừng. Các ứng dụng công việc không thể: gửi thông báo cho bạn, sử dụng pin hoặc xem dữ liệu vị trí"</string>
<string name="work_switch_tip" msgid="808075064383839144">"Tạm dừng các ứng dụng và thông báo liên quan tới công việc"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Không thực hiện được thao tác: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index eb448e5..c302f71 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -133,13 +133,13 @@
<string name="all_apps_personal_tab" msgid="4190252696685155002">"个人"</string>
<string name="all_apps_work_tab" msgid="4884822796154055118">"工作"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"工作资料"</string>
- <string name="work_profile_edu_personal_apps" msgid="4155536355149317441">"个人数据与工作应用相互独立,两者不会同时显示"</string>
+ <string name="work_profile_edu_personal_apps" msgid="4155536355149317441">"工作应用与个人数据相互独立,它们无法获取此类数据"</string>
<string name="work_profile_edu_work_apps" msgid="237051938268703058">"您的 IT 管理员可以查看工作应用和工作数据"</string>
<string name="work_profile_edu_next" msgid="8783418929296503629">"继续"</string>
<string name="work_profile_edu_accept" msgid="6069788082535149071">"知道了"</string>
- <string name="work_apps_paused_title" msgid="2389865654362803723">"工作资料已暂停使用"</string>
- <string name="work_apps_paused_body" msgid="5388070126389079077">"工作应用无法向您发送通知、使用电池电量,也无法获取您的位置信息"</string>
- <string name="work_apps_paused_content_description" msgid="7553586952985486433">"工作资料已暂停使用。工作应用无法向您发送通知、不能使用电池电量,也无法获取您的位置信息"</string>
+ <string name="work_apps_paused_title" msgid="2389865654362803723">"工作资料已被暂停"</string>
+ <string name="work_apps_paused_body" msgid="5388070126389079077">"现在,工作应用无法向您发送通知、不能耗用电池电量,也无法获取您的位置信息"</string>
+ <string name="work_apps_paused_content_description" msgid="7553586952985486433">"工作资料已被暂停。现在,工作应用无法向您发送通知、不能耗用电池电量,也无法获取您的位置信息"</string>
<string name="work_switch_tip" msgid="808075064383839144">"暂停工作应用和工作通知"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"失败:<xliff:g id="WHAT">%1$s</xliff:g>"</string>
</resources>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index d4cb6d7..2875006 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -35,6 +35,7 @@
<attr name="widgetsTheme" format="reference" />
<attr name="loadingIconColor" format="color" />
<attr name="iconOnlyShortcutColor" format="color"/>
+ <attr name="eduHalfSheetBGColor" format="color"/>
<attr name="folderDotColor" format="color" />
<attr name="folderFillColor" format="color" />
diff --git a/res/values/config.xml b/res/values/config.xml
index 41bb909..603dc91 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -1,8 +1,6 @@
<resources>
<!-- Miscellaneous -->
<bool name="config_largeHeap">false</bool>
- <bool name="is_tablet">false</bool>
- <bool name="is_large_tablet">false</bool>
<bool name="allow_rotation">false</bool>
<integer name="extracted_color_gradient_alpha">153</integer>
@@ -132,7 +130,7 @@
<item name="dismiss_task_trans_x_stiffness" type="dimen" format="float">800</item>
<item name="horizontal_spring_damping_ratio" type="dimen" format="float">0.8</item>
- <item name="horizontal_spring_stiffness" type="dimen" format="float">400</item>
+ <item name="horizontal_spring_stiffness" type="dimen" format="float">250</item>
<item name="swipe_up_rect_scale_damping_ratio" type="dimen" format="float">0.75</item>
<item name="swipe_up_rect_scale_stiffness" type="dimen" format="float">200</item>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 5f4bd8e..2efa66f 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -103,9 +103,9 @@
<!-- Label for install drop target. [CHAR_LIMIT=20] -->
<string name="install_drop_target_label">Install</string>
<!-- Label for install dismiss prediction. -->
- <string translatable="false" name="dismiss_prediction_label">Don\'t suggest app</string>
+ <string name="dismiss_prediction_label">Don\'t suggest app</string>
<!-- Label for pinning predicted app. -->
- <string name="pin_prediction" translatable="false">Pin Prediction</string>
+ <string name="pin_prediction">Pin Prediction</string>
<!-- Permissions: -->
@@ -342,7 +342,7 @@
<!--- heading shown when user opens work apps tab while work apps are paused -->
<string name="work_apps_paused_title">Work profile is paused</string>
<!--- body shown when user opens work apps tab while work apps are paused -->
- <string name="work_apps_paused_body">Work apps can\’t send you notifications, use your battery, or access your location</string>
+ <string name="work_apps_paused_body">Work apps can\'t send you notifications, use your battery, or access your location</string>
<!-- content description for paused work apps list -->
<string name="work_apps_paused_content_description">Work profile is paused. Work apps can\’t send you notifications, use your battery, or access your location</string>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index a2c0f23..26b7205 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -53,6 +53,7 @@
<item name="loadingIconColor">#CCFFFFFF</item>
<item name="iconOnlyShortcutColor">?android:attr/textColorSecondary</item>
<item name="workProfileOverlayTextColor">#FF212121</item>
+ <item name="eduHalfSheetBGColor">?android:attr/colorAccent</item>
<item name="android:windowTranslucentStatus">false</item>
<item name="android:windowTranslucentNavigation">false</item>
@@ -90,7 +91,7 @@
<item name="android:textColorHint">#A0FFFFFF</item>
<item name="android:colorControlHighlight">#A0FFFFFF</item>
<item name="android:colorPrimary">#FF212121</item>
- <item name="allAppsScrimColor">#FF212121</item>
+ <item name="allAppsScrimColor">#FF000000</item>
<item name="allAppsInterimScrimAlpha">102</item>
<item name="allAppsNavBarScrimColor">#80000000</item>
<item name="popupColorPrimary">#3C4043</item> <!-- Gray 800 -->
@@ -106,6 +107,7 @@
<item name="loadingIconColor">#99FFFFFF</item>
<item name="iconOnlyShortcutColor">#B3FFFFFF</item>
<item name="workProfileOverlayTextColor">@android:color/white</item>
+ <item name="eduHalfSheetBGColor">#DD000000</item>
</style>
<style name="LauncherTheme.Dark.DarkMainColor" parent="@style/LauncherTheme.Dark">
@@ -229,9 +231,7 @@
<style name="TextHeadline" parent="@android:style/TextAppearance.DeviceDefault.DialogWindowTitle" />
<style name="PrimaryMediumText" parent="@android:style/TextAppearance.DeviceDefault.Medium"/>
- <style name="PrimaryHeadline" parent="@android:style/TextAppearance.DeviceDefault.DialogWindowTitle">
- <item name="android:textStyle">bold</item>
- </style>
+ <style name="PrimaryHeadline" parent="@android:style/TextAppearance.DeviceDefault.DialogWindowTitle"/>
<style name="TextTitle" parent="@android:style/TextAppearance.DeviceDefault" />
diff --git a/src/com/android/launcher3/BaseDraggingActivity.java b/src/com/android/launcher3/BaseDraggingActivity.java
index e4f201c..239d8a3 100644
--- a/src/com/android/launcher3/BaseDraggingActivity.java
+++ b/src/com/android/launcher3/BaseDraggingActivity.java
@@ -16,7 +16,7 @@
package com.android.launcher3;
-import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.APP_LAUNCH_TAP;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_TAP;
import static com.android.launcher3.util.DefaultDisplay.CHANGE_ROTATION;
import android.app.ActivityOptions;
@@ -24,6 +24,7 @@
import android.content.Intent;
import android.content.pm.LauncherApps;
import android.content.res.Configuration;
+import android.graphics.Point;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.Process;
@@ -31,6 +32,7 @@
import android.os.UserHandle;
import android.util.Log;
import android.view.ActionMode;
+import android.view.Display;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Toast;
@@ -181,9 +183,8 @@
sourceContainer);
}
getUserEventDispatcher().logAppLaunch(v, intent, user);
-
- getStatsLogManager().log(APP_LAUNCH_TAP, item == null ? null
- : item.buildProto(null, null));
+ getStatsLogManager().log(LAUNCHER_APP_LAUNCH_TAP, item == null ? null
+ : item.buildProto(null));
return true;
} catch (NullPointerException|ActivityNotFoundException|SecurityException e) {
Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
@@ -270,4 +271,16 @@
}
protected abstract void reapplyUi();
+
+ protected Rect getMultiWindowDisplaySize() {
+ if (Utilities.ATLEAST_R) {
+ return new Rect(getWindowManager().getCurrentWindowMetrics().getBounds());
+ }
+ // Note: Calls to getSize() can't rely on our cached DefaultDisplay since it can return
+ // the app window size
+ Display display = getWindowManager().getDefaultDisplay();
+ Point mwSize = new Point();
+ display.getSize(mwSize);
+ return new Rect(0, 0, mwSize.x, mwSize.y);
+ }
}
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index d7d4a27..79ed2b8 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -722,11 +722,27 @@
}
@Override
- public void getVisualDragBounds(Rect bounds) {
+ public void getWorkspaceVisualDragBounds(Rect bounds) {
DeviceProfile grid = mActivity.getDeviceProfile();
BubbleTextView.getIconBounds(this, bounds, grid.iconSizePx);
}
+ private int getIconSizeForDisplay(int display) {
+ DeviceProfile grid = mActivity.getDeviceProfile();
+ switch (display) {
+ case DISPLAY_ALL_APPS:
+ return grid.allAppsIconSizePx;
+ case DISPLAY_WORKSPACE:
+ case DISPLAY_FOLDER:
+ default:
+ return grid.iconSizePx;
+ }
+ }
+
+ public void getSourceVisualDragBounds(Rect bounds) {
+ BubbleTextView.getIconBounds(this, bounds, getIconSizeForDisplay(mDisplay));
+ }
+
@Override
public void prepareDrawDragView() {
if (getIcon() instanceof FastBitmapDrawable) {
diff --git a/src/com/android/launcher3/DeleteDropTarget.java b/src/com/android/launcher3/DeleteDropTarget.java
index b4c5f96..d75d712 100644
--- a/src/com/android/launcher3/DeleteDropTarget.java
+++ b/src/com/android/launcher3/DeleteDropTarget.java
@@ -16,6 +16,8 @@
package com.android.launcher3;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ITEM_DROPPED_ON_CANCEL;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ITEM_DROPPED_ON_REMOVE;
import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch.TAP;
import static com.android.launcher3.userevent.nano.LauncherLogProto.ControlType.UNDO;
@@ -27,6 +29,7 @@
import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.logging.LoggerUtils;
+import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.model.ModelWriter;
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
@@ -38,6 +41,8 @@
public class DeleteDropTarget extends ButtonDropTarget {
+ private final StatsLogManager mStatsLogManager;
+
private int mControlType = ControlType.DEFAULT_CONTROLTYPE;
public DeleteDropTarget(Context context, AttributeSet attrs) {
@@ -46,6 +51,7 @@
public DeleteDropTarget(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
+ this.mStatsLogManager = StatsLogManager.newInstance(context);
}
@Override
@@ -120,6 +126,11 @@
d.dragInfo.container = NO_ID;
}
super.onDrop(d, options);
+ mStatsLogManager.log(
+ mControlType == ControlType.REMOVE_TARGET
+ ? LAUNCHER_ITEM_DROPPED_ON_REMOVE
+ : LAUNCHER_ITEM_DROPPED_ON_CANCEL,
+ d.logInstanceId);
}
@Override
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index a5f98c0..51b21aa 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -32,6 +32,10 @@
public class DeviceProfile {
+ private static final float TABLET_MIN_DPS = 600;
+ private static final float LARGE_TABLET_MIN_DPS = 720;
+
+
public final InvariantDeviceProfile inv;
private final DefaultDisplay.Info mInfo;
@@ -45,6 +49,8 @@
public final boolean isLandscape;
public final boolean isMultiWindowMode;
+ public final int windowX;
+ public final int windowY;
public final int widthPx;
public final int heightPx;
public final int availableWidthPx;
@@ -133,13 +139,16 @@
public DotRenderer mDotRendererWorkSpace;
public DotRenderer mDotRendererAllApps;
- public DeviceProfile(Context context, InvariantDeviceProfile inv, DefaultDisplay.Info info,
+ DeviceProfile(Context context, InvariantDeviceProfile inv, DefaultDisplay.Info info,
Point minSize, Point maxSize, int width, int height, boolean isLandscape,
- boolean isMultiWindowMode, boolean transposeLayoutWithOrientation) {
+ boolean isMultiWindowMode, boolean transposeLayoutWithOrientation,
+ Point windowPosition) {
this.inv = inv;
this.isLandscape = isLandscape;
this.isMultiWindowMode = isMultiWindowMode;
+ windowX = windowPosition.x;
+ windowY = windowPosition.y;
// Determine sizes.
widthPx = width;
@@ -153,11 +162,12 @@
}
mInfo = info;
- Resources res = context.getResources();
// Constants from resources
- isTablet = res.getBoolean(R.bool.is_tablet);
- isLargeTablet = res.getBoolean(R.bool.is_large_tablet);
+ float swDPs = Utilities.dpiFromPx(
+ Math.min(info.smallestSize.x, info.smallestSize.y), info.metrics);
+ isTablet = swDPs >= TABLET_MIN_DPS;
+ isLargeTablet = swDPs >= LARGE_TABLET_MIN_DPS;
isPhone = !isTablet && !isLargeTablet;
aspectRatio = ((float) Math.max(widthPx, heightPx)) / Math.min(widthPx, heightPx);
boolean isTallDevice = Float.compare(aspectRatio, TALL_DEVICE_ASPECT_RATIO_THRESHOLD) >= 0;
@@ -165,10 +175,10 @@
// Some more constants
this.transposeLayoutWithOrientation = transposeLayoutWithOrientation;
- context = getContext(context, isVerticalBarLayout()
+ context = getContext(context, info, isVerticalBarLayout()
? Configuration.ORIENTATION_LANDSCAPE
: Configuration.ORIENTATION_PORTRAIT);
- res = context.getResources();
+ final Resources res = context.getResources();
edgeMarginPx = res.getDimensionPixelSize(R.dimen.dynamic_grid_edge_margin);
desiredWorkspaceLeftRightMarginPx = isVerticalBarLayout() ? 0 : edgeMarginPx;
@@ -244,6 +254,7 @@
return new Builder(context, inv, mInfo)
.setSizeRange(size, size)
.setSize(widthPx, heightPx)
+ .setWindowPosition(windowX, windowY)
.setMultiWindowMode(isMultiWindowMode);
}
@@ -254,10 +265,11 @@
/**
* TODO: Move this to the builder as part of setMultiWindowMode
*/
- public DeviceProfile getMultiWindowProfile(Context context, Point mwSize) {
+ public DeviceProfile getMultiWindowProfile(Context context, Rect windowPosition) {
// We take the minimum sizes of this profile and it's multi-window variant to ensure that
// the system decor is always excluded.
- mwSize.set(Math.min(availableWidthPx, mwSize.x), Math.min(availableHeightPx, mwSize.y));
+ Point mwSize = new Point(Math.min(availableWidthPx, windowPosition.width()),
+ Math.min(availableHeightPx, windowPosition.height()));
// In multi-window mode, we can have widthPx = availableWidthPx
// and heightPx = availableHeightPx because Launcher uses the InvariantDeviceProfiles'
@@ -265,6 +277,7 @@
DeviceProfile profile = toBuilder(context)
.setSizeRange(mwSize, mwSize)
.setSize(mwSize.x, mwSize.y)
+ .setWindowPosition(windowPosition.left, windowPosition.top)
.setMultiWindowMode(true)
.build();
@@ -286,7 +299,7 @@
}
/**
- * Inverse of {@link #getMultiWindowProfile(Context, Point)}
+ * Inverse of {@link #getMultiWindowProfile(Context, Rect)}
* @return device profile corresponding to the current orientation in non multi-window mode.
*/
public DeviceProfile getFullScreenProfile() {
@@ -624,10 +637,11 @@
}
}
- private static Context getContext(Context c, int orientation) {
- Configuration context = new Configuration(c.getResources().getConfiguration());
- context.orientation = orientation;
- return c.createConfigurationContext(context);
+ private static Context getContext(Context c, DefaultDisplay.Info info, int orientation) {
+ Configuration config = new Configuration(c.getResources().getConfiguration());
+ config.orientation = orientation;
+ config.densityDpi = info.metrics.densityDpi;
+ return c.createConfigurationContext(config);
}
/**
@@ -649,6 +663,7 @@
private InvariantDeviceProfile mInv;
private DefaultDisplay.Info mInfo;
+ private final Point mWindowPosition = new Point();
private Point mMinSize, mMaxSize;
private int mWidth, mHeight;
@@ -682,6 +697,14 @@
return this;
}
+ /**
+ * Sets the window position if not full-screen
+ */
+ public Builder setWindowPosition(int x, int y) {
+ mWindowPosition.set(x, y);
+ return this;
+ }
+
public Builder setTransposeLayoutWithOrientation(boolean transposeLayoutWithOrientation) {
mTransposeLayoutWithOrientation = transposeLayoutWithOrientation;
return this;
@@ -690,7 +713,7 @@
public DeviceProfile build() {
return new DeviceProfile(mContext, mInv, mInfo, mMinSize, mMaxSize,
mWidth, mHeight, mIsLandscape, mIsMultiWindowMode,
- mTransposeLayoutWithOrientation);
+ mTransposeLayoutWithOrientation, mWindowPosition);
}
}
diff --git a/src/com/android/launcher3/DropTarget.java b/src/com/android/launcher3/DropTarget.java
index 0a0f9ad..0b0983c 100644
--- a/src/com/android/launcher3/DropTarget.java
+++ b/src/com/android/launcher3/DropTarget.java
@@ -25,6 +25,8 @@
import com.android.launcher3.dragndrop.DragView;
import com.android.launcher3.dragndrop.DraggableView;
import com.android.launcher3.folder.FolderNameProvider;
+import com.android.launcher3.logging.InstanceId;
+import com.android.launcher3.logging.InstanceIdSequence;
import com.android.launcher3.model.data.ItemInfo;
/**
@@ -75,6 +77,11 @@
* DragView represents. May be an actual View class or a virtual stand-in */
public DraggableView originalView = null;
+ /** Used for matching DROP event with its corresponding DRAG event on the server side. */
+ public final InstanceId logInstanceId =
+ new InstanceIdSequence(1 << 20 /*InstanceId.INSTANCE_ID_MAX*/)
+ .newInstanceId();
+
public DragObject(Context context) {
if (FeatureFlags.FOLDER_NAME_SUGGEST.get()) {
folderNameProvider = FolderNameProvider.newInstance(context);
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 070a392..59476dd 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -18,23 +18,30 @@
import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
+import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED;
import static com.android.launcher3.AbstractFloatingView.TYPE_ALL;
import static com.android.launcher3.AbstractFloatingView.TYPE_REBIND_SAFE;
import static com.android.launcher3.AbstractFloatingView.TYPE_SNACKBAR;
+import static com.android.launcher3.InstallShortcutReceiver.FLAG_DRAG_AND_DROP;
import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
import static com.android.launcher3.LauncherState.ALL_APPS;
+import static com.android.launcher3.LauncherState.FLAG_CLOSE_POPUPS;
+import static com.android.launcher3.LauncherState.FLAG_MULTI_PAGE;
+import static com.android.launcher3.LauncherState.FLAG_NON_INTERACTIVE;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.NO_OFFSET;
import static com.android.launcher3.LauncherState.NO_SCALE;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.LauncherState.OVERVIEW_PEEK;
+import static com.android.launcher3.LauncherState.SPRING_LOADED;
import static com.android.launcher3.Utilities.postAsyncCallback;
import static com.android.launcher3.dragndrop.DragLayer.ALPHA_INDEX_LAUNCHER_LOAD;
import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
import static com.android.launcher3.popup.SystemShortcut.APP_INFO;
import static com.android.launcher3.popup.SystemShortcut.INSTALL;
import static com.android.launcher3.popup.SystemShortcut.WIDGETS;
+import static com.android.launcher3.states.RotationHelper.REQUEST_LOCK;
import static com.android.launcher3.states.RotationHelper.REQUEST_NONE;
import android.animation.Animator;
@@ -57,11 +64,9 @@
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.database.sqlite.SQLiteDatabase;
-import android.graphics.Point;
import android.os.Build;
import android.os.Bundle;
import android.os.CancellationSignal;
-import android.os.Handler;
import android.os.Parcelable;
import android.os.Process;
import android.os.StrictMode;
@@ -69,7 +74,6 @@
import android.text.method.TextKeyListener;
import android.util.Log;
import android.util.SparseArray;
-import android.view.Display;
import android.view.KeyEvent;
import android.view.KeyboardShortcutGroup;
import android.view.KeyboardShortcutInfo;
@@ -82,18 +86,19 @@
import android.view.animation.OvershootInterpolator;
import android.widget.Toast;
+import androidx.annotation.CallSuper;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import androidx.annotation.VisibleForTesting;
import com.android.launcher3.DropTarget.DragObject;
-import com.android.launcher3.LauncherStateManager.StateHandler;
import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
import com.android.launcher3.allapps.AllAppsContainerView;
import com.android.launcher3.allapps.AllAppsStore;
import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.allapps.DiscoveryBounce;
import com.android.launcher3.anim.PropertyListBuilder;
+import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dot.DotInfo;
import com.android.launcher3.dragndrop.DragController;
@@ -124,6 +129,10 @@
import com.android.launcher3.popup.PopupDataProvider;
import com.android.launcher3.popup.SystemShortcut;
import com.android.launcher3.qsb.QsbContainerView;
+import com.android.launcher3.statemanager.StateManager;
+import com.android.launcher3.statemanager.StateManager.StateHandler;
+import com.android.launcher3.statemanager.StateManager.StateListener;
+import com.android.launcher3.statemanager.StatefulActivity;
import com.android.launcher3.states.RotationHelper;
import com.android.launcher3.testing.TestLogging;
import com.android.launcher3.testing.TestProtocol;
@@ -187,7 +196,7 @@
/**
* Default launcher application.
*/
-public class Launcher extends BaseDraggingActivity implements LauncherExterns,
+public class Launcher extends StatefulActivity<LauncherState> implements LauncherExterns,
Callbacks, InvariantDeviceProfile.OnIDPChangeListener, PluginListener<OverlayPlugin> {
public static final String TAG = "Launcher";
@@ -234,7 +243,7 @@
public static final String ON_RESUME_EVT = "Launcher.onResume";
public static final String ON_NEW_INTENT_EVT = "Launcher.onNewIntent";
- private LauncherStateManager mStateManager;
+ private StateManager<LauncherState> mStateManager;
private static final int ON_ACTIVITY_RESULT_ANIMATION_DELAY = 500;
@@ -318,10 +327,6 @@
private RotationHelper mRotationHelper;
- final Handler mHandler = new Handler();
- private final Runnable mHandleDeferredResume = this::handleDeferredResume;
- private boolean mDeferredResumePending;
-
private float mCurrentAssistantVisibility = 0f;
protected LauncherOverlayManager mOverlayManager;
@@ -368,9 +373,9 @@
mDragController = new DragController(this);
mAllAppsController = new AllAppsTransitionController(this);
- mStateManager = new LauncherStateManager(this);
+ mStateManager = new StateManager<>(this, NORMAL);
- mOnboardingPrefs = createOnboardingPrefs(mSharedPrefs, mStateManager);
+ mOnboardingPrefs = createOnboardingPrefs(mSharedPrefs);
mAppWidgetManager = new WidgetManagerHelper(this);
mAppWidgetHost = new LauncherAppWidgetHost(this,
@@ -433,7 +438,7 @@
mRotationHelper.initialize();
- mStateManager.addStateListener(new LauncherStateManager.StateListener() {
+ mStateManager.addStateListener(new StateListener<LauncherState>() {
@Override
public void onStateTransitionComplete(LauncherState finalState) {
@@ -460,9 +465,8 @@
return new LauncherOverlayManager() { };
}
- protected OnboardingPrefs createOnboardingPrefs(SharedPreferences sharedPrefs,
- LauncherStateManager stateManager) {
- return new OnboardingPrefs<>(this, sharedPrefs, stateManager);
+ protected OnboardingPrefs createOnboardingPrefs(SharedPreferences sharedPrefs) {
+ return new OnboardingPrefs<>(this, sharedPrefs);
}
public OnboardingPrefs getOnboardingPrefs() {
@@ -516,13 +520,9 @@
}
@Override
- public void reapplyUi() {
- reapplyUi(true /* cancelCurrentAnimation */);
- }
-
public void reapplyUi(boolean cancelCurrentAnimation) {
getRootView().dispatchInsets();
- getStateManager().reapplyState(cancelCurrentAnimation);
+ super.reapplyUi(cancelCurrentAnimation);
}
@Override
@@ -560,12 +560,8 @@
// Load configuration-specific DeviceProfile
mDeviceProfile = idp.getDeviceProfile(this);
if (isInMultiWindowMode()) {
- // Note: Calls to getSize() can't rely on our cached DefaultDisplay since it can return
- // the app window size
- Display display = getWindowManager().getDefaultDisplay();
- Point mwSize = new Point();
- display.getSize(mwSize);
- mDeviceProfile = mDeviceProfile.getMultiWindowProfile(this, mwSize);
+ mDeviceProfile = mDeviceProfile.getMultiWindowProfile(
+ this, getMultiWindowDisplaySize());
}
onDeviceProfileInitiated();
@@ -580,7 +576,8 @@
return mFocusHandler;
}
- public LauncherStateManager getStateManager() {
+ @Override
+ public StateManager<LauncherState> getStateManager() {
return mStateManager;
}
@@ -887,11 +884,7 @@
@Override
protected void onStop() {
- final boolean wasActive = isUserActive();
- final LauncherState origState = getStateManager().getState();
- final int origDragLayerChildCount = mDragLayer.getChildCount();
super.onStop();
-
if (mDeferOverlayCallbacks) {
checkIfOverlayStillDeferred();
} else {
@@ -899,30 +892,8 @@
}
logStopAndResume(Action.Command.STOP);
-
mAppWidgetHost.setListenIfResumed(false);
-
NotificationListener.removeNotificationsChangedListener();
- getStateManager().moveToRestState();
-
- // Workaround for b/78520668, explicitly trim memory once UI is hidden
- onTrimMemory(TRIM_MEMORY_UI_HIDDEN);
-
- if (wasActive) {
- // The expected condition is that this activity is stopped because the device goes to
- // sleep and the UI may have noticeable changes.
- mDragLayer.post(() -> {
- if ((!getStateManager().isInStableState(origState)
- // The drag layer may be animating (e.g. dismissing QSB).
- || mDragLayer.getAlpha() < 1
- // Maybe an ArrowPopup is closed.
- || mDragLayer.getChildCount() != origDragLayerChildCount)) {
- onUiChangedWhileSleeping();
- }
- });
- }
-
- TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "Activity.onStop");
}
@Override
@@ -936,38 +907,29 @@
mAppWidgetHost.setListenIfResumed(true);
TraceHelper.INSTANCE.endSection(traceToken);
- TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "Activity.onStart");
}
- private void handleDeferredResume() {
- if (hasBeenResumed() && !mStateManager.getState().disableInteraction) {
- logStopAndResume(Action.Command.RESUME);
- getUserEventDispatcher().startSession();
+ @Override
+ @CallSuper
+ protected void onDeferredResumed() {
+ logStopAndResume(Action.Command.RESUME);
+ getUserEventDispatcher().startSession();
- AppLaunchTracker.INSTANCE.get(this).onReturnedToHome();
+ AppLaunchTracker.INSTANCE.get(this).onReturnedToHome();
- // Process any items that were added while Launcher was away.
- InstallShortcutReceiver.disableAndFlushInstallQueue(
- InstallShortcutReceiver.FLAG_ACTIVITY_PAUSED, this);
+ // Process any items that were added while Launcher was away.
+ InstallShortcutReceiver.disableAndFlushInstallQueue(
+ InstallShortcutReceiver.FLAG_ACTIVITY_PAUSED, this);
- // Refresh shortcuts if the permission changed.
- mModel.refreshShortcutsIfRequired();
+ // Refresh shortcuts if the permission changed.
+ mModel.refreshShortcutsIfRequired();
- // Set the notification listener and fetch updated notifications when we resume
- NotificationListener.setNotificationsChangedListener(mPopupDataProvider);
+ // Set the notification listener and fetch updated notifications when we resume
+ NotificationListener.setNotificationsChangedListener(mPopupDataProvider);
- DiscoveryBounce.showForHomeIfNeeded(this);
-
- onDeferredResumed();
- addActivityFlags(ACTIVITY_STATE_DEFERRED_RESUMED);
-
- mDeferredResumePending = false;
- } else {
- mDeferredResumePending = true;
- }
+ DiscoveryBounce.showForHomeIfNeeded(this);
}
- protected void onDeferredResumed() { }
private void logStopAndResume(int command) {
int containerType = mStateManager.getState().containerType;
@@ -988,7 +950,8 @@
if (!mDeferOverlayCallbacks) {
return;
}
- if (isStarted() && (!hasBeenResumed() || mStateManager.getState().disableInteraction)) {
+ if (isStarted() && (!hasBeenResumed()
+ || mStateManager.getState().hasFlag(FLAG_NON_INTERACTIVE))) {
return;
}
mDeferOverlayCallbacks = false;
@@ -1015,21 +978,51 @@
return mOverlayManager;
}
+ @Override
public void onStateSetStart(LauncherState state) {
- if (mDeferredResumePending) {
- handleDeferredResume();
- }
+ super.onStateSetStart(state);
if (mDeferOverlayCallbacks) {
scheduleDeferredCheck();
}
addActivityFlags(ACTIVITY_STATE_TRANSITION_ACTIVE);
+
+ if (state.hasFlag(FLAG_CLOSE_POPUPS)) {
+ AbstractFloatingView.closeAllOpenViews(this, !state.hasFlag(FLAG_NON_INTERACTIVE));
+ }
+
+ if (state == SPRING_LOADED) {
+ // Prevent any Un/InstallShortcutReceivers from updating the db while we are
+ // not on homescreen
+ InstallShortcutReceiver.enableInstallQueue(FLAG_DRAG_AND_DROP);
+ getRotationHelper().setCurrentStateRequest(REQUEST_LOCK);
+
+ mWorkspace.showPageIndicatorAtCurrentScroll();
+ mWorkspace.setClipChildren(false);
+ }
+ // When multiple pages are visible, show persistent page indicator
+ mWorkspace.getPageIndicator().setShouldAutoHide(!state.hasFlag(FLAG_MULTI_PAGE));
}
+ @Override
public void onStateSetEnd(LauncherState state) {
+ super.onStateSetStart(state);
getAppWidgetHost().setResumed(state == LauncherState.NORMAL);
- getWorkspace().setClipChildren(!state.disablePageClipping);
+ getWorkspace().setClipChildren(!state.hasFlag(FLAG_MULTI_PAGE));
+
finishAutoCancelActionMode();
removeActivityFlags(ACTIVITY_STATE_TRANSITION_ACTIVE);
+
+ // dispatch window state changed
+ getWindow().getDecorView().sendAccessibilityEvent(TYPE_WINDOW_STATE_CHANGED);
+ AccessibilityManagerCompat.sendStateEventToTest(this, state.ordinal);
+
+ if (state == NORMAL) {
+ // Re-enable any Un/InstallShortcutReceiver and now process any queued items
+ InstallShortcutReceiver.disableAndFlushInstallQueue(FLAG_DRAG_AND_DROP, this);
+
+ // Clear any rotation locks when going to normal state
+ getRotationHelper().setCurrentStateRequest(REQUEST_NONE);
+ }
}
@Override
@@ -1038,9 +1031,6 @@
TraceHelper.FLAG_UI_EVENT);
super.onResume();
- mHandler.removeCallbacks(mHandleDeferredResume);
- Utilities.postAsyncCallback(mHandler, mHandleDeferredResume);
-
if (!mOnResumeCallbacks.isEmpty()) {
final ArrayList<OnResumeCallback> resumeCallbacks = new ArrayList<>(mOnResumeCallbacks);
mOnResumeCallbacks.clear();
@@ -1083,10 +1073,6 @@
}
}
- public boolean isInState(LauncherState state) {
- return mStateManager.getState() == state;
- }
-
/**
* Restores the previous state, if it exists.
*
@@ -1100,7 +1086,7 @@
int stateOrdinal = savedState.getInt(RUNTIME_STATE, NORMAL.ordinal);
LauncherState[] stateValues = LauncherState.values();
LauncherState state = stateValues[stateOrdinal];
- if (!state.disableRestore) {
+ if (!state.shouldDisableRestore()) {
mStateManager.goToState(state, false /* animated */);
}
@@ -1325,8 +1311,6 @@
}
};
- protected void onUiChangedWhileSleeping() { }
-
private void updateNotificationDots(Predicate<PackageUserKey> updatedDots) {
mWorkspace.updateNotificationDots(updatedDots);
mAppsView.getAppsStore().updateNotificationDots(updatedDots);
@@ -2196,6 +2180,9 @@
workspace.requestLayout();
}
+ @Override
+ public void bindPredictedItems(List<AppInfo> appInfos, IntArray ranks) { }
+
/**
* Add the views for a widget to the workspace.
*/
@@ -2688,7 +2675,7 @@
return super.onKeyUp(keyCode, event);
}
- protected StateHandler[] createStateHandlers() {
+ protected StateHandler<LauncherState>[] createStateHandlers() {
return new StateHandler[] { getAllAppsController(), getWorkspace() };
}
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index 2f38037..14e604d 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -33,6 +33,7 @@
import com.android.launcher3.icons.IconCache;
import com.android.launcher3.icons.IconProvider;
import com.android.launcher3.icons.LauncherIcons;
+import com.android.launcher3.model.PredictionModel;
import com.android.launcher3.notification.NotificationListener;
import com.android.launcher3.pm.InstallSessionHelper;
import com.android.launcher3.pm.InstallSessionTracker;
@@ -57,6 +58,7 @@
private final IconCache mIconCache;
private final WidgetPreviewLoader mWidgetCache;
private final InvariantDeviceProfile mInvariantDeviceProfile;
+ private final PredictionModel mPredictionModel;
private SecureSettingsObserver mNotificationDotsObserver;
private InstallSessionTracker mInstallSessionTracker;
@@ -127,6 +129,7 @@
mIconCache = new IconCache(mContext, mInvariantDeviceProfile, iconCacheFileName);
mWidgetCache = new WidgetPreviewLoader(mContext, mIconCache);
mModel = new LauncherModel(this, mIconCache, AppFilter.newInstance(mContext));
+ mPredictionModel = new PredictionModel(mContext);
}
protected void onNotificationSettingsChanged(boolean areNotificationDotsEnabled) {
@@ -182,6 +185,10 @@
return mModel;
}
+ public PredictionModel getPredictionModel() {
+ return mPredictionModel;
+ }
+
public WidgetPreviewLoader getWidgetCache() {
return mWidgetCache;
}
diff --git a/src/com/android/launcher3/LauncherAppTransitionManager.java b/src/com/android/launcher3/LauncherAppTransitionManager.java
index 9148c2f..24e0d14 100644
--- a/src/com/android/launcher3/LauncherAppTransitionManager.java
+++ b/src/com/android/launcher3/LauncherAppTransitionManager.java
@@ -13,11 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package com.android.launcher3;
-
-import android.animation.Animator;
import android.app.ActivityOptions;
import android.content.Context;
import android.graphics.Rect;
@@ -58,17 +55,6 @@
}
/**
- * Number of animations which run on state properties.
- */
- public int getStateElementAnimationsCount() {
- return 0;
- }
-
- public Animator createStateElementAnimation(int index, float... values) {
- throw new RuntimeException("Unknown gesture animation " + index);
- }
-
- /**
* Registers remote animations for certain system transitions.
*/
public void registerRemoteAnimations() {
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index 21cd04e..48b97fa 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -20,7 +20,6 @@
import static com.android.launcher3.provider.LauncherDbUtils.copyTable;
import static com.android.launcher3.provider.LauncherDbUtils.dropTable;
import static com.android.launcher3.provider.LauncherDbUtils.tableExists;
-import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
import android.annotation.TargetApi;
import android.app.backup.BackupManager;
@@ -48,7 +47,6 @@
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
-import android.os.Handler;
import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
@@ -85,6 +83,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Locale;
+import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
public class LauncherProvider extends ContentProvider {
@@ -92,8 +91,7 @@
private static final boolean LOGD = false;
private static final String DOWNGRADE_SCHEMA_FILE = "downgrade_schema.json";
- private static final String TOKEN_RESTORE_BACKUP_TABLE = "restore_backup_table";
- private static final long RESTORE_BACKUP_TABLE_DELAY = 60000;
+ private static final long RESTORE_BACKUP_TABLE_DELAY = TimeUnit.SECONDS.toMillis(30);
/**
* Represents the schema of the database. Changes in scheme need not be backwards compatible.
@@ -107,6 +105,8 @@
protected DatabaseHelper mOpenHelper;
+ private long mLastRestoreTimestamp = 0L;
+
/**
* $ adb shell dumpsys activity provider com.android.launcher3
*/
@@ -412,11 +412,12 @@
return null;
}
case LauncherSettings.Settings.METHOD_RESTORE_BACKUP_TABLE: {
- final Handler handler = MODEL_EXECUTOR.getHandler();
- handler.removeCallbacksAndMessages(TOKEN_RESTORE_BACKUP_TABLE);
- handler.postDelayed(() -> RestoreDbTask.restoreIfPossible(
- getContext(), mOpenHelper, new BackupManager(getContext())),
- TOKEN_RESTORE_BACKUP_TABLE, RESTORE_BACKUP_TABLE_DELAY);
+ final long ts = System.currentTimeMillis();
+ if (ts - mLastRestoreTimestamp > RESTORE_BACKUP_TABLE_DELAY) {
+ mLastRestoreTimestamp = ts;
+ RestoreDbTask.restoreIfPossible(
+ getContext(), mOpenHelper, new BackupManager(getContext()));
+ }
return null;
}
case LauncherSettings.Settings.METHOD_UPDATE_CURRENT_OPEN_HELPER: {
diff --git a/src/com/android/launcher3/LauncherRootView.java b/src/com/android/launcher3/LauncherRootView.java
index b4fbbc3..226a924 100644
--- a/src/com/android/launcher3/LauncherRootView.java
+++ b/src/com/android/launcher3/LauncherRootView.java
@@ -64,15 +64,8 @@
private void handleSystemWindowInsets(Rect insets) {
mConsumedInsets.setEmpty();
boolean drawInsetBar = false;
- if (mLauncher.isInMultiWindowMode()
- && (insets.left > 0 || insets.right > 0 || insets.bottom > 0)) {
- mConsumedInsets.left = insets.left;
- mConsumedInsets.right = insets.right;
- mConsumedInsets.bottom = insets.bottom;
- insets.set(0, insets.top, 0, 0);
- drawInsetBar = true;
- } else if ((insets.right > 0 || insets.left > 0) &&
- getContext().getSystemService(ActivityManager.class).isLowRamDevice()) {
+ if ((insets.right > 0 || insets.left > 0)
+ && getContext().getSystemService(ActivityManager.class).isLowRamDevice()) {
mConsumedInsets.left = insets.left;
mConsumedInsets.right = insets.right;
insets.set(0, insets.top, 0, insets.bottom);
diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java
index d3af5fc..87ead9e 100644
--- a/src/com/android/launcher3/LauncherSettings.java
+++ b/src/com/android/launcher3/LauncherSettings.java
@@ -152,6 +152,7 @@
public static final int CONTAINER_HOTSEAT = -101;
public static final int CONTAINER_PREDICTION = -102;
public static final int CONTAINER_HOTSEAT_PREDICTION = -103;
+ public static final int CONTAINER_ALL_APPS = -104;
public static final String containerToString(int container) {
switch (container) {
diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java
index e2b867e..db2a6cd 100644
--- a/src/com/android/launcher3/LauncherState.java
+++ b/src/com/android/launcher3/LauncherState.java
@@ -15,23 +15,7 @@
*/
package com.android.launcher3;
-import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_AUTO;
-import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS;
-import static android.view.View.VISIBLE;
-import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED;
-
-import static com.android.launcher3.anim.Interpolators.ACCEL;
import static com.android.launcher3.anim.Interpolators.ACCEL_2;
-import static com.android.launcher3.anim.Interpolators.DEACCEL;
-import static com.android.launcher3.anim.Interpolators.DEACCEL_1_7;
-import static com.android.launcher3.anim.Interpolators.clampToProgress;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS;
-import static com.android.launcher3.states.RotationHelper.REQUEST_NONE;
-import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_FADE;
-import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE;
-import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_X;
-import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_FADE;
-import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_SCALE;
import static com.android.launcher3.testing.TestProtocol.ALL_APPS_STATE_ORDINAL;
import static com.android.launcher3.testing.TestProtocol.BACKGROUND_APP_STATE_ORDINAL;
import static com.android.launcher3.testing.TestProtocol.HINT_STATE_ORDINAL;
@@ -43,25 +27,22 @@
import static com.android.launcher3.testing.TestProtocol.SPRING_LOADED_STATE_ORDINAL;
import android.content.Context;
-import android.view.View;
import android.view.animation.Interpolator;
-import com.android.launcher3.allapps.AllAppsContainerView;
+import com.android.launcher3.statemanager.BaseState;
+import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.states.HintState;
import com.android.launcher3.states.SpringLoadedState;
-import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.uioverrides.states.AllAppsState;
import com.android.launcher3.uioverrides.states.OverviewState;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import java.util.Arrays;
-
/**
* Base state for various states used for the Launcher
*/
-public abstract class LauncherState {
-
+public abstract class LauncherState implements BaseState<LauncherState> {
/**
* Set of elements indicating various workspace elements which change visibility across states
@@ -80,16 +61,24 @@
public static final int APPS_VIEW_ITEM_MASK =
HOTSEAT_SEARCH_BOX | ALL_APPS_HEADER | ALL_APPS_HEADER_EXTRA | ALL_APPS_CONTENT;
- protected static final int FLAG_MULTI_PAGE = 1 << 0;
- protected static final int FLAG_DISABLE_ACCESSIBILITY = 1 << 1;
- protected static final int FLAG_DISABLE_RESTORE = 1 << 2;
- protected static final int FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED = 1 << 3;
- protected static final int FLAG_DISABLE_PAGE_CLIPPING = 1 << 4;
- protected static final int FLAG_PAGE_BACKGROUNDS = 1 << 5;
- protected static final int FLAG_DISABLE_INTERACTION = 1 << 6;
- protected static final int FLAG_OVERVIEW_UI = 1 << 7;
- protected static final int FLAG_HIDE_BACK_BUTTON = 1 << 8;
- protected static final int FLAG_HAS_SYS_UI_SCRIM = 1 << 9;
+ // Flag indicating workspace has multiple pages visible.
+ public static final int FLAG_MULTI_PAGE = BaseState.getFlag(0);
+ // Flag indicating that workspace and its contents are not accessible
+ public static final int FLAG_WORKSPACE_INACCESSIBLE = BaseState.getFlag(1);
+
+ // Flag indicating the state allows workspace icons to be dragged.
+ public static final int FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED = BaseState.getFlag(2);
+ // Flag to indicate that workspace should draw page background
+ public static final int FLAG_WORKSPACE_HAS_BACKGROUNDS = BaseState.getFlag(3);
+ // True if the back button should be hidden when in this state (assuming no floating views are
+ // open, launcher has window focus, etc).
+ public static final int FLAG_HIDE_BACK_BUTTON = BaseState.getFlag(4);
+ // Flag to indicate if the state would have scrim over sysui region: statu sbar and nav bar
+ public static final int FLAG_HAS_SYS_UI_SCRIM = BaseState.getFlag(5);
+ // Flag to inticate that all popups should be closed when this state is enabled.
+ public static final int FLAG_CLOSE_POPUPS = BaseState.getFlag(6);
+ public static final int FLAG_OVERVIEW_UI = BaseState.getFlag(7);
+
public static final float NO_OFFSET = 0;
public static final float NO_SCALE = 1;
@@ -112,7 +101,7 @@
FLAG_DISABLE_RESTORE | FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED | FLAG_HIDE_BACK_BUTTON |
FLAG_HAS_SYS_UI_SCRIM) {
@Override
- public int getTransitionDuration(Launcher launcher) {
+ public int getTransitionDuration(Context context) {
// Arbitrary duration, when going to NORMAL we use the state we're coming from instead.
return 0;
}
@@ -144,87 +133,32 @@
public final int containerType;
/**
- * True if the state can be persisted across activity restarts.
- */
- public final boolean disableRestore;
-
- /**
- * True if workspace has multiple pages visible.
- */
- public final boolean hasMultipleVisiblePages;
-
- /**
- * Accessibility flag for workspace and its pages.
- * @see android.view.View#setImportantForAccessibility(int)
- */
- public final int workspaceAccessibilityFlag;
-
- /**
- * Properties related to state transition animation
- *
- * @see WorkspaceStateTransitionAnimation
- */
- public final boolean hasWorkspacePageBackground;
-
- /**
- * True if the state allows workspace icons to be dragged.
- */
- public final boolean workspaceIconsCanBeDragged;
-
- /**
- * True if the workspace pages should not be clipped relative to the workspace bounds
- * for this state.
- */
- public final boolean disablePageClipping;
-
- /**
- * True if launcher can not be directly interacted in this state;
- */
- public final boolean disableInteraction;
-
- /**
* True if the state has overview panel visible.
*/
public final boolean overviewUi;
- /**
- * True if the back button should be hidden when in this state (assuming no floating views are
- * open, launcher has window focus, etc).
- */
- public final boolean hideBackButton;
-
- public final boolean hasSysUiScrim;
+ private final int mFlags;
public LauncherState(int id, int containerType, int flags) {
this.containerType = containerType;
-
- this.hasWorkspacePageBackground = (flags & FLAG_PAGE_BACKGROUNDS) != 0;
- this.hasMultipleVisiblePages = (flags & FLAG_MULTI_PAGE) != 0;
- this.workspaceAccessibilityFlag = (flags & FLAG_DISABLE_ACCESSIBILITY) != 0
- ? IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
- : IMPORTANT_FOR_ACCESSIBILITY_AUTO;
- this.disableRestore = (flags & FLAG_DISABLE_RESTORE) != 0;
- this.workspaceIconsCanBeDragged = (flags & FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED) != 0;
- this.disablePageClipping = (flags & FLAG_DISABLE_PAGE_CLIPPING) != 0;
- this.disableInteraction = (flags & FLAG_DISABLE_INTERACTION) != 0;
+ this.mFlags = flags;
this.overviewUi = (flags & FLAG_OVERVIEW_UI) != 0;
- this.hideBackButton = (flags & FLAG_HIDE_BACK_BUTTON) != 0;
- this.hasSysUiScrim = (flags & FLAG_HAS_SYS_UI_SCRIM) != 0;
-
this.ordinal = id;
sAllStates[id] = this;
}
+ /**
+ * Returns if the state has the provided flag
+ */
+ @Override
+ public final boolean hasFlag(int mask) {
+ return (mFlags & mask) != 0;
+ }
+
public static LauncherState[] values() {
return Arrays.copyOf(sAllStates, sAllStates.length);
}
- /**
- * @return How long the animation to this state should take (or from this state to NORMAL).
- * @param launcher
- */
- public abstract int getTransitionDuration(Launcher launcher);
-
public ScaleAndTranslation getWorkspaceScaleAndTranslation(Launcher launcher) {
return new ScaleAndTranslation(NO_SCALE, NO_OFFSET, NO_OFFSET);
}
@@ -252,12 +186,6 @@
return 0;
}
- public void onStateEnabled(Launcher launcher) {
- dispatchWindowStateChanged(launcher);
- }
-
- public void onStateDisabled(Launcher launcher) { }
-
public int getVisibleElements(Launcher launcher) {
if (launcher.getDeviceProfile().isVerticalBarLayout()) {
return HOTSEAT_ICONS | VERTICAL_SWIPE_INDICATOR;
@@ -324,82 +252,25 @@
};
}
+ @Override
public LauncherState getHistoryForState(LauncherState previousState) {
// No history is supported
return NORMAL;
}
- /**
- * Called when the start transition ends and the user settles on this particular state.
- */
- public void onStateTransitionEnd(Launcher launcher) {
- if (this == NORMAL) {
- // Clear any rotation locks when going to normal state
- launcher.getRotationHelper().setCurrentStateRequest(REQUEST_NONE);
- }
+ @Override
+ public String toString() {
+ return "Ordinal-" + ordinal;
}
public void onBackPressed(Launcher launcher) {
if (this != NORMAL) {
- LauncherStateManager lsm = launcher.getStateManager();
+ StateManager<LauncherState> lsm = launcher.getStateManager();
LauncherState lastState = lsm.getLastState();
lsm.goToState(lastState);
}
}
- /**
- * Prepares for a non-user controlled animation from fromState to this state. Preparations
- * include:
- * - Setting interpolators for various animations included in the state transition.
- * - Setting some start values (e.g. scale) for views that are hidden but about to be shown.
- */
- public void prepareForAtomicAnimation(Launcher launcher, LauncherState fromState,
- StateAnimationConfig config) {
- if (this == NORMAL && fromState == OVERVIEW) {
- config.setInterpolator(ANIM_WORKSPACE_SCALE, DEACCEL);
- config.setInterpolator(ANIM_WORKSPACE_FADE, ACCEL);
- config.setInterpolator(ANIM_OVERVIEW_SCALE, clampToProgress(ACCEL, 0, 0.9f));
- config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, ACCEL);
- config.setInterpolator(ANIM_OVERVIEW_FADE, DEACCEL_1_7);
- Workspace workspace = launcher.getWorkspace();
-
- // Start from a higher workspace scale, but only if we're invisible so we don't jump.
- boolean isWorkspaceVisible = workspace.getVisibility() == VISIBLE;
- if (isWorkspaceVisible) {
- CellLayout currentChild = (CellLayout) workspace.getChildAt(
- workspace.getCurrentPage());
- isWorkspaceVisible = currentChild.getVisibility() == VISIBLE
- && currentChild.getShortcutsAndWidgets().getAlpha() > 0;
- }
- if (!isWorkspaceVisible) {
- workspace.setScaleX(0.92f);
- workspace.setScaleY(0.92f);
- }
- Hotseat hotseat = launcher.getHotseat();
- boolean isHotseatVisible = hotseat.getVisibility() == VISIBLE && hotseat.getAlpha() > 0;
- if (!isHotseatVisible) {
- hotseat.setScaleX(0.92f);
- hotseat.setScaleY(0.92f);
- if (ENABLE_OVERVIEW_ACTIONS.get()) {
- AllAppsContainerView qsbContainer = launcher.getAppsView();
- View qsb = qsbContainer.getSearchView();
- boolean qsbVisible = qsb.getVisibility() == VISIBLE && qsb.getAlpha() > 0;
- if (!qsbVisible) {
- qsbContainer.setScaleX(0.92f);
- qsbContainer.setScaleY(0.92f);
- }
- }
- }
- } else if (this == NORMAL && fromState == OVERVIEW_PEEK) {
- // Keep fully visible until the very end (when overview is offscreen) to make invisible.
- config.setInterpolator(ANIM_OVERVIEW_FADE, t -> t < 1 ? 0 : 1);
- }
- }
-
- protected static void dispatchWindowStateChanged(Launcher launcher) {
- launcher.getWindow().getDecorView().sendAccessibilityEvent(TYPE_WINDOW_STATE_CHANGED);
- }
-
public static abstract class PageAlphaProvider {
public final Interpolator interpolator;
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 5343424..359190c 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -257,13 +257,6 @@
forceFinishScroller(true);
}
- /**
- * Returns left offset of a page. This is the gap between pages and prevents overlap.
- */
- public int scrollOffsetLeft() {
- return mInsets.left + getPaddingLeft();
- }
-
private void abortScrollerAnimation(boolean resetNextPage) {
mScroller.abortAnimation();
// We need to clean up the next page here to avoid computeScrollHelper from
@@ -1075,7 +1068,7 @@
private int getSpringOverScroll(int amount) {
if (mScroller.isSpringing()) {
return amount < 0
- ? mScroller.getCurrPos()
+ ? mScroller.getCurrPos() - mMinScroll
: Math.max(0, mScroller.getCurrPos() - mMaxScroll);
} else {
return 0;
diff --git a/src/com/android/launcher3/SecondaryDropTarget.java b/src/com/android/launcher3/SecondaryDropTarget.java
index 9dbb5fc..fbac0bd 100644
--- a/src/com/android/launcher3/SecondaryDropTarget.java
+++ b/src/com/android/launcher3/SecondaryDropTarget.java
@@ -7,6 +7,10 @@
import static com.android.launcher3.accessibility.LauncherAccessibilityDelegate.DISMISS_PREDICTION;
import static com.android.launcher3.accessibility.LauncherAccessibilityDelegate.RECONFIGURE;
import static com.android.launcher3.accessibility.LauncherAccessibilityDelegate.UNINSTALL;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ITEM_DROPPED_ON_DONT_SUGGEST;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ITEM_DROPPED_ON_UNINSTALL;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ITEM_UNINSTALL_CANCELLED;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ITEM_UNINSTALL_COMPLETED;
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_SYSTEM_MASK;
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_SYSTEM_NO;
@@ -34,6 +38,7 @@
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.logging.FileLog;
import com.android.launcher3.logging.LoggerUtils;
+import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.model.AppLaunchTracker;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.ItemInfoWithIcon;
@@ -58,7 +63,7 @@
private static final long CACHE_EXPIRE_TIMEOUT = 5000;
private final ArrayMap<UserHandle, Boolean> mUninstallDisabledCache = new ArrayMap<>(1);
-
+ private final StatsLogManager mStatsLogManager;
private final Alarm mCacheExpireAlarm;
private boolean mHadPendingAlarm;
@@ -69,8 +74,8 @@
public SecondaryDropTarget(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
-
mCacheExpireAlarm = new Alarm();
+ mStatsLogManager = StatsLogManager.newInstance(context);
}
@Override
@@ -214,6 +219,11 @@
// Defer onComplete
d.dragSource = new DeferredOnComplete(d.dragSource, getContext());
super.onDrop(d, options);
+ if (mCurrentAccessibilityAction == UNINSTALL) {
+ mStatsLogManager.log(LAUNCHER_ITEM_DROPPED_ON_UNINSTALL, d.logInstanceId);
+ } else if (mCurrentAccessibilityAction == DISMISS_PREDICTION) {
+ mStatsLogManager.log(LAUNCHER_ITEM_DROPPED_ON_DONT_SUGGEST, d.logInstanceId);
+ }
}
@Override
@@ -338,8 +348,10 @@
mDragObject.dragInfo.user, PackageManager.MATCH_UNINSTALLED_PACKAGES) == null) {
mDragObject.dragSource = mOriginal;
mOriginal.onDropCompleted(SecondaryDropTarget.this, mDragObject, true);
+ mStatsLogManager.log(LAUNCHER_ITEM_UNINSTALL_COMPLETED, mDragObject.logInstanceId);
} else {
sendFailure();
+ mStatsLogManager.log(LAUNCHER_ITEM_UNINSTALL_CANCELLED, mDragObject.logInstanceId);
}
}
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 7baee95..8e33406 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -63,6 +63,8 @@
import android.view.ViewConfiguration;
import android.view.animation.Interpolator;
+import androidx.core.os.BuildCompat;
+
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dragndrop.FolderAdaptiveIcon;
import com.android.launcher3.graphics.GridOptionsProvider;
@@ -104,6 +106,8 @@
public static final String[] EMPTY_STRING_ARRAY = new String[0];
public static final Person[] EMPTY_PERSON_ARRAY = new Person[0];
+ public static final boolean ATLEAST_R = BuildCompat.isAtLeastR();
+
public static final boolean ATLEAST_Q = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q;
public static final boolean ATLEAST_P =
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 70a5cc5..286b522 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -19,6 +19,9 @@
import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
import static com.android.launcher3.LauncherState.ALL_APPS;
+import static com.android.launcher3.LauncherState.FLAG_MULTI_PAGE;
+import static com.android.launcher3.LauncherState.FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED;
+import static com.android.launcher3.LauncherState.FLAG_WORKSPACE_INACCESSIBLE;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.LauncherState.SPRING_LOADED;
@@ -76,6 +79,8 @@
import com.android.launcher3.graphics.DragPreviewProvider;
import com.android.launcher3.graphics.PreloadIconDrawable;
import com.android.launcher3.icons.BitmapRenderer;
+import com.android.launcher3.logging.StatsLogManager;
+import com.android.launcher3.logging.StatsLogManager.LauncherEvent;
import com.android.launcher3.logging.UserEventDispatcher;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.FolderInfo;
@@ -84,6 +89,7 @@
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.pageindicators.WorkspacePageIndicator;
import com.android.launcher3.popup.PopupContainerWithArrow;
+import com.android.launcher3.statemanager.StateManager.StateHandler;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.touch.WorkspaceTouchListener;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
@@ -114,7 +120,7 @@
*/
public class Workspace extends PagedView<WorkspacePageIndicator>
implements DropTarget, DragSource, View.OnTouchListener,
- DragController.DragListener, Insettable, LauncherStateManager.StateHandler,
+ DragController.DragListener, Insettable, StateHandler<LauncherState>,
WorkspaceLayoutManager {
/** The value that {@link #mTransitionProgress} must be greater than for
@@ -243,6 +249,8 @@
// Handles workspace state transitions
private final WorkspaceStateTransitionAnimation mStateTransitionAnimation;
+ private final StatsLogManager mStatsLogManager;
+
/**
* Used to inflate the Workspace from XML.
*
@@ -275,6 +283,7 @@
// Disable multitouch across the workspace/all apps/customize tray
setMotionEventSplittingEnabled(true);
setOnTouchListener(new WorkspaceTouchListener(mLauncher, this));
+ mStatsLogManager = StatsLogManager.newInstance(context);
}
@Override
@@ -354,7 +363,7 @@
}
@Override
- public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) {
+ public void onDragStart(DragObject dragObject, DragOptions options) {
if (ENFORCE_DRAG_EVENT_ORDER) {
enforceDragParity("onDragStart", 0, 0);
}
@@ -406,6 +415,14 @@
// Always enter the spring loaded mode
mLauncher.getStateManager().goToState(SPRING_LOADED);
+ mStatsLogManager.log(
+ LauncherEvent.LAUNCHER_ITEM_DRAG_STARTED,
+ dragObject.logInstanceId,
+ dragObject.originalDragInfo.buildProto(
+ dragObject.dragSource instanceof Folder
+ ? ((Folder) dragObject.dragSource).mInfo
+ : null)
+ );
}
public void deferRemoveExtraEmptyScreen() {
@@ -1208,7 +1225,7 @@
/** Returns whether a drag should be allowed to be started from the current workspace state. */
public boolean workspaceIconsCanBeDragged() {
- return mLauncher.getStateManager().getState().workspaceIconsCanBeDragged;
+ return mLauncher.getStateManager().getState().hasFlag(FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED);
}
private void updateChildrenLayersEnabled() {
@@ -1318,7 +1335,7 @@
// Invalidate the pages now, so that we have the visible pages before the
// animation is started
- if (toState.hasMultipleVisiblePages) {
+ if (toState.hasFlag(FLAG_MULTI_PAGE)) {
mForceDrawAdjacentPages = true;
}
invalidate(); // This will call dispatchDraw(), which calls getVisiblePages().
@@ -1336,7 +1353,10 @@
public void updateAccessibilityFlags() {
// TODO: Update the accessibility flags appropriately when dragging.
- int accessibilityFlag = mLauncher.getStateManager().getState().workspaceAccessibilityFlag;
+ int accessibilityFlag =
+ mLauncher.getStateManager().getState().hasFlag(FLAG_WORKSPACE_INACCESSIBLE)
+ ? IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
+ : IMPORTANT_FOR_ACCESSIBILITY_AUTO;
if (!mLauncher.getAccessibilityDelegate().isInAccessibleDrag()) {
int total = getPageCount();
for (int i = 0; i < total; i++) {
@@ -1422,6 +1442,10 @@
mOutlineProvider = previewProvider;
+ if (draggableView == null && child instanceof DraggableView) {
+ draggableView = (DraggableView) child;
+ }
+
// The drag bitmap follows the touch point around on the screen
final Bitmap b = previewProvider.createDragBitmap();
int halfPadding = previewProvider.previewPadding / 2;
@@ -1432,12 +1456,8 @@
Point dragVisualizeOffset = null;
Rect dragRect = new Rect();
- if (draggableView == null && child instanceof DraggableView) {
- draggableView = (DraggableView) child;
- }
-
if (draggableView != null) {
- draggableView.getVisualDragBounds(dragRect);
+ draggableView.getSourceVisualDragBounds(dragRect);
dragLayerY += dragRect.top;
dragVisualizeOffset = new Point(- halfPadding, halfPadding);
}
@@ -1630,7 +1650,10 @@
Rect folderLocation = new Rect();
float scale = mLauncher.getDragLayer().getDescendantRectRelativeToSelf(v, folderLocation);
target.removeView(v);
-
+ mStatsLogManager.log(
+ LauncherEvent.LAUNCHER_ITEM_DROP_FOLDER_CREATED,
+ d.logInstanceId,
+ destInfo.buildProto(null));
FolderIcon fi = mLauncher.addFolder(target, container, screenId, targetCell[0],
targetCell[1]);
destInfo.cellX = -1;
@@ -1668,6 +1691,10 @@
if (dropOverView instanceof FolderIcon) {
FolderIcon fi = (FolderIcon) dropOverView;
if (fi.acceptDrop(d.dragInfo)) {
+ mStatsLogManager.log(
+ LauncherEvent.LAUNCHER_ITEM_DROP_COMPLETED,
+ d.logInstanceId,
+ fi.mInfo.buildProto(null));
fi.onDrop(d, false /* itemReturnedOnFailedDrop */);
// if the drag started here, we need to remove it from the workspace
@@ -1683,6 +1710,7 @@
@Override
public void prepareAccessibilityDrop() { }
+ @Override
public void onDrop(final DragObject d, DragOptions options) {
mDragViewVisualCenter = d.getVisualCenter(mDragViewVisualCenter);
CellLayout dropTargetLayout = mDropToLayout;
@@ -1869,6 +1897,10 @@
mLauncher.getStateManager().goToState(
NORMAL, SPRING_LOADED_EXIT_DELAY, onCompleteRunnable);
+ mStatsLogManager.log(
+ LauncherEvent.LAUNCHER_ITEM_DROP_COMPLETED,
+ d.logInstanceId,
+ d.dragInfo.buildProto(null));
}
if (d.stateAnnouncer != null && !droppedOnOriginalCell) {
@@ -2495,6 +2527,10 @@
resetTransitionTransform();
}
}
+ mStatsLogManager.log(
+ LauncherEvent.LAUNCHER_ITEM_DROP_COMPLETED,
+ d.logInstanceId,
+ d.dragInfo.buildProto(null));
}
public Bitmap createWidgetBitmap(ItemInfo widgetInfo, View layout) {
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index c4c4377..06a73db 100644
--- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -21,6 +21,8 @@
import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
+import static com.android.launcher3.LauncherState.FLAG_HAS_SYS_UI_SCRIM;
+import static com.android.launcher3.LauncherState.FLAG_WORKSPACE_HAS_BACKGROUNDS;
import static com.android.launcher3.LauncherState.HOTSEAT_ICONS;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.anim.Interpolators.ZOOM_OUT;
@@ -64,7 +66,7 @@
}
/**
- * @see com.android.launcher3.LauncherStateManager.StateHandler#setStateWithAnimation
+ * @see com.android.launcher3.statemanager.StateManager.StateHandler#setStateWithAnimation
*/
public void setStateWithAnimation(
LauncherState toState, StateAnimationConfig config, PendingAnimation animation) {
@@ -161,7 +163,8 @@
WorkspaceAndHotseatScrim scrim = mLauncher.getDragLayer().getScrim();
propertySetter.setFloat(scrim, SCRIM_PROGRESS, state.getWorkspaceScrimAlpha(mLauncher),
LINEAR);
- propertySetter.setFloat(scrim, SYSUI_PROGRESS, state.hasSysUiScrim ? 1 : 0, LINEAR);
+ propertySetter.setFloat(scrim, SYSUI_PROGRESS,
+ state.hasFlag(FLAG_HAS_SYS_UI_SCRIM) ? 1 : 0, LINEAR);
}
public void applyChildState(LauncherState state, CellLayout cl, int childIndex) {
@@ -173,7 +176,8 @@
PageAlphaProvider pageAlphaProvider, PropertySetter propertySetter,
StateAnimationConfig config) {
float pageAlpha = pageAlphaProvider.getPageAlpha(childIndex);
- int drawableAlpha = Math.round(pageAlpha * (state.hasWorkspacePageBackground ? 255 : 0));
+ int drawableAlpha = state.hasFlag(FLAG_WORKSPACE_HAS_BACKGROUNDS)
+ ? Math.round(pageAlpha * 255) : 0;
if (!config.onlyPlayAtomicComponent()) {
// Don't update the scrim during the atomic animation.
diff --git a/src/com/android/launcher3/allapps/AllAppsStore.java b/src/com/android/launcher3/allapps/AllAppsStore.java
index d2dcfd2..b11312c 100644
--- a/src/com/android/launcher3/allapps/AllAppsStore.java
+++ b/src/com/android/launcher3/allapps/AllAppsStore.java
@@ -18,7 +18,6 @@
import static com.android.launcher3.model.data.AppInfo.COMPONENT_KEY_COMPARATOR;
import static com.android.launcher3.model.data.AppInfo.EMPTY_ARRAY;
-import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
@@ -32,6 +31,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Consumer;
import java.util.function.Predicate;
@@ -50,14 +50,12 @@
private AppInfo[] mApps = EMPTY_ARRAY;
- private final List<OnUpdateListener> mUpdateListeners = new ArrayList<>();
+ private final List<OnUpdateListener> mUpdateListeners = new CopyOnWriteArrayList<>();
private final ArrayList<ViewGroup> mIconContainers = new ArrayList<>();
private int mDeferUpdatesFlags = 0;
private boolean mUpdatePending = false;
- private boolean mListenerUpdateInProgress = false;
-
public AppInfo[] getApps() {
return mApps;
}
@@ -102,12 +100,9 @@
mUpdatePending = true;
return;
}
- mListenerUpdateInProgress = true;
- int count = mUpdateListeners.size();
- for (int i = 0; i < count; i++) {
- mUpdateListeners.get(i).onAppsUpdated();
+ for (OnUpdateListener listener : mUpdateListeners) {
+ listener.onAppsUpdated();
}
- mListenerUpdateInProgress = false;
}
public void addUpdateListener(OnUpdateListener listener) {
@@ -115,9 +110,6 @@
}
public void removeUpdateListener(OnUpdateListener listener) {
- if (mListenerUpdateInProgress) {
- Log.e("AllAppsStore", "Trying to remove listener during update", new Exception());
- }
mUpdateListeners.remove(listener);
}
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 071c03d..f057036 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -28,11 +28,11 @@
import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
-import com.android.launcher3.LauncherStateManager.StateHandler;
import com.android.launcher3.R;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.anim.PropertySetter;
+import com.android.launcher3.statemanager.StateManager.StateHandler;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
import com.android.launcher3.util.Themes;
@@ -50,8 +50,8 @@
* If release velocity < THRES1, snap according to either top or bottom depending on whether it's
* closer to top or closer to the page indicator.
*/
-public class AllAppsTransitionController implements StateHandler, OnDeviceProfileChangeListener,
- PluginListener<AllAppsSearchPlugin> {
+public class AllAppsTransitionController implements StateHandler<LauncherState>,
+ OnDeviceProfileChangeListener, PluginListener<AllAppsSearchPlugin> {
public static final FloatProperty<AllAppsTransitionController> ALL_APPS_PROGRESS =
new FloatProperty<AllAppsTransitionController>("allAppsProgress") {
@@ -132,6 +132,10 @@
mAppsView.setTranslationY(shiftCurrent);
+ if (mPlugin != null) {
+ mPlugin.setProgress(progress);
+ }
+
// Use a light system UI (dark icons) if all apps is behind at least half of the
// status bar.
boolean forceChange = Math.min(shiftCurrent, mScrimView.getVisualTop())
@@ -200,8 +204,8 @@
// TODO: change this from toggle event to continuous transition event.
mPlugin.setEditText(mAppsView.getSearchUiManager().setTextSearchEnabled(true));
} else {
- mAppsView.getSearchUiManager().setTextSearchEnabled(false);
mPlugin.setEditText(null);
+ mAppsView.getSearchUiManager().setTextSearchEnabled(false);
}
}
@@ -230,6 +234,8 @@
hasAllAppsContent, setter, headerFade, allAppsFade);
} else {
setter.setViewAlpha(mPluginContent, hasAllAppsContent ? 1 : 0, allAppsFade);
+ setter.setViewAlpha(mAppsView.getContentView(), 0, allAppsFade);
+ setter.setViewAlpha(mAppsView.getScrollBar(), 0, allAppsFade);
}
mAppsView.getSearchUiManager().setContentVisibility(visibleElements, setter, allAppsFade);
@@ -279,7 +285,7 @@
R.layout.all_apps_content_layout, mAppsView, false);
mAppsView.addView(mPluginContent);
mPluginContent.setAlpha(0f);
- mPlugin.setup((ViewGroup) mPluginContent);
+ mPlugin.setup((ViewGroup) mPluginContent, mLauncher);
}
@Override
diff --git a/src/com/android/launcher3/allapps/DiscoveryBounce.java b/src/com/android/launcher3/allapps/DiscoveryBounce.java
index 0648682..5397942 100644
--- a/src/com/android/launcher3/allapps/DiscoveryBounce.java
+++ b/src/com/android/launcher3/allapps/DiscoveryBounce.java
@@ -31,9 +31,9 @@
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
-import com.android.launcher3.LauncherStateManager.StateListener;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
+import com.android.launcher3.statemanager.StateManager.StateListener;
import com.android.launcher3.util.OnboardingPrefs;
/**
@@ -46,7 +46,7 @@
private final Launcher mLauncher;
private final Animator mDiscoBounceAnimation;
- private final StateListener mStateListener = new StateListener() {
+ private final StateListener<LauncherState> mStateListener = new StateListener<LauncherState>() {
@Override
public void onStateTransitionStart(LauncherState toState) {
handleClose(false);
diff --git a/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java b/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java
index f6766c4..80b6a5a 100644
--- a/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java
@@ -22,7 +22,7 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
-import com.android.launcher3.LauncherStateManager;
+import com.android.launcher3.statemanager.StateManager.StateListener;
import com.android.launcher3.views.WorkEduView;
/**
@@ -32,7 +32,7 @@
private final Launcher mLauncher;
- private LauncherStateManager.StateListener mWorkTabListener;
+ private StateListener<LauncherState> mWorkTabListener;
public LauncherAllAppsContainerView(Context context) {
this(context, null);
diff --git a/src/com/android/launcher3/anim/PendingAnimation.java b/src/com/android/launcher3/anim/PendingAnimation.java
index a95a5e1..740f7f2 100644
--- a/src/com/android/launcher3/anim/PendingAnimation.java
+++ b/src/com/android/launcher3/anim/PendingAnimation.java
@@ -105,6 +105,13 @@
add(anim);
}
+ public <T> void addFloat(T target, FloatProperty<T> property, float from, float to,
+ TimeInterpolator interpolator) {
+ Animator anim = ObjectAnimator.ofFloat(target, property, from, to);
+ anim.setDuration(mDuration).setInterpolator(interpolator);
+ add(anim);
+ }
+
@Override
public <T> void setInt(T target, IntProperty<T> property, int value,
TimeInterpolator interpolator) {
diff --git a/src/com/android/launcher3/anim/SpringAnimationBuilder.java b/src/com/android/launcher3/anim/SpringAnimationBuilder.java
index bc77aab..770df03 100644
--- a/src/com/android/launcher3/anim/SpringAnimationBuilder.java
+++ b/src/com/android/launcher3/anim/SpringAnimationBuilder.java
@@ -17,6 +17,8 @@
import static com.android.launcher3.anim.Interpolators.LINEAR;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.Context;
import android.util.FloatProperty;
@@ -195,6 +197,12 @@
animator.setDuration(getDuration()).setInterpolator(LINEAR);
animator.addUpdateListener(anim ->
property.set(target, getInterpolatedValue(anim.getAnimatedFraction())));
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ property.set(target, mEndValue);
+ }
+ });
return animator;
}
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index df30f7b..78d194b 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -92,6 +92,7 @@
public static final BooleanFlag ENABLE_QUICKSTEP_LIVE_TILE = getDebugFlag(
"ENABLE_QUICKSTEP_LIVE_TILE", false, "Enable live tile in Quickstep overview");
+ // Keep as DeviceFlag to allow remote disable in emergency.
public static final BooleanFlag ENABLE_SUGGESTED_ACTIONS_OVERVIEW = new DeviceFlag(
"ENABLE_SUGGESTED_ACTIONS_OVERVIEW", false, "Show chip hints on the overview screen");
@@ -117,8 +118,8 @@
"ASSISTANT_GIVES_LAUNCHER_FOCUS", false,
"Allow Launcher to handle nav bar gestures while Assistant is running over it");
- public static final BooleanFlag ENABLE_HYBRID_HOTSEAT = new DeviceFlag(
- "ENABLE_HYBRID_HOTSEAT", false, "Fill gaps in hotseat with predicted apps");
+ public static final BooleanFlag ENABLE_HYBRID_HOTSEAT = getDebugFlag(
+ "ENABLE_HYBRID_HOTSEAT", true, "Fill gaps in hotseat with predicted apps");
public static final BooleanFlag HOTSEAT_MIGRATE_TO_FOLDER = new DeviceFlag(
"HOTSEAT_MIGRATE_TO_FOLDER", false, "Should move hotseat items into a folder");
@@ -139,8 +140,9 @@
"ENABLE_OVERVIEW_ACTIONS", true, "Show app actions instead of the shelf in Overview."
+ " As part of this decoupling, also distinguish swipe up from nav bar vs above it.");
- public static final BooleanFlag ENABLE_SELECT_MODE = getDebugFlag(
- "ENABLE_SELECT_MODE", true, "Show Select Mode button in Overview Actions");
+ // Keep as DeviceFlag for remote disable in emergency.
+ public static final BooleanFlag ENABLE_OVERVIEW_SELECTIONS = new DeviceFlag(
+ "ENABLE_OVERVIEW_SELECTIONS", true, "Show Select Mode button in Overview Actions");
public static final BooleanFlag ENABLE_DATABASE_RESTORE = getDebugFlag(
"ENABLE_DATABASE_RESTORE", true,
diff --git a/src/com/android/launcher3/dragndrop/DragController.java b/src/com/android/launcher3/dragndrop/DragController.java
index d93fb1a..03028d3 100644
--- a/src/com/android/launcher3/dragndrop/DragController.java
+++ b/src/com/android/launcher3/dragndrop/DragController.java
@@ -186,8 +186,7 @@
mDragObject.dragSource = source;
mDragObject.dragInfo = dragInfo;
- mDragObject.originalDragInfo = new ItemInfo();
- mDragObject.originalDragInfo.copyFrom(dragInfo);
+ mDragObject.originalDragInfo = mDragObject.dragInfo.makeShallowCopy();
if (dragOffset != null) {
dragView.setDragVisualizeOffset(new Point(dragOffset));
diff --git a/src/com/android/launcher3/dragndrop/DragLayer.java b/src/com/android/launcher3/dragndrop/DragLayer.java
index 970c5a0..ddf44ca 100644
--- a/src/com/android/launcher3/dragndrop/DragLayer.java
+++ b/src/com/android/launcher3/dragndrop/DragLayer.java
@@ -274,19 +274,29 @@
scale *= childScale;
int toX = Math.round(coord[0]);
int toY = Math.round(coord[1]);
+
float toScale = scale;
if (child instanceof DraggableView) {
+ // This code is fairly subtle. Please verify drag and drop is pixel-perfect in a number
+ // of scenarios before modifying (from all apps, from workspace, different grid-sizes,
+ // shortcuts from in and out of Launcher etc).
DraggableView d = (DraggableView) child;
- d.getVisualDragBounds(dragViewBounds);
+ Rect destRect = new Rect();
+ d.getWorkspaceVisualDragBounds(destRect);
+
+ // In most cases this additional scale factor should be a no-op (1). It mainly accounts
+ // for alternate grids where the source and destination icon sizes are different
+ toScale *= ((1f * destRect.width())
+ / (dragView.getMeasuredWidth() - dragView.getBlurSizeOutline()));
// This accounts for the offset of the DragView created by scaling it about its
// center as it animates into place.
- float scaleShiftX = dragView.getMeasuredWidth() * (1 - scale) / 2;
- float scaleShiftY = dragView.getMeasuredHeight() * (1 - scale) / 2;
+ float scaleShiftX = dragView.getMeasuredWidth() * (1 - toScale) / 2;
+ float scaleShiftY = dragView.getMeasuredHeight() * (1 - toScale) / 2;
- toX += scale * (dragViewBounds.left - dragView.getBlurSizeOutline() / 2) - scaleShiftX;
- toY += scale * (dragViewBounds.top - dragView.getBlurSizeOutline() / 2) - scaleShiftY;
+ toX += scale * destRect.left - toScale * dragView.getBlurSizeOutline() / 2 - scaleShiftX;
+ toY += scale * destRect.top - toScale * dragView.getBlurSizeOutline() / 2 - scaleShiftY;
}
child.setVisibility(INVISIBLE);
diff --git a/src/com/android/launcher3/dragndrop/DragView.java b/src/com/android/launcher3/dragndrop/DragView.java
index 1e23bb6..de0fa1a 100644
--- a/src/com/android/launcher3/dragndrop/DragView.java
+++ b/src/com/android/launcher3/dragndrop/DragView.java
@@ -49,18 +49,18 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.LauncherState;
-import com.android.launcher3.LauncherStateManager;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.statemanager.StateManager.StateListener;
import com.android.launcher3.util.Themes;
import com.android.launcher3.util.Thunk;
import java.util.Arrays;
-public class DragView extends View implements LauncherStateManager.StateListener {
+public class DragView extends View implements StateListener<LauncherState> {
private static final ColorMatrix sTempMatrix1 = new ColorMatrix();
private static final ColorMatrix sTempMatrix2 = new ColorMatrix();
diff --git a/src/com/android/launcher3/dragndrop/DraggableView.java b/src/com/android/launcher3/dragndrop/DraggableView.java
index df99902..287c781 100644
--- a/src/com/android/launcher3/dragndrop/DraggableView.java
+++ b/src/com/android/launcher3/dragndrop/DraggableView.java
@@ -53,5 +53,14 @@
*
* @param bounds Visual bounds in the views coordinates will be written here.
*/
- default void getVisualDragBounds(Rect bounds) { }
+ default void getWorkspaceVisualDragBounds(Rect bounds) { }
+
+ /**
+ * Same as above, but accounts for differing icon sizes between source and destination
+ *
+ * @param bounds Visual bounds in the views coordinates will be written here.
+ */
+ default void getSourceVisualDragBounds(Rect bounds) {
+ getWorkspaceVisualDragBounds(bounds);
+ }
}
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index c287190..9a36b3e 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -87,6 +87,7 @@
import com.android.launcher3.dragndrop.DragController.DragListener;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.dragndrop.DragOptions;
+import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.FolderInfo.FolderListener;
@@ -1346,6 +1347,10 @@
if (d.stateAnnouncer != null) {
d.stateAnnouncer.completeAction(R.string.item_moved);
}
+ StatsLogManager.newInstance(getContext())
+ .log(StatsLogManager.LauncherEvent.LAUNCHER_ITEM_DROP_COMPLETED,
+ d.logInstanceId,
+ d.dragInfo.buildProto(mInfo));
}
// This is used so the item doesn't immediately appear in the folder when added. In one case
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index b875a0b..93208d4 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -53,6 +53,7 @@
import com.android.launcher3.Reorderable;
import com.android.launcher3.Utilities;
import com.android.launcher3.Workspace;
+import com.android.launcher3.allapps.AllAppsContainerView;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dot.FolderDotInfo;
@@ -85,7 +86,7 @@
@Thunk ActivityContext mActivity;
@Thunk Folder mFolder;
- private FolderInfo mInfo;
+ public FolderInfo mInfo;
private CheckLongPressHelper mLongPressHelper;
@@ -385,6 +386,14 @@
float finalAlpha = index < MAX_NUM_ITEMS_IN_PREVIEW ? 0.5f : 0f;
float finalScale = scale * scaleRelativeToDragLayer;
+
+ // Account for potentially different icon sizes with non-default grid settings
+ if (d.dragSource instanceof AllAppsContainerView) {
+ DeviceProfile grid = mActivity.getDeviceProfile();
+ float containerScale = (1f * grid.iconSizePx / grid.allAppsIconSizePx);
+ finalScale *= containerScale;
+ }
+
dragLayer.animateView(animateView, from, to, finalAlpha,
1, 1, finalScale, finalScale, DROP_IN_ANIMATION_DURATION,
Interpolators.DEACCEL_2, Interpolators.ACCEL_2,
@@ -758,7 +767,7 @@
}
@Override
- public void getVisualDragBounds(Rect bounds) {
+ public void getWorkspaceVisualDragBounds(Rect bounds) {
getPreviewBounds(bounds);
}
}
diff --git a/src/com/android/launcher3/graphics/DragPreviewProvider.java b/src/com/android/launcher3/graphics/DragPreviewProvider.java
index 848c04a..634d07e 100644
--- a/src/com/android/launcher3/graphics/DragPreviewProvider.java
+++ b/src/com/android/launcher3/graphics/DragPreviewProvider.java
@@ -77,7 +77,7 @@
if (mView instanceof DraggableView) {
DraggableView dv = (DraggableView) mView;
dv.prepareDrawDragView();
- dv.getVisualDragBounds(mTempRect);
+ dv.getSourceVisualDragBounds(mTempRect);
destCanvas.translate(blurSizeOutline / 2 - mTempRect.left,
blurSizeOutline / 2 - mTempRect.top);
mView.draw(destCanvas);
@@ -95,7 +95,7 @@
// Assume scaleX == scaleY, which is always the case for workspace items.
float scale = mView.getScaleX();
if (mView instanceof DraggableView) {
- ((DraggableView) mView).getVisualDragBounds(mTempRect);
+ ((DraggableView) mView).getSourceVisualDragBounds(mTempRect);
width = mTempRect.width();
height = mTempRect.height();
} else {
diff --git a/src/com/android/launcher3/logging/InstanceId.java b/src/com/android/launcher3/logging/InstanceId.java
new file mode 100644
index 0000000..e720d75
--- /dev/null
+++ b/src/com/android/launcher3/logging/InstanceId.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.logging;
+
+import static java.lang.Math.max;
+import static java.lang.Math.min;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
+
+
+/**
+ * An opaque identifier used to disambiguate which logs refer to a particular instance of some
+ * UI element. Useful when there might be multiple instances simultaneously active.
+ * Obtain from InstanceIdSequence. Clipped to range [0, INSTANCE_ID_MAX].
+ *
+ * Copy of frameworks/base/core/java/com/android/internal/logging/InstanceId.java.
+ */
+public final class InstanceId implements Parcelable {
+ // At most 20 bits: ~1m possibilities, ~0.5% probability of collision in 100 values
+ static final int INSTANCE_ID_MAX = 1 << 20;
+
+ private final int mId;
+ InstanceId(int id) {
+ mId = min(max(0, id), INSTANCE_ID_MAX);
+ }
+
+ private InstanceId(Parcel in) {
+ this(in.readInt());
+ }
+
+ @VisibleForTesting
+ public int getId() {
+ return mId;
+ }
+
+ @NonNull
+ @Override
+ public String toString() {
+ return mId + "";
+ }
+
+ /**
+ * Create a fake instance ID for testing purposes. Not for production use. See also
+ * InstanceIdSequenceFake, which is a testing replacement for InstanceIdSequence.
+ * @param id The ID you want to assign.
+ * @return new InstanceId.
+ */
+ @VisibleForTesting
+ public static InstanceId fakeInstanceId(int id) {
+ return new InstanceId(id);
+ }
+
+ @Override
+ public int hashCode() {
+ return mId;
+ }
+
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ if (!(obj instanceof InstanceId)) {
+ return false;
+ }
+ return mId == ((InstanceId) obj).mId;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(mId);
+ }
+
+ public static final Parcelable.Creator<InstanceId> CREATOR =
+ new Parcelable.Creator<InstanceId>() {
+ @Override
+ public InstanceId createFromParcel(Parcel in) {
+ return new InstanceId(in);
+ }
+
+ @Override
+ public InstanceId[] newArray(int size) {
+ return new InstanceId[size];
+ }
+ };
+
+}
diff --git a/src/com/android/launcher3/logging/InstanceIdSequence.java b/src/com/android/launcher3/logging/InstanceIdSequence.java
new file mode 100644
index 0000000..a4b7953
--- /dev/null
+++ b/src/com/android/launcher3/logging/InstanceIdSequence.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.logging;
+
+import static java.lang.Math.max;
+import static java.lang.Math.min;
+
+import androidx.annotation.VisibleForTesting;
+
+import java.security.SecureRandom;
+import java.util.Random;
+
+/**
+ * Generates random InstanceIds in range [1, instanceIdMax] for passing to
+ * UiEventLogger.logWithInstanceId(). Holds a SecureRandom, which self-seeds on first use; try to
+ * give it a long lifetime. Safe for concurrent use.
+ *
+ * Copy of frameworks/base/core/java/com/android/internal/logging/InstanceIdSequence.java
+ */
+public class InstanceIdSequence {
+ protected final int mInstanceIdMax;
+ private final Random mRandom = new SecureRandom();
+
+ /**
+ * Constructs a sequence with identifiers [1, instanceIdMax]. Capped at INSTANCE_ID_MAX.
+ * @param instanceIdMax Limiting value of identifiers. Normally positive: otherwise you get
+ * an all-1 sequence.
+ */
+ public InstanceIdSequence(int instanceIdMax) {
+ mInstanceIdMax = min(max(1, instanceIdMax), InstanceId.INSTANCE_ID_MAX);
+ }
+
+ /**
+ * Gets the next instance from the sequence. Safe for concurrent use.
+ * @return new InstanceId
+ */
+ public InstanceId newInstanceId() {
+ return newInstanceIdInternal(1 + mRandom.nextInt(mInstanceIdMax));
+ }
+
+ /**
+ * Factory function for instance IDs, used for testing.
+ * @param id
+ * @return new InstanceId(id)
+ */
+ @VisibleForTesting
+ protected InstanceId newInstanceIdInternal(int id) {
+ return new InstanceId(id);
+ }
+}
diff --git a/src/com/android/launcher3/logging/LoggerUtils.java b/src/com/android/launcher3/logging/LoggerUtils.java
index 0f79bd6..cd4f034 100644
--- a/src/com/android/launcher3/logging/LoggerUtils.java
+++ b/src/com/android/launcher3/logging/LoggerUtils.java
@@ -41,6 +41,7 @@
private static final ArrayMap<Class, SparseArray<String>> sNameCache = new ArrayMap<>();
private static final String UNKNOWN = "UNKNOWN";
private static final int DEFAULT_PREDICTED_RANK = 10000;
+ private static final String DELIMITER_DOT = "\\.";
public static String getFieldName(int value, Class c) {
SparseArray<String> cache;
@@ -173,4 +174,17 @@
targets.toArray(targetsArray);
return newLauncherEvent(action, targetsArray);
}
+
+ /**
+ * String conversion for only the helpful parts of {@link Object#toString()} method
+ * @param stringToExtract "foo.bar.baz.MyObject@1234"
+ * @return "MyObject@1234"
+ */
+ public static String extractObjectNameAndAddress(String stringToExtract) {
+ String[] superStringParts = stringToExtract.split(DELIMITER_DOT);
+ if (superStringParts.length == 0) {
+ return "";
+ }
+ return superStringParts[superStringParts.length - 1];
+ }
}
diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java
index 2829951..9455bd3 100644
--- a/src/com/android/launcher3/logging/StatsLogManager.java
+++ b/src/com/android/launcher3/logging/StatsLogManager.java
@@ -16,6 +16,7 @@
package com.android.launcher3.logging;
import android.content.Context;
+import android.util.Log;
import com.android.launcher3.R;
import com.android.launcher3.logger.LauncherAtom;
@@ -25,22 +26,61 @@
/**
* Handles the user event logging in R+.
+ * All of the event ids are defined here.
+ * Most of the methods are dummy methods for Launcher3
+ * Actual call happens only for Launcher variant that implements QuickStep.
*/
public class StatsLogManager implements ResourceBasedOverride {
+ private static final String TAG = "StatsLogManager";
+
interface EventEnum {
int getId();
}
public enum LauncherEvent implements EventEnum {
@LauncherUiEvent(doc = "App launched from workspace, hotseat or folder in launcher")
- APP_LAUNCH_TAP(1),
+ LAUNCHER_APP_LAUNCH_TAP(338),
+
@LauncherUiEvent(doc = "Task launched from overview using TAP")
- TASK_LAUNCH_TAP(2),
+ LAUNCHER_TASK_LAUNCH_TAP(339),
+
@LauncherUiEvent(doc = "Task launched from overview using SWIPE DOWN")
- TASK_LAUNCH_SWIPE_DOWN(2),
+ LAUNCHER_TASK_LAUNCH_SWIPE_DOWN(340),
+
@LauncherUiEvent(doc = "TASK dismissed from overview using SWIPE UP")
- TASK_DISMISS_SWIPE_UP(3);
+ LAUNCHER_TASK_DISMISS_SWIPE_UP(341),
+
+ @LauncherUiEvent(doc = "User dragged a launcher item")
+ LAUNCHER_ITEM_DRAG_STARTED(383),
+
+ @LauncherUiEvent(doc = "A dragged launcher item is successfully dropped")
+ LAUNCHER_ITEM_DROP_COMPLETED(385),
+
+ @LauncherUiEvent(doc = "A dragged launcher item is successfully dropped on another item "
+ + "resulting in a new folder creation")
+ LAUNCHER_ITEM_DROP_FOLDER_CREATED(386),
+
+ @LauncherUiEvent(doc = "A dragged item is dropped on 'Remove' button in the target bar")
+ LAUNCHER_ITEM_DROPPED_ON_REMOVE(465),
+
+ @LauncherUiEvent(doc = "A dragged item is dropped on 'Cancel' button in the target bar")
+ LAUNCHER_ITEM_DROPPED_ON_CANCEL(466),
+
+ @LauncherUiEvent(doc = "A predicted item is dragged and dropped on 'Don't suggest app'"
+ + " button in the target bar")
+ LAUNCHER_ITEM_DROPPED_ON_DONT_SUGGEST(467),
+
+ @LauncherUiEvent(doc = "A dragged item is dropped on 'Uninstall' button in target bar")
+ LAUNCHER_ITEM_DROPPED_ON_UNINSTALL(468),
+
+ @LauncherUiEvent(doc = "User completed uninstalling the package after dropping on "
+ + "the icon onto 'Uninstall' button in the target bar")
+ LAUNCHER_ITEM_UNINSTALL_COMPLETED(469),
+
+ @LauncherUiEvent(doc = "User cancelled uninstalling the package after dropping on "
+ + "the icon onto 'Uninstall' button in the target bar")
+ LAUNCHER_ITEM_UNINSTALL_CANCELLED(470);
// ADD MORE
private final int mId;
@@ -54,23 +94,37 @@
protected LogStateProvider mStateProvider;
+ /**
+ * Creates a new instance of {@link StatsLogManager} based on provided context.
+ */
+ public static StatsLogManager newInstance(Context context) {
+ return newInstance(context, null);
+ }
+
public static StatsLogManager newInstance(Context context, LogStateProvider stateProvider) {
StatsLogManager mgr = Overrides.getObject(StatsLogManager.class,
context.getApplicationContext(), R.string.stats_log_manager_class);
mgr.mStateProvider = stateProvider;
- mgr.verify();
return mgr;
}
/**
* Logs an event and accompanying {@link ItemInfo}
*/
- public void log(LauncherEvent eventId, LauncherAtom.ItemInfo itemInfo) { }
+ public void log(LauncherEvent event, InstanceId instanceId) {
+ Log.d(TAG, String.format("%s(InstanceId:%s)", event.name(), instanceId));
+ // Call StatsLog method
+ }
+
+ /**
+ * Logs an event and accompanying {@link LauncherAtom.ItemInfo}
+ */
+ public void log(LauncherEvent event, InstanceId instanceId, LauncherAtom.ItemInfo itemInfo) { }
+ public void log(LauncherEvent event, LauncherAtom.ItemInfo itemInfo) { }
+
/**
* Logs snapshot, or impression of the current workspace.
*/
public void logSnapshot() { }
-
- public void verify() {} // TODO: should move into robo tests
}
diff --git a/src/com/android/launcher3/logging/StatsLogUtils.java b/src/com/android/launcher3/logging/StatsLogUtils.java
index 97aaf84..10d88e5 100644
--- a/src/com/android/launcher3/logging/StatsLogUtils.java
+++ b/src/com/android/launcher3/logging/StatsLogUtils.java
@@ -1,7 +1,5 @@
package com.android.launcher3.logging;
-import static com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType.DEFAULT_CONTAINERTYPE;
-
import android.view.View;
import android.view.ViewParent;
@@ -13,6 +11,7 @@
import java.util.ArrayList;
+import static com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType.DEFAULT_CONTAINERTYPE;
public class StatsLogUtils {
@@ -31,8 +30,6 @@
/**
* Implemented by containers to provide a container source for a given child.
- *
- * Currently,
*/
public interface LogContainerProvider {
diff --git a/src/com/android/launcher3/model/BaseLoaderResults.java b/src/com/android/launcher3/model/BaseLoaderResults.java
index c98be56..1465100 100644
--- a/src/com/android/launcher3/model/BaseLoaderResults.java
+++ b/src/com/android/launcher3/model/BaseLoaderResults.java
@@ -17,6 +17,7 @@
package com.android.launcher3.model;
import static com.android.launcher3.model.ModelUtils.filterCurrentWorkspaceItems;
+import static com.android.launcher3.model.ModelUtils.getMissingHotseatRanks;
import static com.android.launcher3.model.ModelUtils.sortWorkspaceItemsSpatially;
import android.util.Log;
@@ -196,6 +197,10 @@
// Load items on the current page.
bindWorkspaceItems(currentWorkspaceItems, mainExecutor);
bindAppWidgets(currentAppWidgets, mainExecutor);
+
+ // Locate available spots for prediction using currentWorkspaceItems
+ IntArray gaps = getMissingHotseatRanks(currentWorkspaceItems, idp.numHotseatIcons);
+ bindPredictedItems(gaps, mainExecutor);
// In case of validFirstPage, only bind the first screen, and defer binding the
// remaining screens after first onDraw (and an optional the fade animation whichever
// happens later).
@@ -247,6 +252,11 @@
}
}
+ private void bindPredictedItems(IntArray ranks, final Executor executor) {
+ executeCallbacksTask(
+ c -> c.bindPredictedItems(mBgDataModel.cachedPredictedItems, ranks), executor);
+ }
+
protected void executeCallbacksTask(CallbackTask task, Executor executor) {
executor.execute(() -> {
if (mMyBindingId != mBgDataModel.lastBindId) {
diff --git a/src/com/android/launcher3/model/BgDataModel.java b/src/com/android/launcher3/model/BgDataModel.java
index f79a9d1..2522a49 100644
--- a/src/com/android/launcher3/model/BgDataModel.java
+++ b/src/com/android/launcher3/model/BgDataModel.java
@@ -93,6 +93,11 @@
public final Map<ShortcutKey, MutableInt> pinnedShortcutCounts = new HashMap<>();
/**
+ * List of all cached predicted items visible on home screen
+ */
+ public final ArrayList<AppInfo> cachedPredictedItems = new ArrayList<>();
+
+ /**
* True if the launcher has permission to access deep shortcuts.
*/
public boolean hasShortcutHostPermission;
@@ -366,5 +371,10 @@
void bindDeepShortcutMap(HashMap<ComponentKey, Integer> deepShortcutMap);
void bindAllApplications(AppInfo[] apps);
+
+ /**
+ * Binds predicted appInfos at at available prediction slots.
+ */
+ void bindPredictedItems(List<AppInfo> appInfos, IntArray ranks);
}
}
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index 4c02837..9e6282e 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -179,6 +179,7 @@
try (LauncherModel.LoaderTransaction transaction = mApp.getModel().beginLoader(this)) {
List<ShortcutInfo> allShortcuts = new ArrayList<>();
loadWorkspace(allShortcuts);
+ loadCachedPredictions();
logger.addSplit("loadWorkspace");
verifyNotStopped();
@@ -849,6 +850,26 @@
}
}
+ private List<AppInfo> loadCachedPredictions() {
+ synchronized (mBgDataModel) {
+ List<ComponentKey> componentKeys =
+ mApp.getPredictionModel().getPredictionComponentKeys();
+ List<AppInfo> results = new ArrayList<>();
+ if (componentKeys == null) return results;
+ List<LauncherActivityInfo> l;
+ mBgDataModel.cachedPredictedItems.clear();
+ for (ComponentKey key : componentKeys) {
+ l = mLauncherApps.getActivityList(key.componentName.getPackageName(), key.user);
+ if (l.size() == 0) continue;
+ boolean quietMode = mUserManager.isQuietModeEnabled(key.user);
+ AppInfo info = new AppInfo(l.get(0), key.user, quietMode);
+ mBgDataModel.cachedPredictedItems.add(info);
+ mIconCache.getTitleAndIcon(info, false);
+ }
+ return results;
+ }
+ }
+
private List<LauncherActivityInfo> loadAllApps() {
final List<UserHandle> profiles = mUserCache.getUserProfiles();
List<LauncherActivityInfo> allActivityList = new ArrayList<>();
@@ -880,6 +901,14 @@
PackageInstallInfo.fromInstallingState(info));
}
}
+ for (AppInfo item : mBgDataModel.cachedPredictedItems) {
+ List<LauncherActivityInfo> l = mLauncherApps.getActivityList(
+ item.componentName.getPackageName(), item.user);
+ for (LauncherActivityInfo info : l) {
+ boolean quietMode = mUserManager.isQuietModeEnabled(item.user);
+ mBgAllAppsList.add(new AppInfo(info, item.user, quietMode), info);
+ }
+ }
mBgAllAppsList.getAndResetChangeFlag();
return allActivityList;
diff --git a/src/com/android/launcher3/model/ModelUtils.java b/src/com/android/launcher3/model/ModelUtils.java
index ef7e828..4efeba5 100644
--- a/src/com/android/launcher3/model/ModelUtils.java
+++ b/src/com/android/launcher3/model/ModelUtils.java
@@ -19,11 +19,14 @@
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.IntSet;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
+import java.util.List;
+import java.util.stream.IntStream;
/**
* Utils class for {@link com.android.launcher3.LauncherModel}.
@@ -109,4 +112,17 @@
}
});
}
+
+ /**
+ * Iterates though current workspace items and returns available hotseat ranks for prediction.
+ */
+ public static IntArray getMissingHotseatRanks(List<ItemInfo> items, int len) {
+ IntSet seen = new IntSet();
+ items.stream().filter(
+ info -> info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT)
+ .forEach(i -> seen.add(i.screenId));
+ IntArray result = new IntArray(len);
+ IntStream.range(0, len).filter(i -> !seen.contains(i)).forEach(result::add);
+ return result;
+ }
}
diff --git a/src/com/android/launcher3/model/PredictionModel.java b/src/com/android/launcher3/model/PredictionModel.java
new file mode 100644
index 0000000..6aa41eb
--- /dev/null
+++ b/src/com/android/launcher3/model/PredictionModel.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.model;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.os.UserHandle;
+
+import com.android.launcher3.Utilities;
+import com.android.launcher3.model.data.AppInfo;
+import com.android.launcher3.util.ComponentKey;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * Model helper for app predictions in workspace
+ */
+public class PredictionModel {
+ private static final String CACHED_ITEMS_KEY = "predicted_item_keys";
+ private static final int MAX_CACHE_ITEMS = 5;
+
+ private final Context mContext;
+ private final SharedPreferences mDevicePrefs;
+ private ArrayList<ComponentKey> mCachedComponentKeys;
+
+ public PredictionModel(Context context) {
+ mContext = context;
+ mDevicePrefs = Utilities.getDevicePrefs(mContext);
+ }
+
+ /**
+ * Formats and stores a list of component key in device preferences.
+ */
+ public void cachePredictionComponentKeys(List<ComponentKey> componentKeys) {
+ StringBuilder builder = new StringBuilder();
+ int count = Math.min(componentKeys.size(), MAX_CACHE_ITEMS);
+ for (int i = 0; i < count; i++) {
+ builder.append(componentKeys.get(i));
+ builder.append("\n");
+ }
+ mDevicePrefs.edit().putString(CACHED_ITEMS_KEY, builder.toString()).apply();
+ mCachedComponentKeys = null;
+ }
+
+ /**
+ * parses and returns ComponentKeys saved by
+ * {@link PredictionModel#cachePredictionComponentKeys(List)}
+ */
+ public List<ComponentKey> getPredictionComponentKeys() {
+ if (mCachedComponentKeys == null) {
+ mCachedComponentKeys = new ArrayList<>();
+
+ String cachedBlob = mDevicePrefs.getString(CACHED_ITEMS_KEY, "");
+ for (String line : cachedBlob.split("\n")) {
+ ComponentKey key = ComponentKey.fromString(line);
+ if (key != null) {
+ mCachedComponentKeys.add(key);
+ }
+ }
+ }
+ return mCachedComponentKeys;
+ }
+
+ /**
+ * Remove uninstalled applications from model
+ */
+ public void removePackage(String pkgName, UserHandle user, ArrayList<AppInfo> ids) {
+ for (int i = ids.size() - 1; i >= 0; i--) {
+ AppInfo info = ids.get(i);
+ if (info.user.equals(user) && pkgName.equals(info.componentName.getPackageName())) {
+ ids.remove(i);
+ }
+ }
+ cachePredictionComponentKeys(getPredictionComponentKeys().stream()
+ .filter(cn -> !(cn.user.equals(user) && cn.componentName.getPackageName().equals(
+ pkgName))).collect(Collectors.toList()));
+ }
+}
diff --git a/src/com/android/launcher3/model/data/AppInfo.java b/src/com/android/launcher3/model/data/AppInfo.java
index ae79f0d..b17b062 100644
--- a/src/com/android/launcher3/model/data/AppInfo.java
+++ b/src/com/android/launcher3/model/data/AppInfo.java
@@ -16,6 +16,8 @@
package com.android.launcher3.model.data;
+import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_ALL_APPS;
+
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -74,7 +76,7 @@
public AppInfo(LauncherActivityInfo info, UserHandle user, boolean quietModeEnabled) {
this.componentName = info.getComponentName();
- this.container = ItemInfo.NO_ID;
+ this.container = CONTAINER_ALL_APPS;
this.user = user;
intent = makeLaunchIntent(info);
diff --git a/src/com/android/launcher3/model/data/FolderInfo.java b/src/com/android/launcher3/model/data/FolderInfo.java
index cfe34c1..3ac6a22 100644
--- a/src/com/android/launcher3/model/data/FolderInfo.java
+++ b/src/com/android/launcher3/model/data/FolderInfo.java
@@ -21,6 +21,7 @@
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.Utilities;
+import com.android.launcher3.logger.LauncherAtom;
import com.android.launcher3.model.ModelWriter;
import com.android.launcher3.util.ContentWriter;
@@ -155,4 +156,20 @@
return super.dumpProperties()
+ " manuallyTypedTitle=" + hasOption(FLAG_MANUAL_FOLDER_NAME);
}
+
+ @Override
+ public LauncherAtom.ItemInfo buildProto(FolderInfo fInfo) {
+ return getDefaultItemInfoBuilder()
+ .setFolderIcon(LauncherAtom.FolderIcon.newBuilder().setCardinality(contents.size()))
+ .setContainerInfo(getContainerInfo())
+ .build();
+ }
+
+ @Override
+ public ItemInfo makeShallowCopy() {
+ FolderInfo folderInfo = new FolderInfo();
+ folderInfo.copyFrom(this);
+ folderInfo.contents = this.contents;
+ return folderInfo;
+ }
}
diff --git a/src/com/android/launcher3/model/data/ItemInfo.java b/src/com/android/launcher3/model/data/ItemInfo.java
index 14f9a3e..7611ee7 100644
--- a/src/com/android/launcher3/model/data/ItemInfo.java
+++ b/src/com/android/launcher3/model/data/ItemInfo.java
@@ -16,8 +16,10 @@
package com.android.launcher3.model.data;
+import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_ALL_APPS;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT;
+import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
@@ -35,6 +37,8 @@
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.Workspace;
import com.android.launcher3.logger.LauncherAtom;
+import com.android.launcher3.logger.LauncherAtom.AllAppsContainer;
+import com.android.launcher3.logger.LauncherAtom.ContainerInfo;
import com.android.launcher3.util.ContentWriter;
import java.util.Optional;
@@ -122,6 +126,12 @@
*/
public CharSequence contentDescription;
+ /**
+ * When the instance is created using {@link #copyFrom}, this field is used to keep track of
+ * original {@link ComponentName}.
+ */
+ private ComponentName mComponentName;
+
public UserHandle user;
public ItemInfo() {
@@ -144,6 +154,7 @@
container = info.container;
user = info.user;
contentDescription = info.contentDescription;
+ mComponentName = info.getTargetComponent();
}
public Intent getIntent() {
@@ -152,12 +163,7 @@
@Nullable
public ComponentName getTargetComponent() {
- Intent intent = getIntent();
- if (intent != null) {
- return intent.getComponent();
- } else {
- return null;
- }
+ return Optional.ofNullable(getIntent()).map(Intent::getComponent).orElse(mComponentName);
}
public void writeToValues(ContentWriter writer) {
@@ -246,10 +252,8 @@
/**
* Creates {@link LauncherAtom.ItemInfo} with important fields and parent container info.
*/
- public LauncherAtom.ItemInfo buildProto(Intent intent, FolderInfo fInfo) {
-
- LauncherAtom.ItemInfo.Builder itemBuilder = LauncherAtom.ItemInfo.newBuilder();
- itemBuilder.setIsWork(user != Process.myUserHandle());
+ public LauncherAtom.ItemInfo buildProto(FolderInfo fInfo) {
+ LauncherAtom.ItemInfo.Builder itemBuilder = getDefaultItemInfoBuilder();
Optional<ComponentName> nullableComponent = Optional.ofNullable(getTargetComponent());
switch (itemType) {
case ITEM_TYPE_APPLICATION:
@@ -269,7 +273,14 @@
.orElse(LauncherAtom.Shortcut.newBuilder()));
break;
case ITEM_TYPE_APPWIDGET:
- setItemBuilder(itemBuilder);
+ itemBuilder
+ .setWidget(nullableComponent
+ .map(component -> LauncherAtom.Widget.newBuilder()
+ .setComponentName(component.flattenToShortString())
+ .setPackageName(component.getPackageName()))
+ .orElse(LauncherAtom.Widget.newBuilder())
+ .setSpanX(spanX)
+ .setSpanY(spanY));
break;
default:
break;
@@ -281,6 +292,7 @@
switch (fInfo.container) {
case CONTAINER_HOTSEAT:
+ case CONTAINER_HOTSEAT_PREDICTION:
folderBuilder.setHotseat(LauncherAtom.HotseatContainer.newBuilder()
.setIndex(fInfo.screenId));
break;
@@ -290,21 +302,47 @@
.setGridX(fInfo.cellX).setGridY(fInfo.cellY));
break;
}
- itemBuilder.setFolder(folderBuilder);
- } else {
- switch (container) {
- case CONTAINER_HOTSEAT:
- itemBuilder.setHotseat(LauncherAtom.HotseatContainer.newBuilder()
- .setIndex(screenId));
- break;
- case CONTAINER_DESKTOP:
- itemBuilder.setWorkspace(LauncherAtom.WorkspaceContainer.newBuilder()
- .setGridX(cellX)
- .setGridY(cellY)
- .setPageIndex(screenId));
- break;
- }
+ itemBuilder.setContainerInfo(ContainerInfo.newBuilder().setFolder(folderBuilder));
+ } else if (getContainerInfo().getContainerCase().getNumber() > 0) {
+ itemBuilder.setContainerInfo(getContainerInfo());
}
return itemBuilder.build();
}
+
+ LauncherAtom.ItemInfo.Builder getDefaultItemInfoBuilder() {
+ LauncherAtom.ItemInfo.Builder itemBuilder = LauncherAtom.ItemInfo.newBuilder();
+ itemBuilder.setIsWork(user != Process.myUserHandle());
+ return itemBuilder;
+ }
+
+ ContainerInfo getContainerInfo() {
+ switch (container) {
+ case CONTAINER_HOTSEAT:
+ case CONTAINER_HOTSEAT_PREDICTION:
+ return ContainerInfo.newBuilder()
+ .setHotseat(LauncherAtom.HotseatContainer.newBuilder().setIndex(screenId))
+ .build();
+ case CONTAINER_DESKTOP:
+ return ContainerInfo.newBuilder()
+ .setWorkspace(
+ LauncherAtom.WorkspaceContainer.newBuilder()
+ .setGridX(cellX)
+ .setGridY(cellY)
+ .setPageIndex(screenId))
+ .build();
+ case CONTAINER_ALL_APPS:
+ return ContainerInfo.newBuilder()
+ .setAllAppsContainer(
+ AllAppsContainer.getDefaultInstance())
+ .build();
+ }
+ return ContainerInfo.getDefaultInstance();
+ }
+
+ /** Returns shallow copy of the object. */
+ public ItemInfo makeShallowCopy() {
+ ItemInfo itemInfo = new ItemInfo();
+ itemInfo.copyFrom(this);
+ return itemInfo;
+ }
}
diff --git a/src/com/android/launcher3/model/data/LauncherAppWidgetInfo.java b/src/com/android/launcher3/model/data/LauncherAppWidgetInfo.java
index adb97dc..b0d19a6 100644
--- a/src/com/android/launcher3/model/data/LauncherAppWidgetInfo.java
+++ b/src/com/android/launcher3/model/data/LauncherAppWidgetInfo.java
@@ -21,6 +21,8 @@
import android.content.Intent;
import android.os.Process;
+import androidx.annotation.Nullable;
+
import com.android.launcher3.AppWidgetResizeFrame;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherSettings;
@@ -142,6 +144,12 @@
return appWidgetId <= CUSTOM_WIDGET_ID;
}
+ @Nullable
+ @Override
+ public ComponentName getTargetComponent() {
+ return providerName;
+ }
+
@Override
public void onAddToDatabase(ContentWriter writer) {
super.onAddToDatabase(writer);
diff --git a/src/com/android/launcher3/pm/InstallSessionHelper.java b/src/com/android/launcher3/pm/InstallSessionHelper.java
index 976d7ba..901d27f 100644
--- a/src/com/android/launcher3/pm/InstallSessionHelper.java
+++ b/src/com/android/launcher3/pm/InstallSessionHelper.java
@@ -56,8 +56,6 @@
// Set<String> of session ids of promise icons that have been added to the home screen
// as FLAG_PROMISE_NEW_INSTALLS.
protected static final String PROMISE_ICON_IDS = "promise_icon_ids";
- public static final String KEY_INSTALL_SESSION_CREATED_TIMESTAMP =
- "key_install_session_created_timestamp";
private static final boolean DEBUG = false;
@@ -166,14 +164,13 @@
}
/**
- * Attempt to restore workspace layout if the session is triggered due to device restore and it
- * has a newer timestamp.
+ * Attempt to restore workspace layout if the session is triggered due to device restore.
*/
public boolean restoreDbIfApplicable(@NonNull final SessionInfo info) {
if (!Utilities.ATLEAST_OREO || !FeatureFlags.ENABLE_DATABASE_RESTORE.get()) {
return false;
}
- if (isRestore(info) && hasNewerTimestamp(mAppContext, info)) {
+ if (isRestore(info)) {
LauncherSettings.Settings.call(mAppContext.getContentResolver(),
LauncherSettings.Settings.METHOD_RESTORE_BACKUP_TABLE);
return true;
@@ -186,13 +183,6 @@
return info.getInstallReason() == PackageManager.INSTALL_REASON_DEVICE_RESTORE;
}
- private static boolean hasNewerTimestamp(
- @NonNull final Context context, @NonNull final SessionInfo info) {
- return PackageManagerHelper.getSessionCreatedTimeInMillis(info)
- > Utilities.getDevicePrefs(context).getLong(
- KEY_INSTALL_SESSION_CREATED_TIMESTAMP, 0);
- }
-
public boolean promiseIconAddedForId(int sessionId) {
return mPromiseIconIds.contains(sessionId);
}
diff --git a/src/com/android/launcher3/provider/RestoreDbTask.java b/src/com/android/launcher3/provider/RestoreDbTask.java
index 33eff57..53183bf 100644
--- a/src/com/android/launcher3/provider/RestoreDbTask.java
+++ b/src/com/android/launcher3/provider/RestoreDbTask.java
@@ -16,7 +16,6 @@
package com.android.launcher3.provider;
-import static com.android.launcher3.pm.InstallSessionHelper.KEY_INSTALL_SESSION_CREATED_TIMESTAMP;
import static com.android.launcher3.provider.LauncherDbUtils.dropTable;
import android.app.backup.BackupManager;
@@ -87,13 +86,10 @@
*/
public static boolean restoreIfPossible(@NonNull Context context,
@NonNull DatabaseHelper helper, @NonNull BackupManager backupManager) {
- Utilities.getDevicePrefs(context).edit().putLong(
- KEY_INSTALL_SESSION_CREATED_TIMESTAMP, System.currentTimeMillis()).apply();
final SQLiteDatabase db = helper.getWritableDatabase();
try (SQLiteTransaction t = new SQLiteTransaction(db)) {
RestoreDbTask task = new RestoreDbTask();
task.restoreWorkspace(context, db, helper, backupManager);
- task.restoreAppWidgetIdsIfExists(context);
t.commit();
return true;
} catch (Exception e) {
@@ -107,7 +103,6 @@
*/
private void backupWorkspace(Context context, SQLiteDatabase db) throws Exception {
InvariantDeviceProfile idp = LauncherAppState.getIDP(context);
- // TODO(pinyaoting): Support backing up workspace with multiple grid options.
new GridBackupTable(context, db, idp.numHotseatIcons, idp.numColumns, idp.numRows)
.doBackup(getDefaultProfileId(db), GridBackupTable.OPTION_REQUIRES_SANITIZATION);
}
@@ -115,13 +110,17 @@
private void restoreWorkspace(@NonNull Context context, @NonNull SQLiteDatabase db,
@NonNull DatabaseHelper helper, @NonNull BackupManager backupManager)
throws Exception {
- // TODO(pinyaoting): Support restoring workspace with multiple grid options.
final InvariantDeviceProfile idp = LauncherAppState.getIDP(context);
GridBackupTable backupTable = new GridBackupTable(context, db, idp.numHotseatIcons,
idp.numColumns, idp.numRows);
if (backupTable.restoreFromRawBackupIfAvailable(getDefaultProfileId(db))) {
- sanitizeDB(helper, db, backupManager);
+ int itemsDeleted = sanitizeDB(helper, db, backupManager);
LauncherAppState.getInstance(context).getModel().forceReload();
+ restoreAppWidgetIdsIfExists(context);
+ if (itemsDeleted == 0) {
+ // all the items are restored, we no longer need the backup table
+ dropTable(db, Favorites.BACKUP_TABLE_NAME);
+ }
}
}
@@ -132,8 +131,10 @@
* the restored apps get installed.
* 3. If the user serial for any restored profile is different than that of the previous
* device, update the entries to the new profile id.
+ *
+ * @return number of items deleted.
*/
- private void sanitizeDB(DatabaseHelper helper, SQLiteDatabase db, BackupManager backupManager)
+ private int sanitizeDB(DatabaseHelper helper, SQLiteDatabase db, BackupManager backupManager)
throws Exception {
// Primary user ids
long myProfileId = helper.getDefaultUserSerial();
@@ -210,6 +211,7 @@
if (myProfileId != oldProfileId) {
changeDefaultColumn(db, myProfileId);
}
+ return itemsDeleted;
}
/**
diff --git a/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java b/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java
index dd6fc49..4a15af1 100644
--- a/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java
+++ b/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java
@@ -196,6 +196,9 @@
public void bindItems(List<ItemInfo> shortcuts, boolean forceAnimateIcons) { }
@Override
+ public void bindPredictedItems(List<AppInfo> appInfos, IntArray ranks) { }
+
+ @Override
public void bindScreens(IntArray orderedScreenIds) { }
@Override
diff --git a/src/com/android/launcher3/statemanager/BaseState.java b/src/com/android/launcher3/statemanager/BaseState.java
new file mode 100644
index 0000000..daec1d8
--- /dev/null
+++ b/src/com/android/launcher3/statemanager/BaseState.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.statemanager;
+
+import android.content.Context;
+
+/**
+ * Interface representing a state of a StatefulActivity
+ */
+public interface BaseState<T extends BaseState> {
+
+ // Flag to indicate that Launcher is non-interactive in this state
+ int FLAG_NON_INTERACTIVE = 1 << 0;
+ int FLAG_DISABLE_RESTORE = 1 << 1;
+
+ static int getFlag(int index) {
+ // reserve few spots to base flags
+ return 1 << (index + 2);
+ }
+
+ /**
+ * @return How long the animation to this state should take (or from this state to NORMAL).
+ */
+ int getTransitionDuration(Context context);
+
+ /**
+ * Returns the state to go back to from this state
+ */
+ T getHistoryForState(T previousState);
+
+ /**
+ * @return true if the state can be persisted across activity restarts.
+ */
+ default boolean shouldDisableRestore() {
+ return hasFlag(FLAG_DISABLE_RESTORE);
+ }
+
+ /**
+ * Returns if the state has the provided flag
+ */
+ boolean hasFlag(int flagMask);
+}
diff --git a/src/com/android/launcher3/LauncherStateManager.java b/src/com/android/launcher3/statemanager/StateManager.java
similarity index 69%
rename from src/com/android/launcher3/LauncherStateManager.java
rename to src/com/android/launcher3/statemanager/StateManager.java
index 1d2e866..4447166 100644
--- a/src/com/android/launcher3/LauncherStateManager.java
+++ b/src/com/android/launcher3/statemanager/StateManager.java
@@ -14,9 +14,8 @@
* limitations under the License.
*/
-package com.android.launcher3;
+package com.android.launcher3.statemanager;
-import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_COMPONENTS;
import android.animation.Animator;
@@ -25,93 +24,62 @@
import android.animation.AnimatorSet;
import android.os.Handler;
import android.os.Looper;
+import android.util.Log;
+import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.PendingAnimation;
-import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.states.StateAnimationConfig.AnimationFlags;
+import com.android.launcher3.testing.TestProtocol;
import java.io.PrintWriter;
import java.util.ArrayList;
/**
- * TODO: figure out what kind of tests we can write for this
- *
- * Things to test when changing the following class.
- * - Home from workspace
- * - from center screen
- * - from other screens
- * - Home from all apps
- * - from center screen
- * - from other screens
- * - Back from all apps
- * - from center screen
- * - from other screens
- * - Launch app from workspace and quit
- * - with back
- * - with home
- * - Launch app from all apps and quit
- * - with back
- * - with home
- * - Go to a screen that's not the default, then all
- * apps, and launch and app, and go back
- * - with back
- * -with home
- * - On workspace, long press power and go back
- * - with back
- * - with home
- * - On all apps, long press power and go back
- * - with back
- * - with home
- * - On workspace, power off
- * - On all apps, power off
- * - Launch an app and turn off the screen while in that app
- * - Go back with home key
- * - Go back with back key TODO: make this not go to workspace
- * - From all apps
- * - From workspace
- * - Enter and exit car mode (becase it causes an extra configuration changed)
- * - From all apps
- * - From the center workspace
- * - From another workspace
+ * Class to manage transitions between different states for a StatefulActivity based on different
+ * states
*/
-public class LauncherStateManager {
+public class StateManager<STATE_TYPE extends BaseState<STATE_TYPE>> {
public static final String TAG = "StateManager";
private final AnimationState mConfig = new AnimationState();
private final Handler mUiHandler;
- private final Launcher mLauncher;
- private final ArrayList<StateListener> mListeners = new ArrayList<>();
+ private final StatefulActivity<STATE_TYPE> mActivity;
+ private final ArrayList<StateListener<STATE_TYPE>> mListeners = new ArrayList<>();
+ private final STATE_TYPE mBaseState;
// Animators which are run on properties also controlled by state animations.
- private Animator[] mStateElementAnimators;
+ private final AtomicAnimationFactory mAtomicAnimationFactory;
- private StateHandler[] mStateHandlers;
- private LauncherState mState = NORMAL;
+ private StateHandler<STATE_TYPE>[] mStateHandlers;
+ private STATE_TYPE mState;
- private LauncherState mLastStableState = NORMAL;
- private LauncherState mCurrentStableState = NORMAL;
+ private STATE_TYPE mLastStableState;
+ private STATE_TYPE mCurrentStableState;
- private LauncherState mRestState;
+ private STATE_TYPE mRestState;
- public LauncherStateManager(Launcher l) {
+ public StateManager(StatefulActivity<STATE_TYPE> l, STATE_TYPE baseState) {
mUiHandler = new Handler(Looper.getMainLooper());
- mLauncher = l;
+ mActivity = l;
+ mBaseState = baseState;
+ mState = mLastStableState = mCurrentStableState = baseState;
+ mAtomicAnimationFactory = l.createAtomicAnimationFactory();
}
- public LauncherState getState() {
+ public STATE_TYPE getState() {
return mState;
}
- public LauncherState getCurrentStableState() {
+ public STATE_TYPE getCurrentStableState() {
return mCurrentStableState;
}
public void dump(String prefix, PrintWriter writer) {
- writer.println(prefix + "LauncherState:");
+ writer.println(prefix + "StateManager:");
writer.println(prefix + "\tmLastStableState:" + mLastStableState);
writer.println(prefix + "\tmCurrentStableState:" + mCurrentStableState);
writer.println(prefix + "\tmState:" + mState);
@@ -121,7 +89,7 @@
public StateHandler[] getStateHandlers() {
if (mStateHandlers == null) {
- mStateHandlers = mLauncher.createStateHandlers();
+ mStateHandlers = mActivity.createStateHandlers();
}
return mStateHandlers;
}
@@ -138,29 +106,29 @@
* Returns true if the state changes should be animated.
*/
public boolean shouldAnimateStateChange() {
- return !mLauncher.isForceInvisible() && mLauncher.isStarted();
+ return !mActivity.isForceInvisible() && mActivity.isStarted();
}
/**
* @return {@code true} if the state matches the current state and there is no active
* transition to different state.
*/
- public boolean isInStableState(LauncherState state) {
+ public boolean isInStableState(STATE_TYPE state) {
return mState == state && mCurrentStableState == state
&& (mConfig.targetState == null || mConfig.targetState == state);
}
/**
- * @see #goToState(LauncherState, boolean, Runnable)
+ * @see #goToState(STATE_TYPE, boolean, Runnable)
*/
- public void goToState(LauncherState state) {
+ public void goToState(STATE_TYPE state) {
goToState(state, shouldAnimateStateChange());
}
/**
- * @see #goToState(LauncherState, boolean, Runnable)
+ * @see #goToState(STATE_TYPE, boolean, Runnable)
*/
- public void goToState(LauncherState state, boolean animated) {
+ public void goToState(STATE_TYPE state, boolean animated) {
goToState(state, animated, 0, null);
}
@@ -171,21 +139,21 @@
* true otherwise
* @paras onCompleteRunnable any action to perform at the end of the transition, of null.
*/
- public void goToState(LauncherState state, boolean animated, Runnable onCompleteRunnable) {
+ public void goToState(STATE_TYPE state, boolean animated, Runnable onCompleteRunnable) {
goToState(state, animated, 0, onCompleteRunnable);
}
/**
* Changes the Launcher state to the provided state after the given delay.
*/
- public void goToState(LauncherState state, long delay, Runnable onCompleteRunnable) {
+ public void goToState(STATE_TYPE state, long delay, Runnable onCompleteRunnable) {
goToState(state, true, delay, onCompleteRunnable);
}
/**
* Changes the Launcher state to the provided state after the given delay.
*/
- public void goToState(LauncherState state, long delay) {
+ public void goToState(STATE_TYPE state, long delay) {
goToState(state, true, delay, null);
}
@@ -196,7 +164,7 @@
public void reapplyState(boolean cancelCurrentAnimation) {
boolean wasInAnimation = mConfig.currentAnimation != null;
if (cancelCurrentAnimation) {
- cancelAllStateElementAnimation();
+ mAtomicAnimationFactory.cancelAllStateElementAnimation();
cancelAnimation();
}
if (mConfig.currentAnimation == null) {
@@ -209,10 +177,10 @@
}
}
- private void goToState(LauncherState state, boolean animated, long delay,
+ private void goToState(STATE_TYPE state, boolean animated, long delay,
final Runnable onCompleteRunnable) {
- animated &= Utilities.areAnimationsEnabled(mLauncher);
- if (mLauncher.isInState(state)) {
+ animated &= Utilities.areAnimationsEnabled(mActivity);
+ if (mActivity.isInState(state)) {
if (mConfig.currentAnimation == null) {
// Run any queued runnable
if (onCompleteRunnable != null) {
@@ -230,11 +198,11 @@
}
// Cancel the current animation. This will reset mState to mCurrentStableState, so store it.
- LauncherState fromState = mState;
+ STATE_TYPE fromState = mState;
mConfig.reset();
if (!animated) {
- cancelAllStateElementAnimation();
+ mAtomicAnimationFactory.cancelAllStateElementAnimation();
onStateTransitionStart(state);
for (StateHandler handler : getStateHandlers()) {
handler.setState(state);
@@ -263,13 +231,13 @@
}
}
- private void goToStateAnimated(LauncherState state, LauncherState fromState,
+ private void goToStateAnimated(STATE_TYPE state, STATE_TYPE fromState,
Runnable onCompleteRunnable) {
- // Since state NORMAL can be reached from multiple states, just assume that the
+ // Since state mBaseState can be reached from multiple states, just assume that the
// transition plays in reverse and use the same duration as previous state.
- mConfig.duration = state == NORMAL
- ? fromState.getTransitionDuration(mLauncher)
- : state.getTransitionDuration(mLauncher);
+ mConfig.duration = state == mBaseState
+ ? fromState.getTransitionDuration(mActivity)
+ : state.getTransitionDuration(mActivity);
prepareForAtomicAnimation(fromState, state, mConfig);
AnimatorSet animation = createAnimationToNewWorkspaceInternal(state).getAnim();
if (onCompleteRunnable != null) {
@@ -283,20 +251,20 @@
* - Setting interpolators for various animations included in the state transition.
* - Setting some start values (e.g. scale) for views that are hidden but about to be shown.
*/
- public void prepareForAtomicAnimation(LauncherState fromState, LauncherState toState,
+ public void prepareForAtomicAnimation(STATE_TYPE fromState, STATE_TYPE toState,
StateAnimationConfig config) {
- toState.prepareForAtomicAnimation(mLauncher, fromState, config);
+ mAtomicAnimationFactory.prepareForAtomicAnimation(fromState, toState, config);
}
/**
* Creates an animation representing atomic transitions between the provided states
*/
public AnimatorSet createAtomicAnimation(
- LauncherState fromState, LauncherState toState, StateAnimationConfig config) {
+ STATE_TYPE fromState, STATE_TYPE toState, StateAnimationConfig config) {
PendingAnimation builder = new PendingAnimation(config.duration);
prepareForAtomicAnimation(fromState, toState, config);
- for (StateHandler handler : mLauncher.getStateManager().getStateHandlers()) {
+ for (StateHandler handler : mActivity.getStateManager().getStateHandlers()) {
handler.setStateWithAnimation(toState, config, builder);
}
return builder.getAnim();
@@ -306,23 +274,23 @@
* Creates a {@link AnimatorPlaybackController} that can be used for a controlled
* state transition.
* @param state the final state for the transition.
- * @param duration intended duration for normal playback. Use higher duration for better
+ * @param duration intended duration for state playback. Use higher duration for better
* accuracy.
*/
public AnimatorPlaybackController createAnimationToNewWorkspace(
- LauncherState state, long duration) {
+ STATE_TYPE state, long duration) {
return createAnimationToNewWorkspace(state, duration, ANIM_ALL_COMPONENTS);
}
public AnimatorPlaybackController createAnimationToNewWorkspace(
- LauncherState state, long duration, @AnimationFlags int animComponents) {
+ STATE_TYPE state, long duration, @AnimationFlags int animComponents) {
StateAnimationConfig config = new StateAnimationConfig();
config.duration = duration;
config.animFlags = animComponents;
return createAnimationToNewWorkspace(state, config);
}
- public AnimatorPlaybackController createAnimationToNewWorkspace(LauncherState state,
+ public AnimatorPlaybackController createAnimationToNewWorkspace(STATE_TYPE state,
StateAnimationConfig config) {
config.userControlled = true;
mConfig.reset();
@@ -332,7 +300,11 @@
return mConfig.playbackController;
}
- private PendingAnimation createAnimationToNewWorkspaceInternal(final LauncherState state) {
+ private PendingAnimation createAnimationToNewWorkspaceInternal(final STATE_TYPE state) {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.OVERIEW_NOT_ALLAPPS, "createAnimationToNewWorkspaceInternal: "
+ + state);
+ }
PendingAnimation builder = new PendingAnimation(mConfig.duration);
for (StateHandler handler : getStateHandlers()) {
handler.setStateWithAnimation(state, mConfig, builder);
@@ -347,6 +319,9 @@
@Override
public void onAnimationSuccess(Animator animator) {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.OVERIEW_NOT_ALLAPPS, "onAnimationSuccess: " + state);
+ }
onStateTransitionEnd(state);
}
});
@@ -354,46 +329,33 @@
return builder;
}
- private void onStateTransitionStart(LauncherState state) {
- if (mState != state) {
- mState.onStateDisabled(mLauncher);
- }
+ private void onStateTransitionStart(STATE_TYPE state) {
mState = state;
- mState.onStateEnabled(mLauncher);
- mLauncher.onStateSetStart(mState);
-
- if (state.disablePageClipping) {
- // Only disable clipping if needed, otherwise leave it as previous value.
- mLauncher.getWorkspace().setClipChildren(false);
- }
+ mActivity.onStateSetStart(mState);
for (int i = mListeners.size() - 1; i >= 0; i--) {
mListeners.get(i).onStateTransitionStart(state);
}
}
- private void onStateTransitionEnd(LauncherState state) {
+ private void onStateTransitionEnd(STATE_TYPE state) {
// Only change the stable states after the transitions have finished
if (state != mCurrentStableState) {
mLastStableState = state.getHistoryForState(mCurrentStableState);
mCurrentStableState = state;
}
- state.onStateTransitionEnd(mLauncher);
- mLauncher.onStateSetEnd(state);
-
- if (state == NORMAL) {
+ mActivity.onStateSetEnd(state);
+ if (state == mBaseState) {
setRestState(null);
}
for (int i = mListeners.size() - 1; i >= 0; i--) {
mListeners.get(i).onStateTransitionComplete(state);
}
-
- AccessibilityManagerCompat.sendStateEventToTest(mLauncher, state.ordinal);
}
- public LauncherState getLastState() {
+ public STATE_TYPE getLastState() {
return mLastStableState;
}
@@ -402,18 +364,18 @@
// The user is doing something. Lets not mess it up
return;
}
- if (mState.disableRestore) {
+ if (mState.shouldDisableRestore()) {
goToState(getRestState());
// Reset history
- mLastStableState = NORMAL;
+ mLastStableState = mBaseState;
}
}
- public LauncherState getRestState() {
- return mRestState == null ? NORMAL : mRestState;
+ public STATE_TYPE getRestState() {
+ return mRestState == null ? mBaseState : mRestState;
}
- public void setRestState(LauncherState restState) {
+ public void setRestState(STATE_TYPE restState) {
mRestState = restState;
}
@@ -461,42 +423,23 @@
mConfig.setAnimation(anim, null);
}
- private void cancelAllStateElementAnimation() {
- if (mStateElementAnimators == null) {
- return;
- }
-
- for (Animator animator : mStateElementAnimators) {
- if (animator != null) {
- animator.cancel();
- }
- }
- }
-
/**
* Cancels a currently running gesture animation
*/
public void cancelStateElementAnimation(int index) {
- if (mStateElementAnimators == null) {
- return;
- }
- if (mStateElementAnimators[index] != null) {
- mStateElementAnimators[index].cancel();
+ if (mAtomicAnimationFactory.mStateElementAnimators[index] != null) {
+ mAtomicAnimationFactory.mStateElementAnimators[index].cancel();
}
}
public Animator createStateElementAnimation(int index, float... values) {
cancelStateElementAnimation(index);
- LauncherAppTransitionManager latm = mLauncher.getAppTransitionManager();
- if (mStateElementAnimators == null) {
- mStateElementAnimators = new Animator[latm.getStateElementAnimationsCount()];
- }
- Animator anim = latm.createStateElementAnimation(index, values);
- mStateElementAnimators[index] = anim;
+ Animator anim = mAtomicAnimationFactory.createStateElementAnimation(index, values);
+ mAtomicAnimationFactory.mStateElementAnimators[index] = anim;
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
- mStateElementAnimators[index] = null;
+ mAtomicAnimationFactory.mStateElementAnimators[index] = null;
}
});
return anim;
@@ -527,13 +470,14 @@
}
}
- private static class AnimationState extends StateAnimationConfig implements AnimatorListener {
+ private static class AnimationState<STATE_TYPE> extends StateAnimationConfig
+ implements AnimatorListener {
private static final StateAnimationConfig DEFAULT = new StateAnimationConfig();
public AnimatorPlaybackController playbackController;
public AnimatorSet currentAnimation;
- public LauncherState targetState;
+ public STATE_TYPE targetState;
// Id to keep track of config changes, to tie an animation with the corresponding request
public int changeId = 0;
@@ -568,7 +512,7 @@
}
}
- public void setAnimation(AnimatorSet animation, LauncherState targetState) {
+ public void setAnimation(AnimatorSet animation, STATE_TYPE targetState) {
currentAnimation = animation;
this.targetState = targetState;
currentAnimation.addListener(this);
@@ -584,24 +528,66 @@
public void onAnimationRepeat(Animator animator) { }
}
- public interface StateHandler {
+ public interface StateHandler<STATE_TYPE> {
/**
* Updates the UI to {@param state} without any animations
*/
- void setState(LauncherState state);
+ void setState(STATE_TYPE state);
/**
* Sets the UI to {@param state} by animating any changes.
*/
void setStateWithAnimation(
- LauncherState toState, StateAnimationConfig config, PendingAnimation animation);
+ STATE_TYPE toState, StateAnimationConfig config, PendingAnimation animation);
}
- public interface StateListener {
+ public interface StateListener<STATE_TYPE> {
- default void onStateTransitionStart(LauncherState toState) { }
+ default void onStateTransitionStart(STATE_TYPE toState) { }
- default void onStateTransitionComplete(LauncherState finalState) { }
+ default void onStateTransitionComplete(STATE_TYPE finalState) { }
+ }
+
+ /**
+ * Factory class to configure and create atomic animations.
+ */
+ public static class AtomicAnimationFactory<STATE_TYPE> {
+
+ private final Animator[] mStateElementAnimators;
+
+ /**
+ *
+ * @param sharedElementAnimCount number of animations which run on state properties
+ */
+ public AtomicAnimationFactory(int sharedElementAnimCount) {
+ mStateElementAnimators = new Animator[sharedElementAnimCount];
+ }
+
+ void cancelAllStateElementAnimation() {
+ for (Animator animator : mStateElementAnimators) {
+ if (animator != null) {
+ animator.cancel();
+ }
+ }
+ }
+
+ /**
+ * Creates animations for elements which can be also be part of state transitions. The
+ * actual definition of the animation is up to the app to define.
+ *
+ */
+ public Animator createStateElementAnimation(int index, float... values) {
+ throw new RuntimeException("Unknown gesture animation " + index);
+ }
+
+ /**
+ * Prepares for a non-user controlled animation from fromState to this state. Preparations
+ * include:
+ * - Setting interpolators for various animations included in the state transition.
+ * - Setting some start values (e.g. scale) for views that are hidden but about to be shown.
+ */
+ public void prepareForAtomicAnimation(
+ STATE_TYPE fromState, STATE_TYPE toState, StateAnimationConfig config) { }
}
}
diff --git a/src/com/android/launcher3/statemanager/StatefulActivity.java b/src/com/android/launcher3/statemanager/StatefulActivity.java
new file mode 100644
index 0000000..0a1607c
--- /dev/null
+++ b/src/com/android/launcher3/statemanager/StatefulActivity.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.statemanager;
+
+import static com.android.launcher3.LauncherState.FLAG_NON_INTERACTIVE;
+
+import android.os.Handler;
+
+import androidx.annotation.CallSuper;
+
+import com.android.launcher3.BaseDraggingActivity;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.statemanager.StateManager.AtomicAnimationFactory;
+import com.android.launcher3.statemanager.StateManager.StateHandler;
+import com.android.launcher3.views.BaseDragLayer;
+
+/**
+ * Abstract activity with state management
+ * @param <STATE_TYPE> Type of state object
+ */
+public abstract class StatefulActivity<STATE_TYPE extends BaseState<STATE_TYPE>>
+ extends BaseDraggingActivity {
+
+ public final Handler mHandler = new Handler();
+ private final Runnable mHandleDeferredResume = this::handleDeferredResume;
+ private boolean mDeferredResumePending;
+
+ /**
+ * Create handlers to control the property changes for this activity
+ */
+ protected abstract StateHandler<STATE_TYPE>[] createStateHandlers();
+
+ /**
+ * Returns true if the activity is in the provided state
+ */
+ public boolean isInState(STATE_TYPE state) {
+ return getStateManager().getState() == state;
+ }
+
+ /**
+ * Returns the state manager for this activity
+ */
+ public abstract StateManager<STATE_TYPE> getStateManager();
+
+ /**
+ * Called when transition to the state starts
+ */
+ @CallSuper
+ public void onStateSetStart(STATE_TYPE state) {
+ if (mDeferredResumePending) {
+ handleDeferredResume();
+ }
+ }
+
+ /**
+ * Called when transition to state ends
+ */
+ public void onStateSetEnd(STATE_TYPE state) { }
+
+ /**
+ * Creates a factory for atomic state animations
+ */
+ public AtomicAnimationFactory<STATE_TYPE> createAtomicAnimationFactory() {
+ return new AtomicAnimationFactory(0);
+ }
+
+ @Override
+ public void reapplyUi() {
+ reapplyUi(true /* cancelCurrentAnimation */);
+ }
+
+ /**
+ * Re-applies if any state transition is not running, optionally cancelling
+ * the transition if requested.
+ */
+ public void reapplyUi(boolean cancelCurrentAnimation) {
+ getStateManager().reapplyState(cancelCurrentAnimation);
+ }
+
+ @Override
+ protected void onStop() {
+ BaseDragLayer dragLayer = getDragLayer();
+ final boolean wasActive = isUserActive();
+ final STATE_TYPE origState = getStateManager().getState();
+ final int origDragLayerChildCount = dragLayer.getChildCount();
+ super.onStop();
+
+ getStateManager().moveToRestState();
+
+ // Workaround for b/78520668, explicitly trim memory once UI is hidden
+ onTrimMemory(TRIM_MEMORY_UI_HIDDEN);
+
+ if (wasActive) {
+ // The expected condition is that this activity is stopped because the device goes to
+ // sleep and the UI may have noticeable changes.
+ dragLayer.post(() -> {
+ if ((!getStateManager().isInStableState(origState)
+ // The drag layer may be animating (e.g. dismissing QSB).
+ || dragLayer.getAlpha() < 1
+ // Maybe an ArrowPopup is closed.
+ || dragLayer.getChildCount() != origDragLayerChildCount)) {
+ onUiChangedWhileSleeping();
+ }
+ });
+ }
+ }
+
+ /**
+ * Called if the Activity UI changed while the activity was not visible
+ */
+ protected void onUiChangedWhileSleeping() { }
+
+ private void handleDeferredResume() {
+ if (hasBeenResumed() && !getStateManager().getState().hasFlag(FLAG_NON_INTERACTIVE)) {
+ onDeferredResumed();
+ addActivityFlags(ACTIVITY_STATE_DEFERRED_RESUMED);
+
+ mDeferredResumePending = false;
+ } else {
+ mDeferredResumePending = true;
+ }
+ }
+
+ /**
+ * Called want the activity has stayed resumed for 1 frame.
+ */
+ protected void onDeferredResumed() { }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ mHandler.removeCallbacks(mHandleDeferredResume);
+ Utilities.postAsyncCallback(mHandler, mHandleDeferredResume);
+ }
+}
diff --git a/src/com/android/launcher3/states/HintState.java b/src/com/android/launcher3/states/HintState.java
index 43f30f1..9ea8436 100644
--- a/src/com/android/launcher3/states/HintState.java
+++ b/src/com/android/launcher3/states/HintState.java
@@ -15,10 +15,10 @@
*/
package com.android.launcher3.states;
+import android.content.Context;
+
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
-import com.android.launcher3.LauncherStateManager;
-import com.android.launcher3.Workspace;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
/**
@@ -26,7 +26,7 @@
*/
public class HintState extends LauncherState {
- private static final int STATE_FLAGS = FLAG_DISABLE_ACCESSIBILITY | FLAG_DISABLE_RESTORE
+ private static final int STATE_FLAGS = FLAG_WORKSPACE_INACCESSIBLE | FLAG_DISABLE_RESTORE
| FLAG_HAS_SYS_UI_SCRIM;
public HintState(int id) {
@@ -34,7 +34,7 @@
}
@Override
- public int getTransitionDuration(Launcher launcher) {
+ public int getTransitionDuration(Context context) {
return 80;
}
@@ -48,16 +48,4 @@
// Treat the QSB as part of the hotseat so they move together.
return getHotseatScaleAndTranslation(launcher);
}
-
- @Override
- public void onStateTransitionEnd(Launcher launcher) {
- LauncherStateManager stateManager = launcher.getStateManager();
- Workspace workspace = launcher.getWorkspace();
- boolean willMoveScreens = workspace.getNextPage() != Workspace.DEFAULT_PAGE;
- stateManager.goToState(NORMAL, true, willMoveScreens ? null
- : launcher.getScrimView()::startDragHandleEducationAnim);
- if (willMoveScreens) {
- workspace.post(workspace::moveToDefaultScreen);
- }
- }
}
diff --git a/src/com/android/launcher3/states/SpringLoadedState.java b/src/com/android/launcher3/states/SpringLoadedState.java
index b2ff69a..f0e0557 100644
--- a/src/com/android/launcher3/states/SpringLoadedState.java
+++ b/src/com/android/launcher3/states/SpringLoadedState.java
@@ -15,13 +15,10 @@
*/
package com.android.launcher3.states;
-import static com.android.launcher3.states.RotationHelper.REQUEST_LOCK;
-
import android.content.Context;
import android.graphics.Rect;
import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.InstallShortcutReceiver;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.Workspace;
@@ -32,16 +29,17 @@
*/
public class SpringLoadedState extends LauncherState {
- private static final int STATE_FLAGS = FLAG_MULTI_PAGE |
- FLAG_DISABLE_ACCESSIBILITY | FLAG_DISABLE_RESTORE | FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED |
- FLAG_DISABLE_PAGE_CLIPPING | FLAG_PAGE_BACKGROUNDS | FLAG_HIDE_BACK_BUTTON;
+ private static final int STATE_FLAGS = FLAG_MULTI_PAGE
+ | FLAG_WORKSPACE_INACCESSIBLE | FLAG_DISABLE_RESTORE
+ | FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED | FLAG_WORKSPACE_HAS_BACKGROUNDS
+ | FLAG_HIDE_BACK_BUTTON;
public SpringLoadedState(int id) {
super(id, ContainerType.OVERVIEW, STATE_FLAGS);
}
@Override
- public int getTransitionDuration(Launcher launcher) {
+ public int getTransitionDuration(Context context) {
return 150;
}
@@ -88,28 +86,7 @@
}
@Override
- public void onStateEnabled(Launcher launcher) {
- Workspace ws = launcher.getWorkspace();
- ws.showPageIndicatorAtCurrentScroll();
- ws.getPageIndicator().setShouldAutoHide(false);
-
- // Prevent any Un/InstallShortcutReceivers from updating the db while we are
- // in spring loaded mode
- InstallShortcutReceiver.enableInstallQueue(InstallShortcutReceiver.FLAG_DRAG_AND_DROP);
- launcher.getRotationHelper().setCurrentStateRequest(REQUEST_LOCK);
- }
-
- @Override
public float getWorkspaceScrimAlpha(Launcher launcher) {
return 0.3f;
}
-
- @Override
- public void onStateDisabled(final Launcher launcher) {
- launcher.getWorkspace().getPageIndicator().setShouldAutoHide(true);
-
- // Re-enable any Un/InstallShortcutReceiver and now process any queued items
- InstallShortcutReceiver.disableAndFlushInstallQueue(
- InstallShortcutReceiver.FLAG_DRAG_AND_DROP, launcher);
- }
}
diff --git a/src/com/android/launcher3/testing/TestProtocol.java b/src/com/android/launcher3/testing/TestProtocol.java
index fba6269..0aab495 100644
--- a/src/com/android/launcher3/testing/TestProtocol.java
+++ b/src/com/android/launcher3/testing/TestProtocol.java
@@ -99,4 +99,6 @@
public static final String REQUEST_MOCK_SENSOR_ROTATION = "mock-sensor-rotation";
public static final String PERMANENT_DIAG_TAG = "TaplTarget";
+ public static final String PAUSE_NOT_DETECTED = "b/139891609";
+ public static final String OVERIEW_NOT_ALLAPPS = "b/156095088";
}
diff --git a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
index cbc5257..52e2ab8 100644
--- a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
+++ b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
@@ -31,6 +31,7 @@
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.os.SystemClock;
+import android.util.Log;
import android.view.HapticFeedbackConstants;
import android.view.MotionEvent;
@@ -43,6 +44,7 @@
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.states.StateAnimationConfig.AnimationFlags;
+import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
@@ -162,6 +164,9 @@
@Override
public final boolean onControllerTouchEvent(MotionEvent ev) {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.PAUSE_NOT_DETECTED, "onControllerTouchEvent");
+ }
return mDetector.onTouchEvent(ev);
}
@@ -194,6 +199,10 @@
mFromState = newFromState;
mToState = newToState;
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.OVERIEW_NOT_ALLAPPS, "reinitCurrentAnimation: "
+ + newToState.ordinal);
+ }
mStartProgress = 0;
mPassedOverviewAtomicThreshold = false;
diff --git a/src/com/android/launcher3/touch/BaseSwipeDetector.java b/src/com/android/launcher3/touch/BaseSwipeDetector.java
index 1276ece..01b33d8 100644
--- a/src/com/android/launcher3/touch/BaseSwipeDetector.java
+++ b/src/com/android/launcher3/touch/BaseSwipeDetector.java
@@ -26,6 +26,8 @@
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
+import com.android.launcher3.testing.TestProtocol;
+
import java.util.LinkedList;
import java.util.Queue;
@@ -173,6 +175,9 @@
if (mState != ScrollState.DRAGGING && shouldScrollStart(mDisplacement)) {
setState(ScrollState.DRAGGING);
}
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.PAUSE_NOT_DETECTED, "before report dragging");
+ }
if (mState == ScrollState.DRAGGING) {
reportDragging(ev);
}
diff --git a/src/com/android/launcher3/touch/HomeRotatedPageHandler.java b/src/com/android/launcher3/touch/HomeRotatedPageHandler.java
index 710b676..db5c659 100644
--- a/src/com/android/launcher3/touch/HomeRotatedPageHandler.java
+++ b/src/com/android/launcher3/touch/HomeRotatedPageHandler.java
@@ -18,6 +18,7 @@
import android.graphics.RectF;
import android.view.Surface;
+import android.widget.LinearLayout;
public class HomeRotatedPageHandler extends PortraitPagedViewHandler {
@Override
@@ -46,4 +47,9 @@
}
} // TODO (b/149609488) handle 180 case as well
}
+
+ @Override
+ public int getTaskMenuLayoutOrientation(LinearLayout taskMenuLayout) {
+ return taskMenuLayout.getOrientation();
+ }
}
diff --git a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
index dc50053..5007ca0 100644
--- a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
+++ b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
@@ -126,6 +126,11 @@
}
@Override
+ public int getClearAllScrollOffset(View view, boolean isRtl) {
+ return (isRtl ? view.getPaddingBottom() : - view.getPaddingTop()) / 2;
+ }
+
+ @Override
public int getSecondaryDimension(View view) {
return view.getWidth();
}
@@ -172,6 +177,11 @@
}
@Override
+ public int getRotation() {
+ return Surface.ROTATION_90;
+ }
+
+ @Override
public void offsetTaskRect(RectF rect, float value, int displayRotation, int launcherRotation) {
if (displayRotation == Surface.ROTATION_0) {
rect.offset(0, value);
@@ -241,7 +251,7 @@
}
@Override
- public int getTaskMenuLayoutOrientation() {
+ public int getTaskMenuLayoutOrientation(LinearLayout taskMenuLayout) {
return LinearLayout.HORIZONTAL;
}
diff --git a/src/com/android/launcher3/touch/PagedOrientationHandler.java b/src/com/android/launcher3/touch/PagedOrientationHandler.java
index cc15f99..cdfe6d5 100644
--- a/src/com/android/launcher3/touch/PagedOrientationHandler.java
+++ b/src/com/android/launcher3/touch/PagedOrientationHandler.java
@@ -62,6 +62,7 @@
float getPrimaryVelocity(VelocityTracker velocityTracker, int pointerId);
int getMeasuredSize(View view);
float getPrimarySize(RectF rect);
+ int getClearAllScrollOffset(View view, boolean isRtl);
int getSecondaryDimension(View view);
FloatProperty<View> getPrimaryViewTranslate();
FloatProperty<View> getSecondaryViewTranslate();
@@ -80,6 +81,7 @@
void setMaxScroll(AccessibilityEvent event, int maxScroll);
boolean getRecentsRtlSetting(Resources resources);
float getDegreesRotated();
+ int getRotation();
void offsetTaskRect(RectF rect, float value, int delta, int launcherRotation);
int getPrimaryValue(int x, int y);
int getSecondaryValue(int x, int y);
@@ -94,7 +96,7 @@
float getTaskMenuX(float x, View thumbnailView);
float getTaskMenuY(float y, View thumbnailView);
int getTaskMenuWidth(View view);
- int getTaskMenuLayoutOrientation();
+ int getTaskMenuLayoutOrientation(LinearLayout taskMenuLayout);
void setLayoutParamsForTaskMenuOptionItem(LinearLayout.LayoutParams lp);
/**
diff --git a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
index 7c30e29..25dc1f6 100644
--- a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
+++ b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
@@ -123,6 +123,11 @@
}
@Override
+ public int getClearAllScrollOffset(View view, boolean isRtl) {
+ return (isRtl ? view.getPaddingRight() : - view.getPaddingLeft()) / 2;
+ }
+
+ @Override
public int getSecondaryDimension(View view) {
return view.getHeight();
}
@@ -169,6 +174,11 @@
}
@Override
+ public int getRotation() {
+ return Surface.ROTATION_0;
+ }
+
+ @Override
public void offsetTaskRect(RectF rect, float value, int displayRotation, int launcherRotation) {
if (displayRotation == Surface.ROTATION_0) {
rect.offset(value, 0);
@@ -238,7 +248,7 @@
}
@Override
- public int getTaskMenuLayoutOrientation() {
+ public int getTaskMenuLayoutOrientation(LinearLayout taskMenuLayout) {
return LinearLayout.VERTICAL;
}
diff --git a/src/com/android/launcher3/touch/SeascapePagedViewHandler.java b/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
index 7beb7f7..dde2829 100644
--- a/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
+++ b/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
@@ -55,6 +55,11 @@
}
@Override
+ public int getRotation() {
+ return Surface.ROTATION_270;
+ }
+
+ @Override
public boolean isGoingUp(float displacement) {
return displacement < 0;
}
@@ -75,4 +80,15 @@
public float getTaskMenuY(float y, View thumbnailView) {
return y + thumbnailView.getMeasuredHeight();
}
+
+ @Override
+ public int getClearAllScrollOffset(View view, boolean isRtl) {
+ return (isRtl ? view.getPaddingTop() : - view.getPaddingBottom()) / 2;
+ }
+
+ @Override
+ public void setPrimaryAndResetSecondaryTranslate(View view, float translation) {
+ view.setTranslationX(0);
+ view.setTranslationY(-translation);
+ }
}
diff --git a/src/com/android/launcher3/touch/SingleAxisSwipeDetector.java b/src/com/android/launcher3/touch/SingleAxisSwipeDetector.java
index d725486..875eefb 100644
--- a/src/com/android/launcher3/touch/SingleAxisSwipeDetector.java
+++ b/src/com/android/launcher3/touch/SingleAxisSwipeDetector.java
@@ -17,6 +17,7 @@
import android.content.Context;
import android.graphics.PointF;
+import android.util.Log;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
@@ -24,6 +25,7 @@
import androidx.annotation.VisibleForTesting;
import com.android.launcher3.Utilities;
+import com.android.launcher3.testing.TestProtocol;
/**
* One dimensional scroll/drag/swipe gesture detector (either HORIZONTAL or VERTICAL).
@@ -103,6 +105,11 @@
super(config, isRtl);
mListener = l;
mDir = dir;
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.PAUSE_NOT_DETECTED, "SingleAxisSwipeDetector.ctor "
+ + l.getClass().getSimpleName()
+ + " @ " + android.util.Log.getStackTraceString(new Throwable()));
+ }
}
public void setDetectableScrollConditions(int scrollDirectionFlags, boolean ignoreSlop) {
@@ -154,6 +161,10 @@
@Override
protected void reportDraggingInternal(PointF displacement, MotionEvent event) {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.PAUSE_NOT_DETECTED, "SingleAxisSwipeDetector "
+ + mListener.getClass().getSimpleName());
+ }
mListener.onDrag(mDir.extractDirection(displacement),
mDir.extractOrthogonalDirection(displacement), event);
}
diff --git a/src/com/android/launcher3/touch/WorkspaceTouchListener.java b/src/com/android/launcher3/touch/WorkspaceTouchListener.java
index da631bd..e6de06d 100644
--- a/src/com/android/launcher3/touch/WorkspaceTouchListener.java
+++ b/src/com/android/launcher3/touch/WorkspaceTouchListener.java
@@ -167,8 +167,8 @@
@Override
public void onLongPress(MotionEvent event) {
- TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "Workspace.longPress");
if (mLongPressState == STATE_REQUESTED) {
+ TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "Workspace.longPress");
if (canHandleLongPress()) {
mLongPressState = STATE_PENDING_PARENT_INFORM;
mWorkspace.getParent().requestDisallowInterceptTouchEvent(true);
diff --git a/src/com/android/launcher3/util/DefaultDisplay.java b/src/com/android/launcher3/util/DefaultDisplay.java
index f18e411..fabdb4e 100644
--- a/src/com/android/launcher3/util/DefaultDisplay.java
+++ b/src/com/android/launcher3/util/DefaultDisplay.java
@@ -15,6 +15,8 @@
*/
package com.android.launcher3.util;
+import static android.view.Display.DEFAULT_DISPLAY;
+
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import android.content.Context;
@@ -26,7 +28,6 @@
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Display;
-import android.view.WindowManager;
import androidx.annotation.VisibleForTesting;
@@ -46,6 +47,8 @@
public static final int CHANGE_ROTATION = 1 << 1;
public static final int CHANGE_FRAME_DELAY = 1 << 2;
+ public static final int CHANGE_ALL = CHANGE_SIZE | CHANGE_ROTATION | CHANGE_FRAME_DELAY;
+
private final Context mContext;
private final int mId;
private final ArrayList<DisplayInfoChangeListener> mListeners = new ArrayList<>();
@@ -142,7 +145,7 @@
}
private Info(Context context) {
- this(context.getSystemService(WindowManager.class).getDefaultDisplay());
+ this(context.getSystemService(DisplayManager.class).getDisplay(DEFAULT_DISPLAY));
}
public Info(Display display) {
diff --git a/src/com/android/launcher3/util/LogConfig.java b/src/com/android/launcher3/util/LogConfig.java
index b54074e..528a6e9 100644
--- a/src/com/android/launcher3/util/LogConfig.java
+++ b/src/com/android/launcher3/util/LogConfig.java
@@ -12,6 +12,8 @@
public class LogConfig {
// These are list of strings that can be used to replace TAGNAME.
+ public static final String STATSLOG = "StatsLog";
+
/**
* After this tag is turned on, whenever there is n user event, debug information is
* printed out to logcat.
diff --git a/src/com/android/launcher3/util/OnboardingPrefs.java b/src/com/android/launcher3/util/OnboardingPrefs.java
index baa1eee..1620289 100644
--- a/src/com/android/launcher3/util/OnboardingPrefs.java
+++ b/src/com/android/launcher3/util/OnboardingPrefs.java
@@ -21,7 +21,6 @@
import androidx.annotation.StringDef;
import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherStateManager;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -71,13 +70,10 @@
protected final T mLauncher;
protected final SharedPreferences mSharedPrefs;
- protected final LauncherStateManager mStateManager;
- public OnboardingPrefs(T launcher, SharedPreferences sharedPrefs,
- LauncherStateManager stateManager) {
+ public OnboardingPrefs(T launcher, SharedPreferences sharedPrefs) {
mLauncher = launcher;
mSharedPrefs = sharedPrefs;
- mStateManager = stateManager;
}
/** @return The number of times we have seen the given event. */
diff --git a/src/com/android/launcher3/views/ClipIconView.java b/src/com/android/launcher3/views/ClipIconView.java
index 478141a..1a8e11b 100644
--- a/src/com/android/launcher3/views/ClipIconView.java
+++ b/src/com/android/launcher3/views/ClipIconView.java
@@ -101,7 +101,6 @@
private @Nullable Drawable mForeground;
private @Nullable Drawable mBackground;
- private boolean mIsVerticalBarLayout = false;
private boolean mIsAdaptiveIcon = false;
private ValueAnimator mRevealAnimator;
@@ -145,7 +144,8 @@
}
void update(RectF rect, float progress, float shapeProgressStart, float cornerRadius,
- boolean isOpening, float scale, float minSize, LayoutParams parentLp) {
+ boolean isOpening, float scale, float minSize, LayoutParams parentLp,
+ boolean isVerticalBarLayout) {
DeviceProfile dp = mLauncher.getDeviceProfile();
float dX = mIsRtl
? rect.left - (dp.widthPx - parentLp.getMarginStart() - parentLp.width)
@@ -158,7 +158,7 @@
Math.max(shapeProgressStart, progress), shapeProgressStart, 1f, 0, toMax,
LINEAR), 0, 1);
- if (mIsVerticalBarLayout) {
+ if (isVerticalBarLayout) {
mOutline.right = (int) (rect.width() / scale);
} else {
mOutline.bottom = (int) (rect.height() / scale);
@@ -183,16 +183,16 @@
mRevealAnimator.setCurrentFraction(shapeRevealProgress);
}
- float drawableScale = (mIsVerticalBarLayout ? mOutline.width() : mOutline.height())
+ float drawableScale = (isVerticalBarLayout ? mOutline.width() : mOutline.height())
/ minSize;
- setBackgroundDrawableBounds(drawableScale);
+ setBackgroundDrawableBounds(drawableScale, isVerticalBarLayout);
if (isOpening) {
// Center align foreground
int height = mFinalDrawableBounds.height();
int width = mFinalDrawableBounds.width();
- int diffY = mIsVerticalBarLayout ? 0
+ int diffY = isVerticalBarLayout ? 0
: (int) (((height * drawableScale) - height) / 2);
- int diffX = mIsVerticalBarLayout ? (int) (((width * drawableScale) - width) / 2)
+ int diffX = isVerticalBarLayout ? (int) (((width * drawableScale) - width) / 2)
: 0;
sTmpRect.set(mFinalDrawableBounds);
sTmpRect.offset(diffX, diffY);
@@ -210,11 +210,11 @@
invalidateOutline();
}
- private void setBackgroundDrawableBounds(float scale) {
+ private void setBackgroundDrawableBounds(float scale, boolean isVerticalBarLayout) {
sTmpRect.set(mFinalDrawableBounds);
Utilities.scaleRectAboutCenter(sTmpRect, scale);
// Since the drawable is at the top of the view, we need to offset to keep it centered.
- if (mIsVerticalBarLayout) {
+ if (isVerticalBarLayout) {
sTmpRect.offsetTo((int) (mFinalDrawableBounds.left * scale), sTmpRect.top);
} else {
sTmpRect.offsetTo(sTmpRect.left, (int) (mFinalDrawableBounds.top * scale));
@@ -228,7 +228,8 @@
}
}
- void setIcon(@Nullable Drawable drawable, int iconOffset, LayoutParams lp, boolean isOpening) {
+ void setIcon(@Nullable Drawable drawable, int iconOffset, LayoutParams lp, boolean isOpening,
+ boolean isVerticalBarLayout) {
mIsAdaptiveIcon = drawable instanceof AdaptiveIconDrawable;
if (mIsAdaptiveIcon) {
boolean isFolderIcon = drawable instanceof FolderAdaptiveIcon;
@@ -264,7 +265,7 @@
}
float aspectRatio = mLauncher.getDeviceProfile().aspectRatio;
- if (mIsVerticalBarLayout) {
+ if (isVerticalBarLayout) {
lp.width = (int) Math.max(lp.width, lp.height * aspectRatio);
} else {
lp.height = (int) Math.max(lp.height, lp.width * aspectRatio);
@@ -285,7 +286,7 @@
bgDrawableStartScale = scale;
mOutline.set(0, 0, lp.width, lp.height);
}
- setBackgroundDrawableBounds(bgDrawableStartScale);
+ setBackgroundDrawableBounds(bgDrawableStartScale, isVerticalBarLayout);
mEndRevealRect.set(0, 0, lp.width, lp.height);
setOutlineProvider(new ViewOutlineProvider() {
@Override
diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java
index 6e21512..bd12e06 100644
--- a/src/com/android/launcher3/views/FloatingIconView.java
+++ b/src/com/android/launcher3/views/FloatingIconView.java
@@ -161,7 +161,7 @@
float scale = Math.max(1f, Math.min(scaleX, scaleY));
mClipIconView.update(rect, progress, shapeProgressStart, cornerRadius, isOpening, scale,
- minSize, lp);
+ minSize, lp, mIsVerticalBarLayout);
setPivotX(0);
setPivotY(0);
@@ -335,7 +335,7 @@
final InsettableFrameLayout.LayoutParams lp =
(InsettableFrameLayout.LayoutParams) getLayoutParams();
mBadge = badge;
- mClipIconView.setIcon(drawable, iconOffset, lp, mIsOpening);
+ mClipIconView.setIcon(drawable, iconOffset, lp, mIsOpening, mIsVerticalBarLayout);
if (drawable instanceof AdaptiveIconDrawable) {
final int originalHeight = lp.height;
final int originalWidth = lp.width;
diff --git a/src/com/android/launcher3/views/ScrimView.java b/src/com/android/launcher3/views/ScrimView.java
index da874cf..a2c7d14 100644
--- a/src/com/android/launcher3/views/ScrimView.java
+++ b/src/com/android/launcher3/views/ScrimView.java
@@ -62,10 +62,10 @@
import com.android.launcher3.Insettable;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
-import com.android.launcher3.LauncherStateManager;
-import com.android.launcher3.LauncherStateManager.StateListener;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
+import com.android.launcher3.statemanager.StateManager;
+import com.android.launcher3.statemanager.StateManager.StateListener;
import com.android.launcher3.uioverrides.WallpaperColorInfo;
import com.android.launcher3.uioverrides.WallpaperColorInfo.OnChangeListener;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
@@ -116,7 +116,8 @@
private final AccessibilityManager mAM;
protected final int mEndScrim;
- private final StateListener mAccessibilityLauncherStateListener = new StateListener() {
+ private final StateListener<LauncherState> mAccessibilityLauncherStateListener =
+ new StateListener<LauncherState>() {
@Override
public void onStateTransitionComplete(LauncherState finalState) {
setImportantForAccessibility(finalState == ALL_APPS
@@ -383,7 +384,7 @@
@Override
public void onAccessibilityStateChanged(boolean enabled) {
- LauncherStateManager stateManager = mLauncher.getStateManager();
+ StateManager<LauncherState> stateManager = mLauncher.getStateManager();
stateManager.removeStateListener(mAccessibilityLauncherStateListener);
if (enabled) {
diff --git a/src/com/android/launcher3/views/Snackbar.java b/src/com/android/launcher3/views/Snackbar.java
index dc0e2e0..513ce59 100644
--- a/src/com/android/launcher3/views/Snackbar.java
+++ b/src/com/android/launcher3/views/Snackbar.java
@@ -29,7 +29,7 @@
import android.widget.TextView;
import com.android.launcher3.AbstractFloatingView;
-import com.android.launcher3.Launcher;
+import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.R;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.compat.AccessibilityManagerCompat;
@@ -44,7 +44,7 @@
private static final long HIDE_DURATION_MS = 180;
private static final int TIMEOUT_DURATION_MS = 4000;
- private final Launcher mLauncher;
+ private final BaseDraggingActivity mActivity;
private Runnable mOnDismissed;
public Snackbar(Context context, AttributeSet attrs) {
@@ -53,25 +53,25 @@
public Snackbar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
- mLauncher = Launcher.getLauncher(context);
+ mActivity = BaseDraggingActivity.fromContext(context);
inflate(context, R.layout.snackbar, this);
}
- public static void show(Launcher launcher, int labelStringResId, int actionStringResId,
- Runnable onDismissed, Runnable onActionClicked) {
- closeOpenViews(launcher, true, TYPE_SNACKBAR);
- Snackbar snackbar = new Snackbar(launcher, null);
+ public static void show(BaseDraggingActivity activity, int labelStringResId,
+ int actionStringResId, Runnable onDismissed, Runnable onActionClicked) {
+ closeOpenViews(activity, true, TYPE_SNACKBAR);
+ Snackbar snackbar = new Snackbar(activity, null);
// Set some properties here since inflated xml only contains the children.
snackbar.setOrientation(HORIZONTAL);
snackbar.setGravity(Gravity.CENTER_VERTICAL);
- Resources res = launcher.getResources();
+ Resources res = activity.getResources();
snackbar.setElevation(res.getDimension(R.dimen.snackbar_elevation));
int padding = res.getDimensionPixelSize(R.dimen.snackbar_padding);
snackbar.setPadding(padding, padding, padding, padding);
snackbar.setBackgroundResource(R.drawable.round_rect_primary);
snackbar.mIsOpen = true;
- DragLayer dragLayer = launcher.getDragLayer();
+ BaseDragLayer dragLayer = activity.getDragLayer();
dragLayer.addView(snackbar);
DragLayer.LayoutParams params = (DragLayer.LayoutParams) snackbar.getLayoutParams();
@@ -80,7 +80,7 @@
int maxMarginLeftRight = res.getDimensionPixelSize(R.dimen.snackbar_max_margin_left_right);
int minMarginLeftRight = res.getDimensionPixelSize(R.dimen.snackbar_min_margin_left_right);
int marginBottom = res.getDimensionPixelSize(R.dimen.snackbar_margin_bottom);
- Rect insets = launcher.getDeviceProfile().getInsets();
+ Rect insets = activity.getDeviceProfile().getInsets();
int maxWidth = dragLayer.getWidth() - minMarginLeftRight * 2 - insets.left - insets.right;
int minWidth = dragLayer.getWidth() - maxMarginLeftRight * 2 - insets.left - insets.right;
params.width = minWidth;
@@ -135,7 +135,7 @@
.setDuration(SHOW_DURATION_MS)
.setInterpolator(Interpolators.ACCEL_DEACCEL)
.start();
- int timeout = AccessibilityManagerCompat.getRecommendedTimeoutMillis(launcher,
+ int timeout = AccessibilityManagerCompat.getRecommendedTimeoutMillis(activity,
TIMEOUT_DURATION_MS, FLAG_CONTENT_TEXT | FLAG_CONTENT_CONTROLS);
snackbar.postDelayed(() -> snackbar.close(true), timeout);
}
@@ -160,7 +160,7 @@
}
private void onClosed() {
- mLauncher.getDragLayer().removeView(this);
+ mActivity.getDragLayer().removeView(this);
if (mOnDismissed != null) {
mOnDismissed.run();
}
@@ -179,7 +179,7 @@
@Override
public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
- DragLayer dl = mLauncher.getDragLayer();
+ BaseDragLayer dl = mActivity.getDragLayer();
if (!dl.isEventOverView(this, ev)) {
close(true);
}
diff --git a/src/com/android/launcher3/views/WorkEduView.java b/src/com/android/launcher3/views/WorkEduView.java
index 552f662..d35a38f 100644
--- a/src/com/android/launcher3/views/WorkEduView.java
+++ b/src/com/android/launcher3/views/WorkEduView.java
@@ -32,18 +32,19 @@
import com.android.launcher3.Insettable;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
-import com.android.launcher3.LauncherStateManager;
import com.android.launcher3.R;
import com.android.launcher3.allapps.AllAppsContainerView;
import com.android.launcher3.allapps.AllAppsPagedView;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.Interpolators;
+import com.android.launcher3.statemanager.StateManager.StateListener;
import com.android.launcher3.userevent.nano.LauncherLogProto;
/**
* On boarding flow for users right after setting up work profile
*/
-public class WorkEduView extends AbstractSlideInView implements Insettable {
+public class WorkEduView extends AbstractSlideInView
+ implements Insettable, StateListener<LauncherState> {
private static final int DEFAULT_CLOSE_DURATION = 200;
public static final String KEY_WORK_EDU_STEP = "showed_work_profile_edu";
@@ -82,6 +83,12 @@
}
@Override
+ protected void onCloseComplete() {
+ super.onCloseComplete();
+ mLauncher.getStateManager().removeStateListener(this);
+ }
+
+ @Override
public void logActionCommand(int command) {
// Since this is on-boarding popup, it is not a user controlled action.
}
@@ -150,6 +157,7 @@
private void show() {
attachToContainer();
animateOpen();
+ mLauncher.getStateManager().addStateListener(this);
}
@Override
@@ -177,8 +185,8 @@
/**
* Checks if user has not seen onboarding UI yet and shows it when user navigates to all apps
*/
- public static LauncherStateManager.StateListener showEduFlowIfNeeded(Launcher launcher,
- @Nullable LauncherStateManager.StateListener oldListener) {
+ public static StateListener<LauncherState> showEduFlowIfNeeded(Launcher launcher,
+ @Nullable StateListener<LauncherState> oldListener) {
if (oldListener != null) {
launcher.getStateManager().removeStateListener(oldListener);
}
@@ -187,7 +195,7 @@
return null;
}
- LauncherStateManager.StateListener listener = new LauncherStateManager.StateListener() {
+ StateListener<LauncherState> listener = new StateListener<LauncherState>() {
@Override
public void onStateTransitionComplete(LauncherState finalState) {
if (finalState != LauncherState.ALL_APPS) return;
@@ -222,4 +230,9 @@
private static boolean hasSeenLegacyEdu(Launcher launcher) {
return launcher.getSharedPrefs().getBoolean(KEY_LEGACY_WORK_EDU_SEEN, false);
}
+
+ @Override
+ public void onStateTransitionComplete(LauncherState finalState) {
+ close(false);
+ }
}
diff --git a/src/com/android/launcher3/widget/NavigableAppWidgetHostView.java b/src/com/android/launcher3/widget/NavigableAppWidgetHostView.java
index a4e7daa..ed42bc4 100644
--- a/src/com/android/launcher3/widget/NavigableAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/NavigableAppWidgetHostView.java
@@ -218,7 +218,7 @@
}
@Override
- public void getVisualDragBounds(Rect bounds) {
+ public void getWorkspaceVisualDragBounds(Rect bounds) {
int width = (int) (getMeasuredWidth() * mScaleToFit);
int height = (int) (getMeasuredHeight() * mScaleToFit);
diff --git a/src/com/android/launcher3/widget/WidgetCell.java b/src/com/android/launcher3/widget/WidgetCell.java
index 4a0b4ef..bef91d2 100644
--- a/src/com/android/launcher3/widget/WidgetCell.java
+++ b/src/com/android/launcher3/widget/WidgetCell.java
@@ -55,7 +55,7 @@
private static final int FADE_IN_DURATION_MS = 90;
/** Widget cell width is calculated by multiplying this factor to grid cell width. */
- private static final float WIDTH_SCALE = 2.6f;
+ private static final float WIDTH_SCALE = 3f;
/** Widget preview width is calculated by multiplying this factor to the widget cell width. */
private static final float PREVIEW_SCALE = 0.8f;
@@ -104,7 +104,7 @@
}
private void setContainerWidth() {
- mCellSize = (int) (mDeviceProfile.cellWidthPx * WIDTH_SCALE);
+ mCellSize = (int) (mDeviceProfile.allAppsIconSizePx * WIDTH_SCALE);
mPresetPreviewSize = (int) (mCellSize * PREVIEW_SCALE);
}
diff --git a/src_plugins/com/android/systemui/plugins/AllAppsSearchPlugin.java b/src_plugins/com/android/systemui/plugins/AllAppsSearchPlugin.java
index b865a20..d458fc4 100644
--- a/src_plugins/com/android/systemui/plugins/AllAppsSearchPlugin.java
+++ b/src_plugins/com/android/systemui/plugins/AllAppsSearchPlugin.java
@@ -16,9 +16,9 @@
package com.android.systemui.plugins;
+import android.app.Activity;
import android.view.ViewGroup;
import android.widget.EditText;
-
import com.android.systemui.plugins.annotations.ProvidesInterface;
/**
@@ -27,8 +27,9 @@
@ProvidesInterface(action = AllAppsSearchPlugin.ACTION, version = AllAppsSearchPlugin.VERSION)
public interface AllAppsSearchPlugin extends Plugin {
String ACTION = "com.android.systemui.action.PLUGIN_ALL_APPS_SEARCH_ACTIONS";
- int VERSION = 1;
+ int VERSION = 2;
- void setup(ViewGroup parent);
+ void setup(ViewGroup parent, Activity activity);
void setEditText(EditText editText);
+ void setProgress(float progress);
}
diff --git a/src_plugins/com/android/systemui/plugins/OWNERS b/src_plugins/com/android/systemui/plugins/OWNERS
new file mode 100644
index 0000000..0514999
--- /dev/null
+++ b/src_plugins/com/android/systemui/plugins/OWNERS
@@ -0,0 +1,4 @@
+# When changing interface for this plugin OR when increasing version code, please add Alex
+# Only add other owners if Alex is not available
+per-file AllAppsSearchPlugin.java, globs = set noparent
+per-file AllAppsSearchPlugin.java = alexmang@google.com, hyunyoungs@google.com, sunnygoyal@google.com, twickham@google.com
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/states/AllAppsState.java b/src_ui_overrides/com/android/launcher3/uioverrides/states/AllAppsState.java
index 313ea05..ec3f93f 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/states/AllAppsState.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/states/AllAppsState.java
@@ -16,9 +16,9 @@
package com.android.launcher3.uioverrides.states;
import static com.android.launcher3.anim.Interpolators.DEACCEL_2;
-import static com.android.launcher3.util.OnboardingPrefs.HOME_BOUNCE_SEEN;
-import com.android.launcher3.AbstractFloatingView;
+import android.content.Context;
+
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.R;
@@ -31,7 +31,7 @@
private static final float PARALLAX_COEFFICIENT = .125f;
- private static final int STATE_FLAGS = FLAG_DISABLE_ACCESSIBILITY;
+ private static final int STATE_FLAGS = FLAG_WORKSPACE_INACCESSIBLE;
private static final PageAlphaProvider PAGE_ALPHA_PROVIDER = new PageAlphaProvider(DEACCEL_2) {
@Override
@@ -45,21 +45,11 @@
}
@Override
- public int getTransitionDuration(Launcher context) {
+ public int getTransitionDuration(Context context) {
return 320;
}
@Override
- public void onStateEnabled(Launcher launcher) {
- if (!launcher.getSharedPrefs().getBoolean(HOME_BOUNCE_SEEN, false)) {
- launcher.getSharedPrefs().edit().putBoolean(HOME_BOUNCE_SEEN, true).apply();
- }
-
- AbstractFloatingView.closeAllOpenViews(launcher);
- dispatchWindowStateChanged(launcher);
- }
-
- @Override
public String getDescription(Launcher launcher) {
return launcher.getString(R.string.all_apps_button_label);
}
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/states/OverviewState.java b/src_ui_overrides/com/android/launcher3/uioverrides/states/OverviewState.java
index 507ff59..7a6332c 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/states/OverviewState.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/states/OverviewState.java
@@ -15,7 +15,8 @@
*/
package com.android.launcher3.uioverrides.states;
-import com.android.launcher3.Launcher;
+import android.content.Context;
+
import com.android.launcher3.LauncherState;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
@@ -29,7 +30,7 @@
}
@Override
- public int getTransitionDuration(Launcher context) {
+ public int getTransitionDuration(Context context) {
return 250;
}
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 160daef..7cce044 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -37,6 +37,8 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.StrictMode;
+import android.os.UserHandle;
+import android.os.UserManager;
import android.util.Log;
import androidx.test.InstrumentationRegistry;
@@ -49,11 +51,11 @@
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.LauncherState;
-import com.android.launcher3.LauncherStateManager;
import com.android.launcher3.Utilities;
import com.android.launcher3.common.WidgetUtils;
import com.android.launcher3.model.AppLaunchTracker;
import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.tapl.LauncherInstrumentation;
import com.android.launcher3.tapl.LauncherInstrumentation.ContainerType;
import com.android.launcher3.tapl.TestHelpers;
@@ -276,6 +278,15 @@
mTargetContext = InstrumentationRegistry.getTargetContext();
mTargetPackage = mTargetContext.getPackageName();
mLauncherPid = mLauncher.getPid();
+
+ UserManager userManager = mTargetContext.getSystemService(UserManager.class);
+ if (userManager != null) {
+ for (UserHandle userHandle : userManager.getUserProfiles()) {
+ if (!userHandle.isSystem()) {
+ mDevice.executeShellCommand("pm remove-user " + userHandle.getIdentifier());
+ }
+ }
+ }
}
@After
@@ -297,6 +308,7 @@
clearPackageData(mDevice.getLauncherPackageName());
mLauncher.enableDebugTracing();
mLauncherPid = mLauncher.getPid();
+ mLauncher.waitForLauncherInitialized();
}
}
@@ -525,7 +537,7 @@
private static void checkLauncherIntegrity(
Launcher launcher, ContainerType expectedContainerType) {
if (launcher != null) {
- final LauncherStateManager stateManager = launcher.getStateManager();
+ final StateManager<LauncherState> stateManager = launcher.getStateManager();
final LauncherState stableState = stateManager.getCurrentStableState();
assertTrue("Stable state != state: " + stableState.getClass().getSimpleName() + ", "
diff --git a/tests/tapl/com/android/launcher3/tapl/AddToHomeScreenPrompt.java b/tests/tapl/com/android/launcher3/tapl/AddToHomeScreenPrompt.java
index 5daac39..e1fde3b 100644
--- a/tests/tapl/com/android/launcher3/tapl/AddToHomeScreenPrompt.java
+++ b/tests/tapl/com/android/launcher3/tapl/AddToHomeScreenPrompt.java
@@ -19,6 +19,7 @@
import static java.util.regex.Pattern.CASE_INSENSITIVE;
import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.BySelector;
import androidx.test.uiautomator.UiObject2;
import com.android.launcher3.testing.TestProtocol;
@@ -33,11 +34,14 @@
AddToHomeScreenPrompt(LauncherInstrumentation launcher) {
mLauncher = launcher;
- mWidgetCell = launcher.waitForLauncherObject(By.clazz(
- "com.android.launcher3.widget.WidgetCell"));
+ mWidgetCell = launcher.waitForLauncherObject(getSelector());
mLauncher.assertNotNull("Can't find widget cell object", mWidgetCell);
}
+ private static BySelector getSelector() {
+ return By.clazz("com.android.launcher3.widget.WidgetCell");
+ }
+
public void addAutomatically() {
try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
if (mLauncher.getNavigationModel()
@@ -53,6 +57,7 @@
mLauncher.waitForObjectInContainer(
mWidgetCell.getParent().getParent().getParent().getParent(),
By.text(ADD_AUTOMATICALLY)).click();
+ mLauncher.waitUntilLauncherObjectGone(getSelector());
}
}
}
diff --git a/tests/tapl/com/android/launcher3/tapl/Background.java b/tests/tapl/com/android/launcher3/tapl/Background.java
index 80b8e89..94ab780 100644
--- a/tests/tapl/com/android/launcher3/tapl/Background.java
+++ b/tests/tapl/com/android/launcher3/tapl/Background.java
@@ -71,7 +71,6 @@
}
protected void goToOverviewUnchecked() {
- final boolean launcherWasVisible = mLauncher.isLauncherVisible();
switch (mLauncher.getNavigationModel()) {
case ZERO_BUTTON: {
final int centerX = mLauncher.getDevice().getDisplayWidth() / 2;
@@ -138,11 +137,6 @@
break;
}
expectSwitchToOverviewEvents();
-
- if (!launcherWasVisible) {
- mLauncher.expectEvent(
- TestProtocol.SEQUENCE_MAIN, LauncherInstrumentation.EVENT_START_ACTIVITY);
- }
}
private void expectSwitchToOverviewEvents() {
@@ -192,11 +186,6 @@
}
final boolean isZeroButton = mLauncher.getNavigationModel()
== LauncherInstrumentation.NavigationModel.ZERO_BUTTON;
- if (!launcherWasVisible) {
- mLauncher.expectEvent(
- TestProtocol.SEQUENCE_MAIN,
- LauncherInstrumentation.EVENT_START_ACTIVITY);
- }
mLauncher.swipeToState(startX, startY, endX, endY, 20, expectedState,
launcherWasVisible && isZeroButton
? LauncherInstrumentation.GestureScope.INSIDE_TO_OUTSIDE
@@ -208,11 +197,6 @@
// Double press the recents button.
UiObject2 recentsButton = mLauncher.waitForSystemUiObject("recent_apps");
mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, SQUARE_BUTTON_EVENT);
- if (!launcherWasVisible) {
- mLauncher.expectEvent(
- TestProtocol.SEQUENCE_MAIN,
- LauncherInstrumentation.EVENT_START_ACTIVITY);
- }
mLauncher.runToState(() -> recentsButton.click(), OVERVIEW_STATE_ORDINAL);
mLauncher.getOverview();
mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, SQUARE_BUTTON_EVENT);
@@ -220,8 +204,6 @@
break;
}
mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, TASK_START_EVENT);
- mLauncher.expectEvent(
- TestProtocol.SEQUENCE_MAIN, LauncherInstrumentation.EVENT_STOP_ACTIVITY);
}
protected String getSwipeHeightRequestName() {
diff --git a/tests/tapl/com/android/launcher3/tapl/Launchable.java b/tests/tapl/com/android/launcher3/tapl/Launchable.java
index df7436c..13ecfb8 100644
--- a/tests/tapl/com/android/launcher3/tapl/Launchable.java
+++ b/tests/tapl/com/android/launcher3/tapl/Launchable.java
@@ -25,8 +25,6 @@
import androidx.test.uiautomator.UiObject2;
import androidx.test.uiautomator.Until;
-import com.android.launcher3.testing.TestProtocol;
-
/**
* Ancestor for AppIcon and AppMenuItem.
*/
@@ -64,8 +62,6 @@
event -> event.getEventType() == TYPE_WINDOW_STATE_CHANGED,
() -> "Launching an app didn't open a new window: " + mObject.getText());
expectActivityStartEvents();
- mLauncher.expectEvent(
- TestProtocol.SEQUENCE_MAIN, LauncherInstrumentation.EVENT_STOP_ACTIVITY);
mLauncher.assertTrue(
"App didn't start: " + selector,
@@ -76,7 +72,8 @@
/**
* Drags an object to the center of homescreen.
- * @param startsActivity whether it's expected to start an activity.
+ *
+ * @param startsActivity whether it's expected to start an activity.
* @param isWidgetShortcut whether we drag a widget shortcut
*/
public void dragToWorkspace(boolean startsActivity, boolean isWidgetShortcut) {
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index d46845f..6e9c5a0 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -97,8 +97,6 @@
private static final Pattern EVENT_TOUCH_UP = getTouchEventPattern("ACTION_UP");
private static final Pattern EVENT_TOUCH_CANCEL = getTouchEventPattern("ACTION_CANCEL");
private static final Pattern EVENT_PILFER_POINTERS = Pattern.compile("pilferPointers");
- static final Pattern EVENT_START_ACTIVITY = Pattern.compile("Activity\\.onStart");
- static final Pattern EVENT_STOP_ACTIVITY = Pattern.compile("Activity\\.onStop");
static final Pattern EVENT_START = Pattern.compile("start:");
static final Pattern EVENT_TOUCH_DOWN_TIS = getTouchEventPatternTIS("ACTION_DOWN");
@@ -170,7 +168,6 @@
private static boolean sCheckingEvents;
private boolean mCheckEventsForSuccessfulGestures = false;
- private int mExpectedPid;
private Runnable mOnLauncherCrashed;
private static Pattern getTouchEventPattern(String prefix, String action) {
@@ -362,33 +359,12 @@
return null;
}
- private String getAnomalyMessage() {
- if (mExpectedPid != 0 && mExpectedPid != getPid()) {
- mExpectedPid = 0;
- if (mOnLauncherCrashed != null) mOnLauncherCrashed.run();
- return "Launcher crashed";
- }
-
+ public void checkForAnomaly() {
final String systemAnomalyMessage = getSystemAnomalyMessage();
if (systemAnomalyMessage != null) {
- return "http://go/tapl : Tests are broken by a non-Launcher system error: "
- + systemAnomalyMessage;
- }
-
- return null;
- }
-
- public void checkForAnomaly() {
- final String anomalyMessage = getAnomalyMessage();
- if (anomalyMessage != null) {
- if (sCheckingEvents) {
- sCheckingEvents = false;
- sEventChecker.finishNoWait();
- }
- log("Hierarchy dump for: " + anomalyMessage);
- dumpViewHierarchy();
-
- Assert.fail(formatSystemHealthMessage(anomalyMessage));
+ Assert.fail(formatSystemHealthMessage(closeEvents(
+ "http://go/tapl : Tests are broken by a non-Launcher system error: "
+ + systemAnomalyMessage, false)));
}
}
@@ -448,23 +424,29 @@
return message;
}
- private void fail(String message) {
- checkForAnomaly();
-
- message = "http://go/tapl : " + getContextDescription() + message
- + " (visible state: " + getVisibleStateMessage() + ")";
+ private String closeEvents(String message, boolean checkEvents) {
+ if (sCheckingEvents) {
+ sCheckingEvents = false;
+ if (checkEvents) {
+ final String eventMismatch = sEventChecker.verify(0, false);
+ if (eventMismatch != null) {
+ message = message + ", having produced " + eventMismatch;
+ }
+ } else {
+ sEventChecker.finishNoWait();
+ }
+ }
log("Hierarchy dump for: " + message);
dumpViewHierarchy();
- if (sCheckingEvents) {
- sCheckingEvents = false;
- final String eventMismatch = sEventChecker.verify(0);
- if (eventMismatch != null) {
- message = message + ", having produced " + eventMismatch;
- }
- }
+ return message;
+ }
- Assert.fail(formatSystemHealthMessage(message));
+ private void fail(String message) {
+ checkForAnomaly();
+ Assert.fail(formatSystemHealthMessage(closeEvents(
+ "http://go/tapl : " + getContextDescription() + message
+ + " (visible state: " + getVisibleStateMessage() + ")", true)));
}
private String getContextDescription() {
@@ -560,32 +542,32 @@
if (mDevice.isNaturalOrientation()) {
waitForLauncherObject(APPS_RES_ID);
} else {
- waitUntilGone(APPS_RES_ID);
+ waitUntilLauncherObjectGone(APPS_RES_ID);
}
- waitUntilGone(OVERVIEW_RES_ID);
- waitUntilGone(WIDGETS_RES_ID);
+ waitUntilLauncherObjectGone(OVERVIEW_RES_ID);
+ waitUntilLauncherObjectGone(WIDGETS_RES_ID);
return waitForLauncherObject(WORKSPACE_RES_ID);
}
case WIDGETS: {
- waitUntilGone(WORKSPACE_RES_ID);
- waitUntilGone(APPS_RES_ID);
- waitUntilGone(OVERVIEW_RES_ID);
+ waitUntilLauncherObjectGone(WORKSPACE_RES_ID);
+ waitUntilLauncherObjectGone(APPS_RES_ID);
+ waitUntilLauncherObjectGone(OVERVIEW_RES_ID);
return waitForLauncherObject(WIDGETS_RES_ID);
}
case ALL_APPS: {
- waitUntilGone(WORKSPACE_RES_ID);
- waitUntilGone(OVERVIEW_RES_ID);
- waitUntilGone(WIDGETS_RES_ID);
+ waitUntilLauncherObjectGone(WORKSPACE_RES_ID);
+ waitUntilLauncherObjectGone(OVERVIEW_RES_ID);
+ waitUntilLauncherObjectGone(WIDGETS_RES_ID);
return waitForLauncherObject(APPS_RES_ID);
}
case OVERVIEW: {
if (hasAllAppsInOverview()) {
waitForLauncherObject(APPS_RES_ID);
} else {
- waitUntilGone(APPS_RES_ID);
+ waitUntilLauncherObjectGone(APPS_RES_ID);
}
- waitUntilGone(WORKSPACE_RES_ID);
- waitUntilGone(WIDGETS_RES_ID);
+ waitUntilLauncherObjectGone(WORKSPACE_RES_ID);
+ waitUntilLauncherObjectGone(WIDGETS_RES_ID);
return waitForLauncherObject(OVERVIEW_RES_ID);
}
@@ -593,10 +575,10 @@
return waitForFallbackLauncherObject(OVERVIEW_RES_ID);
}
case BACKGROUND: {
- waitUntilGone(WORKSPACE_RES_ID);
- waitUntilGone(APPS_RES_ID);
- waitUntilGone(OVERVIEW_RES_ID);
- waitUntilGone(WIDGETS_RES_ID);
+ waitUntilLauncherObjectGone(WORKSPACE_RES_ID);
+ waitUntilLauncherObjectGone(APPS_RES_ID);
+ waitUntilLauncherObjectGone(OVERVIEW_RES_ID);
+ waitUntilLauncherObjectGone(WIDGETS_RES_ID);
return null;
}
default:
@@ -640,14 +622,19 @@
* @return the Workspace object.
*/
public Workspace pressHome() {
+ mInstrumentation.getUiAutomation().setOnAccessibilityEventListener(
+ e -> Log.d("b/155926212", e.toString()));
try (LauncherInstrumentation.Closable e = eventsCheck()) {
+ waitForLauncherInitialized();
// Click home, then wait for any accessibility event, then wait until accessibility
// events stop.
// We need waiting for any accessibility event generated after pressing Home because
// otherwise waitForIdle may return immediately in case when there was a big enough
// pause in accessibility events prior to pressing Home.
final String action;
+ Log.d("b/155926212", "Before isLauncherVisible()");
final boolean launcherWasVisible = isLauncherVisible();
+ Log.d("b/155926212", "After isLauncherVisible(): " + launcherWasVisible);
if (getNavigationModel() == NavigationModel.ZERO_BUTTON) {
checkForAnomaly();
@@ -661,7 +648,7 @@
false, GestureScope.INSIDE_TO_OUTSIDE);
try (LauncherInstrumentation.Closable c = addContextLayer(
"Swiped up from context menu to home")) {
- waitUntilGone(CONTEXT_MENU_RES_ID);
+ waitUntilLauncherObjectGone(CONTEXT_MENU_RES_ID);
}
}
if (hasLauncherObject(WORKSPACE_RES_ID)) {
@@ -669,7 +656,7 @@
} else {
log("Hierarchy before swiping up to home:");
dumpViewHierarchy();
- log(action = "swiping up to home from " + getVisibleStateMessage());
+ action = "swiping up to home";
try (LauncherInstrumentation.Closable c = addContextLayer(action)) {
swipeToState(
@@ -680,20 +667,12 @@
? GestureScope.INSIDE_TO_OUTSIDE
: GestureScope.OUTSIDE);
}
- if (!launcherWasVisible) {
- expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_START_ACTIVITY);
- }
}
} else {
- if (!launcherWasVisible) {
- expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_START_ACTIVITY);
- }
log("Hierarchy before clicking home:");
dumpViewHierarchy();
- log(action = "clicking home button from " + getVisibleStateMessage());
+ action = "clicking home button";
try (LauncherInstrumentation.Closable c = addContextLayer(action)) {
- mDevice.waitForIdle();
-
if (!isLauncher3() && getNavigationModel() == NavigationModel.TWO_BUTTON) {
expectEvent(TestProtocol.SEQUENCE_TIS, EVENT_TOUCH_DOWN_TIS);
expectEvent(TestProtocol.SEQUENCE_TIS, EVENT_TOUCH_UP_TIS);
@@ -705,13 +684,14 @@
!hasLauncherObject(WORKSPACE_RES_ID)
&& (hasLauncherObject(APPS_RES_ID)
|| hasLauncherObject(OVERVIEW_RES_ID)));
- mDevice.waitForIdle();
}
}
try (LauncherInstrumentation.Closable c = addContextLayer(
"performed action to switch to Home - " + action)) {
return getWorkspace();
}
+ } finally {
+ mInstrumentation.getUiAutomation().setOnAccessibilityEventListener(null);
}
}
@@ -821,9 +801,17 @@
}
}
- void waitUntilGone(String resId) {
- assertTrue("Unexpected launcher object visible: " + resId,
- mDevice.wait(Until.gone(getLauncherObjectSelector(resId)),
+ void waitUntilLauncherObjectGone(String resId) {
+ waitUntilGoneBySelector(getLauncherObjectSelector(resId));
+ }
+
+ void waitUntilLauncherObjectGone(BySelector selector) {
+ waitUntilGoneBySelector(makeLauncherSelector(selector));
+ }
+
+ private void waitUntilGoneBySelector(BySelector launcherSelector) {
+ assertTrue("Unexpected launcher object visible: " + launcherSelector,
+ mDevice.wait(Until.gone(launcherSelector),
WAIT_TIME_MS));
}
@@ -950,9 +938,9 @@
executeAndWaitForEvent(
command,
event -> isSwitchToStateEvent(event, expectedState, actualEvents),
- () -> "Failed to receive an event for the state change: expected "
+ () -> "Failed to receive an event for the state change: expected ["
+ TestProtocol.stateOrdinalToString(expectedState)
- + ", actual: " + eventListToString(actualEvents));
+ + "], actual: " + eventListToString(actualEvents));
}
private boolean isSwitchToStateEvent(
@@ -1307,19 +1295,25 @@
public Closable eventsCheck() {
Assert.assertTrue("Nested event checking", !sCheckingEvents);
disableSensorRotation();
- sCheckingEvents = true;
- mExpectedPid = getPid();
+ final int initialPid = getPid();
if (sEventChecker == null) sEventChecker = new LogEventChecker();
sEventChecker.start();
+ sCheckingEvents = true;
return () -> {
- checkForAnomaly();
+ if (initialPid != getPid()) {
+ if (mOnLauncherCrashed != null) mOnLauncherCrashed.run();
+ checkForAnomaly();
+ Assert.fail(
+ formatSystemHealthMessage(closeEvents("Launcher crashed", false)));
+ }
if (sCheckingEvents) {
sCheckingEvents = false;
if (mCheckEventsForSuccessfulGestures) {
- final String message = sEventChecker.verify(WAIT_TIME_MS);
+ final String message = sEventChecker.verify(WAIT_TIME_MS, true);
if (message != null) {
+ checkForAnomaly();
Assert.fail(formatSystemHealthMessage(
"http://go/tapl : successful gesture produced " + message));
}
diff --git a/tests/tapl/com/android/launcher3/tapl/LogEventChecker.java b/tests/tapl/com/android/launcher3/tapl/LogEventChecker.java
index 78dfc36..ac90b1b 100644
--- a/tests/tapl/com/android/launcher3/tapl/LogEventChecker.java
+++ b/tests/tapl/com/android/launcher3/tapl/LogEventChecker.java
@@ -69,8 +69,9 @@
mFinished.await();
} catch (InterruptedException e) {
throw new RuntimeException(e);
+ } finally {
+ mFinished = null;
}
- mFinished = null;
}
mEvents.clear();
Log.d(SKIP_EVENTS_TAG, "Cleared events");
@@ -79,24 +80,33 @@
final String id = UUID.randomUUID().toString();
mStartCommand = START_PREFIX + id;
mFinishCommand = FINISH_PREFIX + id;
+ Log.d(SKIP_EVENTS_TAG, "Expected finish command: " + mFinishCommand);
Log.d(TestProtocol.TAPL_EVENTS_TAG, mStartCommand);
}
private void onRun() {
+ while (true) readEvents();
+ }
+
+ private void readEvents() {
try {
// Note that we use Runtime.exec to start the log reading process instead of running
// it via UIAutomation, so that we can directly access the "Process" object and
// ensure that the instrumentation is not stuck forever.
final String cmd = "logcat -s " + TestProtocol.TAPL_EVENTS_TAG;
+ final Process logcatProcess = Runtime.getRuntime().exec(cmd);
try (BufferedReader reader = new BufferedReader(new InputStreamReader(
- Runtime.getRuntime().exec(cmd).getInputStream()))) {
- for (; ; ) {
+ logcatProcess.getInputStream()))) {
+ while (true) {
// Skip everything before the next start command.
for (; ; ) {
final String event = reader.readLine();
- if (event.contains(TestProtocol.TAPL_EVENTS_TAG)
- && event.contains(mStartCommand)) {
+ if (event == null) {
+ Log.d(SKIP_EVENTS_TAG, "Read a null line while waiting for start");
+ return;
+ }
+ if (event.contains(mStartCommand)) {
Log.d(SKIP_EVENTS_TAG, "Read start: " + event);
break;
}
@@ -105,22 +115,30 @@
// Store all actual events until the finish command.
for (; ; ) {
final String event = reader.readLine();
- if (event.contains(TestProtocol.TAPL_EVENTS_TAG)) {
- if (event.contains(mFinishCommand)) {
- mFinished.countDown();
- Log.d(SKIP_EVENTS_TAG, "Read finish: " + event);
- break;
+ if (event == null) {
+ Log.d(SKIP_EVENTS_TAG, "Read a null line after waiting for start");
+ mEventsCounter.drainPermits();
+ mEvents.clear();
+ return;
+ }
+ if (event.contains(mFinishCommand)) {
+ mFinished.countDown();
+ Log.d(SKIP_EVENTS_TAG, "Read finish: " + event);
+ break;
+ } else {
+ final Matcher matcher = EVENT_LOG_ENTRY.matcher(event);
+ if (matcher.find()) {
+ mEvents.add(matcher.group("sequence"), matcher.group("event"));
+ Log.d(SKIP_EVENTS_TAG, "Read event: " + event);
+ mEventsCounter.release();
} else {
- final Matcher matcher = EVENT_LOG_ENTRY.matcher(event);
- if (matcher.find()) {
- mEvents.add(matcher.group("sequence"), matcher.group("event"));
- Log.d(SKIP_EVENTS_TAG, "Read event: " + event);
- mEventsCounter.release();
- }
+ Log.d(SKIP_EVENTS_TAG, "Read something unexpected: " + event);
}
}
}
}
+ } finally {
+ logcatProcess.destroyForcibly();
}
} catch (IOException e) {
throw new RuntimeException(e);
@@ -150,7 +168,7 @@
Log.d(TestProtocol.TAPL_EVENTS_TAG, mFinishCommand);
}
- String verify(long waitForExpectedCountMs) {
+ String verify(long waitForExpectedCountMs, boolean successfulGesture) {
finishSync(waitForExpectedCountMs);
final StringBuilder sb = new StringBuilder();
@@ -161,7 +179,8 @@
List<String> actual = new ArrayList<>(mEvents.getNonNull(sequence));
Log.d(SKIP_EVENTS_TAG, "Verifying events");
final int mismatchPosition = getMismatchPosition(expectedEvents.getValue(), actual);
- hasMismatches = hasMismatches || mismatchPosition != -1;
+ hasMismatches = hasMismatches
+ || mismatchPosition != -1 && !ignoreMistatch(successfulGesture, sequence);
formatSequenceWithMismatch(
sb,
sequence,
@@ -172,7 +191,8 @@
// Check for unexpected event sequences in the actual data.
for (String actualNamedSequence : mEvents.keySet()) {
if (!mExpectedEvents.containsKey(actualNamedSequence)) {
- hasMismatches = true;
+ hasMismatches = hasMismatches
+ || !ignoreMistatch(successfulGesture, actualNamedSequence);
formatSequenceWithMismatch(
sb,
actualNamedSequence,
@@ -185,6 +205,11 @@
return hasMismatches ? "mismatching events: " + sb.toString() : null;
}
+ // Workaround for b/154157191
+ private static boolean ignoreMistatch(boolean successfulGesture, String sequence) {
+ return TestProtocol.SEQUENCE_TIS.equals(sequence) && successfulGesture;
+ }
+
// If the list of actual events matches the list of expected events, returns -1, otherwise
// the position of the mismatch.
private static int getMismatchPosition(List<Pattern> expected, List<String> actual) {
diff --git a/tests/tapl/com/android/launcher3/tapl/OptionsPopupMenuItem.java b/tests/tapl/com/android/launcher3/tapl/OptionsPopupMenuItem.java
index d1268cc..42b6bc9 100644
--- a/tests/tapl/com/android/launcher3/tapl/OptionsPopupMenuItem.java
+++ b/tests/tapl/com/android/launcher3/tapl/OptionsPopupMenuItem.java
@@ -15,8 +15,6 @@
*/
package com.android.launcher3.tapl;
-import android.os.Build;
-
import androidx.annotation.NonNull;
import androidx.test.uiautomator.By;
import androidx.test.uiautomator.UiObject2;
@@ -44,12 +42,6 @@
+ mObject.getVisibleCenter() + " in " + mLauncher.getVisibleBounds(mObject));
mLauncher.clickLauncherObject(mObject);
mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, LauncherInstrumentation.EVENT_START);
- if (!Build.MODEL.contains("Cuttlefish") ||
- Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q &&
- !"R".equals(Build.VERSION.CODENAME)) {
- mLauncher.expectEvent(
- TestProtocol.SEQUENCE_MAIN, LauncherInstrumentation.EVENT_STOP_ACTIVITY);
- }
mLauncher.assertTrue(
"App didn't start: " + By.pkg(expectedPackageName),
mLauncher.getDevice().wait(Until.hasObject(By.pkg(expectedPackageName)),
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
index fae5f19..b235919 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
@@ -79,8 +79,6 @@
() -> "Launching task didn't open a new window: "
+ mTask.getParent().getContentDescription());
mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, TASK_START_EVENT);
- mLauncher.expectEvent(
- TestProtocol.SEQUENCE_MAIN, LauncherInstrumentation.EVENT_STOP_ACTIVITY);
}
return new Background(mLauncher);
}
diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java
index 0d91dc2..f0e686f 100644
--- a/tests/tapl/com/android/launcher3/tapl/Workspace.java
+++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java
@@ -229,12 +229,8 @@
if (startsActivity || isWidgetShortcut) {
launcher.expectEvent(TestProtocol.SEQUENCE_MAIN, LauncherInstrumentation.EVENT_START);
}
- if (startsActivity) {
- launcher.expectEvent(
- TestProtocol.SEQUENCE_MAIN, LauncherInstrumentation.EVENT_STOP_ACTIVITY);
- }
LauncherInstrumentation.log("dragIconToWorkspace: end");
- launcher.waitUntilGone("drop_target_bar");
+ launcher.waitUntilLauncherObjectGone("drop_target_bar");
}
/**