Merge master@5406228 into git_qt-dev-plus-aosp.
am: 1d4d86d942
Change-Id: Ic14dc666c6ed9d918f4ee47396c89ae802ab8153
diff --git a/Android.bp b/Android.bp
index 1121a79..5acec37 100644
--- a/Android.bp
+++ b/Android.bp
@@ -23,7 +23,6 @@
],
srcs: [
"tests/tapl/**/*.java",
- "quickstep/src/com/android/quickstep/SwipeUpSetting.java",
"src/com/android/launcher3/util/SecureSettingsObserver.java",
"src/com/android/launcher3/TestProtocol.java",
],
diff --git a/go/quickstep/src/com/android/launcher3/uioverrides/BackgroundAppState.java b/go/quickstep/src/com/android/launcher3/uioverrides/BackgroundAppState.java
deleted file mode 100644
index 4038c99..0000000
--- a/go/quickstep/src/com/android/launcher3/uioverrides/BackgroundAppState.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.uioverrides;
-
-/**
- * State indicating that the Launcher is behind an app. Same as {@link OverviewState} for Go as we
- * do not support swipe to overview or swipe to home.
- */
-public final class BackgroundAppState extends OverviewState {
- public BackgroundAppState(int id) {
- super(id);
- }
-}
diff --git a/go/quickstep/src/com/android/launcher3/uioverrides/RecentsUiFactory.java b/go/quickstep/src/com/android/launcher3/uioverrides/RecentsUiFactory.java
index 29e650c..d9b9686 100644
--- a/go/quickstep/src/com/android/launcher3/uioverrides/RecentsUiFactory.java
+++ b/go/quickstep/src/com/android/launcher3/uioverrides/RecentsUiFactory.java
@@ -17,7 +17,6 @@
package com.android.launcher3.uioverrides;
import static android.view.View.VISIBLE;
-
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
import android.view.View;
@@ -26,8 +25,12 @@
import com.android.launcher3.LauncherStateManager.StateHandler;
import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.uioverrides.touchcontrollers.LandscapeEdgeSwipeController;
+import com.android.launcher3.uioverrides.touchcontrollers.LandscapeStatesTouchController;
+import com.android.launcher3.uioverrides.touchcontrollers.PortraitStatesTouchController;
+import com.android.launcher3.uioverrides.touchcontrollers.StatusBarTouchController;
import com.android.launcher3.util.TouchController;
-import com.android.quickstep.OverviewInteractionState;
+import com.android.quickstep.SysUINavigationMode;
import com.android.quickstep.views.IconRecentsView;
import java.util.ArrayList;
@@ -49,8 +52,8 @@
list.add(new LandscapeStatesTouchController(launcher));
list.add(new LandscapeEdgeSwipeController(launcher));
} else {
- boolean allowDragToOverview = OverviewInteractionState.INSTANCE.get(launcher)
- .isSwipeUpGestureEnabled();
+ boolean allowDragToOverview = SysUINavigationMode.INSTANCE.get(launcher)
+ .getMode().hasGestures;
list.add(new PortraitStatesTouchController(launcher, allowDragToOverview));
}
if (FeatureFlags.PULL_DOWN_STATUS_BAR && Utilities.IS_DEBUG_DEVICE
diff --git a/go/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java b/go/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
similarity index 85%
rename from go/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
rename to go/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
index cec12a8..6730e97 100644
--- a/go/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
+++ b/go/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.launcher3.uioverrides;
+package com.android.launcher3.uioverrides.states;
import static com.android.launcher3.LauncherAnimUtils.OVERVIEW_TRANSITION_MS;
import static com.android.launcher3.anim.Interpolators.DEACCEL_2;
@@ -43,8 +43,8 @@
}
@Override
- public float[] getOverviewScaleAndTranslationY(Launcher launcher) {
- return new float[] {1f, 0f};
+ public ScaleAndTranslation getOverviewScaleAndTranslation(Launcher launcher) {
+ return new ScaleAndTranslation(1f, 0f, 0f);
}
@Override
@@ -91,4 +91,17 @@
public static float getDefaultSwipeHeight(DeviceProfile dp) {
return dp.allAppsCellHeightPx - dp.allAppsIconTextSizePx;
}
+
+
+ public static OverviewState newBackgroundState(int id) {
+ return new OverviewState(id);
+ }
+
+ public static OverviewState newPeekState(int id) {
+ return new OverviewState(id);
+ }
+
+ public static OverviewState newSwitchState(int id) {
+ return new OverviewState(id);
+ }
}
diff --git a/go/quickstep/src/com/android/launcher3/uioverrides/LandscapeStatesTouchController.java b/go/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/LandscapeStatesTouchController.java
similarity index 97%
rename from go/quickstep/src/com/android/launcher3/uioverrides/LandscapeStatesTouchController.java
rename to go/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/LandscapeStatesTouchController.java
index 2c91bc3..1ccd7d7 100644
--- a/go/quickstep/src/com/android/launcher3/uioverrides/LandscapeStatesTouchController.java
+++ b/go/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/LandscapeStatesTouchController.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.launcher3.uioverrides;
+package com.android.launcher3.uioverrides.touchcontrollers;
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.NORMAL;
diff --git a/go/quickstep/src/com/android/launcher3/uioverrides/PortraitOverviewStateTouchHelper.java b/go/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitOverviewStateTouchHelper.java
similarity index 97%
rename from go/quickstep/src/com/android/launcher3/uioverrides/PortraitOverviewStateTouchHelper.java
rename to go/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitOverviewStateTouchHelper.java
index a3b41b0..011a4e7 100644
--- a/go/quickstep/src/com/android/launcher3/uioverrides/PortraitOverviewStateTouchHelper.java
+++ b/go/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitOverviewStateTouchHelper.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.launcher3.uioverrides;
+package com.android.launcher3.uioverrides.touchcontrollers;
import android.view.MotionEvent;
diff --git a/go/quickstep/src/com/android/quickstep/AppToOverviewAnimationProvider.java b/go/quickstep/src/com/android/quickstep/AppToOverviewAnimationProvider.java
index 051c80f..d1d697c 100644
--- a/go/quickstep/src/com/android/quickstep/AppToOverviewAnimationProvider.java
+++ b/go/quickstep/src/com/android/quickstep/AppToOverviewAnimationProvider.java
@@ -173,8 +173,10 @@
// Keep recents visible throughout the animation.
SurfaceParams[] params = new SurfaceParams[2];
+ // Closing app should stay on top.
+ int boostedMode = MODE_CLOSING;
params[0] = new SurfaceParams(recentsTarget.leash, 1f, null /* matrix */,
- null /* windowCrop */, getLayer(recentsTarget, MODE_OPENING), 0 /* cornerRadius */);
+ null /* windowCrop */, getLayer(recentsTarget, boostedMode), 0 /* cornerRadius */);
valueAnimator.addUpdateListener(new MultiValueUpdateListener() {
private final FloatProp mScaleX;
@@ -214,7 +216,7 @@
m.postTranslate(mTranslationX.value, mTranslationY.value);
params[1] = new SurfaceParams(appTarget.leash, mAlpha.value, m,
- null /* windowCrop */, getLayer(appTarget, MODE_CLOSING),
+ null /* windowCrop */, getLayer(appTarget, boostedMode),
0 /* cornerRadius */);
surfaceApplier.scheduleApply(params);
}
diff --git a/go/quickstep/src/com/android/quickstep/GoActivityControlHelper.java b/go/quickstep/src/com/android/quickstep/GoActivityControlHelper.java
index 7078871..8b6f8bc 100644
--- a/go/quickstep/src/com/android/quickstep/GoActivityControlHelper.java
+++ b/go/quickstep/src/com/android/quickstep/GoActivityControlHelper.java
@@ -34,6 +34,11 @@
}
@Override
+ public void onAssistantVisibilityChanged(float visibility) {
+ // Go does not support assistant visibility transitions.
+ }
+
+ @Override
public HomeAnimationFactory prepareHomeUI(T activity) {
// Go does not support gestures from app to home.
return null;
diff --git a/go/quickstep/src/com/android/quickstep/RecentsActivity.java b/go/quickstep/src/com/android/quickstep/RecentsActivity.java
index 447e7e7..f2ca368 100644
--- a/go/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/go/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -67,9 +67,7 @@
@Override
protected void onStart() {
- // Set the alpha to 1 before calling super, as it may get set back to 0 due to
- // onActivityStart callback.
- mIconRecentsView.setAlpha(0);
+ mIconRecentsView.onBeginTransitionToOverview();
super.onStart();
}
}
diff --git a/go/quickstep/src/com/android/quickstep/TaskActionController.java b/go/quickstep/src/com/android/quickstep/TaskActionController.java
index b2d495b..77b287b 100644
--- a/go/quickstep/src/com/android/quickstep/TaskActionController.java
+++ b/go/quickstep/src/com/android/quickstep/TaskActionController.java
@@ -71,7 +71,6 @@
* Clears all tasks and updates the model and view.
*/
public void clearAllTasks() {
- // TODO: Play an animation so transition is more natural.
int count = mAdapter.getItemCount();
ActivityManagerWrapper.getInstance().removeAllRecentTasks();
mLoader.clearAllTasks();
diff --git a/go/quickstep/src/com/android/quickstep/TaskAdapter.java b/go/quickstep/src/com/android/quickstep/TaskAdapter.java
index e56cc51..c98eca6 100644
--- a/go/quickstep/src/com/android/quickstep/TaskAdapter.java
+++ b/go/quickstep/src/com/android/quickstep/TaskAdapter.java
@@ -75,8 +75,20 @@
// Task list has updated.
return;
}
- holder.bindTask(tasks.get(position));
-
+ Task task = tasks.get(position);
+ holder.bindTask(task);
+ mLoader.loadTaskIconAndLabel(task, () -> {
+ // Ensure holder still has the same task.
+ if (task.equals(holder.getTask())) {
+ holder.getTaskItemView().setIcon(task.icon);
+ holder.getTaskItemView().setLabel(task.titleDescription);
+ }
+ });
+ mLoader.loadTaskThumbnail(task, () -> {
+ if (task.equals(holder.getTask())) {
+ holder.getTaskItemView().setThumbnail(task.thumbnail.thumbnail);
+ }
+ });
}
@Override
diff --git a/go/quickstep/src/com/android/quickstep/TaskHolder.java b/go/quickstep/src/com/android/quickstep/TaskHolder.java
index a89229f..744afd7 100644
--- a/go/quickstep/src/com/android/quickstep/TaskHolder.java
+++ b/go/quickstep/src/com/android/quickstep/TaskHolder.java
@@ -35,17 +35,18 @@
mTaskItemView = itemView;
}
+ public TaskItemView getTaskItemView() {
+ return mTaskItemView;
+ }
+
/**
- * Bind task content to the view. This includes the task icon and title as well as binding
- * input handlers such as which task to launch/remove.
+ * Bind a task to the holder, resetting the view and preparing it for content to load in.
*
* @param task the task to bind to the view
*/
public void bindTask(Task task) {
mTask = task;
- mTaskItemView.setLabel(task.titleDescription);
- mTaskItemView.setIcon(task.icon);
- mTaskItemView.setThumbnail(task.thumbnail.thumbnail);
+ mTaskItemView.resetTaskItemView();
}
/**
diff --git a/go/quickstep/src/com/android/quickstep/TaskListLoader.java b/go/quickstep/src/com/android/quickstep/TaskListLoader.java
index c86c24e..1234989 100644
--- a/go/quickstep/src/com/android/quickstep/TaskListLoader.java
+++ b/go/quickstep/src/com/android/quickstep/TaskListLoader.java
@@ -25,7 +25,6 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
/**
@@ -39,35 +38,48 @@
private ArrayList<Task> mTaskList = new ArrayList<>();
private int mTaskListChangeId;
+ private RecentsModel.TaskThumbnailChangeListener listener = (taskId, thumbnailData) -> {
+ Task foundTask = null;
+ for (Task task : mTaskList) {
+ if (task.key.id == taskId) {
+ foundTask = task;
+ break;
+ }
+ }
+ if (foundTask != null) {
+ foundTask.thumbnail = thumbnailData;
+ }
+ return foundTask;
+ };
public TaskListLoader(Context context) {
mRecentsModel = RecentsModel.INSTANCE.get(context);
+ mRecentsModel.addThumbnailChangeListener(listener);
}
/**
- * Returns the current task list as of the last completed load (see
- * {@link #loadTaskList}) as a read-only list. This list of tasks is guaranteed to always have
- * all its task content loaded.
+ * Returns the current task list as of the last completed load (see {@link #loadTaskList}) as a
+ * read-only list. This list of tasks is not guaranteed to have all content loaded.
*
- * @return the current list of tasks w/ all content loaded
+ * @return the current list of tasks
*/
public List<Task> getCurrentTaskList() {
return Collections.unmodifiableList(mTaskList);
}
/**
- * Fetches the most recent tasks and updates the task list asynchronously. In addition it
- * loads the content for each task (icon and label). The callback and task list being updated
- * only occur when all task content is fully loaded and up-to-date.
+ * Fetches the most recent tasks and updates the task list asynchronously. This call does not
+ * provide guarantees the task content (icon, thumbnail, label) are loaded but will fill in
+ * what it has. May run the callback immediately if there have been no changes in the task
+ * list.
*
- * @param onTasksLoadedCallback callback for when the tasks are fully loaded. Done on the UI
- * thread
+ * @param onLoadedCallback callback to run when task list is loaded
*/
- public void loadTaskList(@Nullable Consumer<ArrayList<Task>> onTasksLoadedCallback) {
+ public void loadTaskList(@Nullable Consumer<ArrayList<Task>> onLoadedCallback) {
if (mRecentsModel.isTaskListValid(mTaskListChangeId)) {
// Current task list is already up to date. No need to update.
- if (onTasksLoadedCallback != null) {
- onTasksLoadedCallback.accept(mTaskList);
+ if (onLoadedCallback != null) {
+ onLoadedCallback.accept(mTaskList);
}
return;
}
@@ -76,16 +88,46 @@
// Reverse tasks to put most recent at the bottom of the view
Collections.reverse(tasks);
// Load task content
- loadTaskContents(tasks, () -> {
- mTaskList = tasks;
- if (onTasksLoadedCallback != null) {
- onTasksLoadedCallback.accept(mTaskList);
+ for (Task task : tasks) {
+ int loadedPos = mTaskList.indexOf(task);
+ if (loadedPos == -1) {
+ continue;
}
- });
+ Task loadedTask = mTaskList.get(loadedPos);
+ task.icon = loadedTask.icon;
+ task.titleDescription = loadedTask.titleDescription;
+ task.thumbnail = loadedTask.thumbnail;
+ }
+ mTaskList = tasks;
+ onLoadedCallback.accept(tasks);
});
}
/**
+ * Load task icon and label asynchronously if it is not already loaded in the task. If the task
+ * already has an icon, this calls the callback immediately.
+ *
+ * @param task task to update with icon + label
+ * @param onLoadedCallback callback to run when task has icon and label
+ */
+ public void loadTaskIconAndLabel(Task task, @Nullable Runnable onLoadedCallback) {
+ mRecentsModel.getIconCache().updateIconInBackground(task,
+ loadedTask -> onLoadedCallback.run());
+ }
+
+ /**
+ * Load thumbnail asynchronously if not already loaded in the task. If the task already has a
+ * thumbnail or if the thumbnail is cached, this calls the callback immediately.
+ *
+ * @param task task to update with the thumbnail
+ * @param onLoadedCallback callback to run when task has thumbnail
+ */
+ public void loadTaskThumbnail(Task task, @Nullable Runnable onLoadedCallback) {
+ mRecentsModel.getThumbnailCache().updateThumbnailInBackground(task,
+ thumbnail -> onLoadedCallback.run());
+ }
+
+ /**
* Removes the task from the current task list.
*/
void removeTask(Task task) {
@@ -98,42 +140,4 @@
void clearAllTasks() {
mTaskList.clear();
}
-
- /**
- * Loads task content for a list of tasks, including the label, icon, and thumbnail. For content
- * that isn't cached, load the content asynchronously in the background.
- *
- * @param tasksToLoad list of tasks that need to load their content
- * @param onFullyLoadedCallback runnable to run after all tasks have loaded their content
- */
- private void loadTaskContents(ArrayList<Task> tasksToLoad,
- @Nullable Runnable onFullyLoadedCallback) {
- // Make two load requests per task, one for the icon/title and one for the thumbnail.
- AtomicInteger loadRequestsCount = new AtomicInteger(tasksToLoad.size() * 2);
- Runnable itemLoadedRunnable = () -> {
- if (loadRequestsCount.decrementAndGet() == 0 && onFullyLoadedCallback != null) {
- onFullyLoadedCallback.run();
- }
- };
- for (Task task : tasksToLoad) {
- // Load icon and title.
- int index = mTaskList.indexOf(task);
- if (index >= 0) {
- // If we've already loaded the task and have its content then just copy it over.
- Task loadedTask = mTaskList.get(index);
- task.titleDescription = loadedTask.titleDescription;
- task.icon = loadedTask.icon;
- itemLoadedRunnable.run();
- } else {
- // Otherwise, load the content in the background.
- mRecentsModel.getIconCache().updateIconInBackground(task,
- loadedTask -> itemLoadedRunnable.run());
- }
-
- // Load the thumbnail. May return immediately and synchronously if the thumbnail is
- // cached.
- mRecentsModel.getThumbnailCache().updateThumbnailInBackground(task,
- thumbnail -> itemLoadedRunnable.run());
- }
- }
}
diff --git a/go/quickstep/src/com/android/quickstep/TouchInteractionService.java b/go/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 89a8454..c579c8a 100644
--- a/go/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/go/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -30,7 +30,6 @@
import com.android.systemui.shared.recents.IOverviewProxy;
import com.android.systemui.shared.recents.ISystemUiProxy;
-import com.android.systemui.shared.system.NavigationBarCompat.HitTarget;
/**
* Service connected by system-UI for handling touch interaction.
@@ -38,8 +37,6 @@
@TargetApi(Build.VERSION_CODES.O)
public class TouchInteractionService extends Service {
- public static final int EDGE_NAV_BAR = 1 << 8;
-
private static final String TAG = "TouchInteractionService";
private final IBinder mMyBinder = new IOverviewProxy.Stub() {
@@ -83,6 +80,15 @@
// TODO handle assistant
}
+ @Override
+ public void onAssistantVisibilityChanged(float visibility) {
+ // TODO handle assistant
+ }
+
+ public void onBackAction(boolean completed, int downX, int downY, boolean isButton,
+ boolean gestureSwipeLeft) {
+ }
+
/** Deprecated methods **/
public void onQuickStep(MotionEvent motionEvent) { }
diff --git a/go/quickstep/src/com/android/quickstep/fallback/GoRecentsActivityRootView.java b/go/quickstep/src/com/android/quickstep/fallback/GoRecentsActivityRootView.java
index d748e89..c0ebcb5 100644
--- a/go/quickstep/src/com/android/quickstep/fallback/GoRecentsActivityRootView.java
+++ b/go/quickstep/src/com/android/quickstep/fallback/GoRecentsActivityRootView.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.util.AttributeSet;
+import com.android.launcher3.util.TouchController;
import com.android.launcher3.views.BaseDragLayer;
import com.android.quickstep.RecentsActivity;
@@ -27,5 +28,7 @@
public final class GoRecentsActivityRootView extends BaseDragLayer<RecentsActivity> {
public GoRecentsActivityRootView(Context context, AttributeSet attrs) {
super(context, attrs, 1 /* alphaChannelCount */);
+ // Go leaves touch control to the view itself.
+ mControllers = new TouchController[0];
}
}
diff --git a/go/quickstep/src/com/android/quickstep/views/IconRecentsView.java b/go/quickstep/src/com/android/quickstep/views/IconRecentsView.java
index a1d62c2..5bb4c5a 100644
--- a/go/quickstep/src/com/android/quickstep/views/IconRecentsView.java
+++ b/go/quickstep/src/com/android/quickstep/views/IconRecentsView.java
@@ -19,6 +19,10 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.animation.ValueAnimator;
import android.content.Context;
import android.util.AttributeSet;
import android.util.FloatProperty;
@@ -65,6 +69,10 @@
}
};
private static final long CROSSFADE_DURATION = 300;
+ private static final long ITEM_ANIMATE_OUT_DURATION = 150;
+ private static final long ITEM_ANIMATE_OUT_DELAY_BETWEEN = 40;
+ private static final float ITEM_ANIMATE_OUT_TRANSLATION_X_RATIO = .25f;
+ private static final long CLEAR_ALL_FADE_DELAY = 120;
/**
* A ratio representing the view's relative placement within its padded space. For example, 0
@@ -81,6 +89,7 @@
private RecyclerView mTaskRecyclerView;
private View mEmptyView;
private View mContentView;
+ private View mClearAllView;
private boolean mTransitionedFromApp;
public IconRecentsView(Context context, AttributeSet attrs) {
@@ -117,12 +126,22 @@
updateContentViewVisibility();
}
});
-
- View clearAllView = findViewById(R.id.clear_all_button);
- clearAllView.setOnClickListener(v -> mTaskActionController.clearAllTasks());
+ mClearAllView = findViewById(R.id.clear_all_button);
+ mClearAllView.setOnClickListener(v -> animateClearAllTasks());
}
}
+
+ @Override
+ public void setEnabled(boolean enabled) {
+ super.setEnabled(enabled);
+ TaskItemView[] itemViews = getTaskViews();
+ for (TaskItemView itemView : itemViews) {
+ itemView.setEnabled(enabled);
+ }
+ mClearAllView.setEnabled(enabled);
+ }
+
/**
* Set activity helper for the view to callback to.
*
@@ -136,8 +155,6 @@
* Logic for when we know we are going to overview/recents and will be putting up the recents
* view. This should be used to prepare recents (e.g. load any task data, etc.) before it
* becomes visible.
- *
- * TODO: Hook this up for fallback recents activity as well
*/
public void onBeginTransitionToOverview() {
// Load any task changes
@@ -195,6 +212,78 @@
}
/**
+ * Clear all tasks and animate out.
+ */
+ private void animateClearAllTasks() {
+ setEnabled(false);
+ TaskItemView[] itemViews = getTaskViews();
+
+ AnimatorSet clearAnim = new AnimatorSet();
+ long currentDelay = 0;
+
+ // Animate each item view to the right and fade out.
+ for (TaskItemView itemView : itemViews) {
+ PropertyValuesHolder transXproperty = PropertyValuesHolder.ofFloat(TRANSLATION_X,
+ 0, itemView.getWidth() * ITEM_ANIMATE_OUT_TRANSLATION_X_RATIO);
+ PropertyValuesHolder alphaProperty = PropertyValuesHolder.ofFloat(ALPHA, 1.0f, 0f);
+ ObjectAnimator itemAnim = ObjectAnimator.ofPropertyValuesHolder(itemView,
+ transXproperty, alphaProperty);
+ itemAnim.setDuration(ITEM_ANIMATE_OUT_DURATION);
+ itemAnim.setStartDelay(currentDelay);
+
+ clearAnim.play(itemAnim);
+ currentDelay += ITEM_ANIMATE_OUT_DELAY_BETWEEN;
+ }
+
+ // Animate view fading and leave recents when faded enough.
+ ValueAnimator contentAlpha = ValueAnimator.ofFloat(1.0f, 0f)
+ .setDuration(CROSSFADE_DURATION);
+ contentAlpha.setStartDelay(CLEAR_ALL_FADE_DELAY);
+ contentAlpha.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ private boolean mLeftRecents = false;
+
+ @Override
+ public void onAnimationUpdate(ValueAnimator valueAnimator) {
+ mContentView.setAlpha((float) valueAnimator.getAnimatedValue());
+ // Leave recents while fading out.
+ if ((float) valueAnimator.getAnimatedValue() < .5f && !mLeftRecents) {
+ mActivityHelper.leaveRecents();
+ mLeftRecents = true;
+ }
+ }
+ });
+
+ clearAnim.play(contentAlpha);
+ clearAnim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ for (TaskItemView itemView : itemViews) {
+ itemView.setTranslationX(0);
+ itemView.setAlpha(1.0f);
+ }
+ setEnabled(true);
+ mContentView.setVisibility(GONE);
+ mTaskActionController.clearAllTasks();
+ }
+ });
+ clearAnim.start();
+ }
+
+ /**
+ * Get attached task item views ordered by most recent.
+ *
+ * @return array of attached task item views
+ */
+ private TaskItemView[] getTaskViews() {
+ int taskCount = mTaskRecyclerView.getChildCount();
+ TaskItemView[] itemViews = new TaskItemView[taskCount];
+ for (int i = 0; i < taskCount; i ++) {
+ itemViews[i] = (TaskItemView) mTaskRecyclerView.getChildAt(i);
+ }
+ return itemViews;
+ }
+
+ /**
* Update the content view so that the appropriate view is shown based off the current list
* of tasks.
*/
diff --git a/go/quickstep/src/com/android/quickstep/views/TaskItemView.java b/go/quickstep/src/com/android/quickstep/views/TaskItemView.java
index 373f107..d831b20 100644
--- a/go/quickstep/src/com/android/quickstep/views/TaskItemView.java
+++ b/go/quickstep/src/com/android/quickstep/views/TaskItemView.java
@@ -17,6 +17,7 @@
import android.content.Context;
import android.graphics.Bitmap;
+import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
@@ -24,6 +25,8 @@
import android.widget.LinearLayout;
import android.widget.TextView;
+import androidx.annotation.Nullable;
+
import com.android.launcher3.R;
/**
@@ -31,12 +34,16 @@
*/
public final class TaskItemView extends LinearLayout {
+ private static final String DEFAULT_LABEL = "...";
+ private final Drawable mDefaultIcon;
private TextView mLabelView;
private ImageView mIconView;
private ImageView mThumbnailView;
public TaskItemView(Context context, AttributeSet attrs) {
super(context, attrs);
+ mDefaultIcon = context.getResources().getDrawable(
+ android.R.drawable.sym_def_app_icon, context.getTheme());
}
@Override
@@ -48,33 +55,56 @@
}
/**
- * Set the label for the task item.
+ * Resets task item view to default values.
+ */
+ public void resetTaskItemView() {
+ setLabel(DEFAULT_LABEL);
+ setIcon(null);
+ setThumbnail(null);
+ }
+
+ /**
+ * Set the label for the task item. Sets to a default label if null.
*
* @param label task label
*/
- public void setLabel(String label) {
+ public void setLabel(@Nullable String label) {
+ if (label == null) {
+ mLabelView.setText(DEFAULT_LABEL);
+ return;
+ }
mLabelView.setText(label);
}
/**
- * Set the icon for the task item.
+ * Set the icon for the task item. Sets to a default icon if null.
*
* @param icon task icon
*/
- public void setIcon(Drawable icon) {
+ public void setIcon(@Nullable Drawable icon) {
// TODO: Scale the icon up based off the padding on the side
// The icon proper is actually smaller than the drawable and has "padding" on the side for
// the purpose of drawing the shadow, allowing the icon to pop up, so we need to scale the
// view if we want the icon to be flush with the bottom of the thumbnail.
+ if (icon == null) {
+ mIconView.setImageDrawable(mDefaultIcon);
+ return;
+ }
mIconView.setImageDrawable(icon);
}
/**
- * Set the task thumbnail for the task.
+ * Set the task thumbnail for the task. Sets to a default thumbnail if null.
*
* @param thumbnail task thumbnail for the task
*/
- public void setThumbnail(Bitmap thumbnail) {
+ public void setThumbnail(@Nullable Bitmap thumbnail) {
+ if (thumbnail == null) {
+ mThumbnailView.setImageBitmap(null);
+ mThumbnailView.setBackgroundColor(Color.GRAY);
+ return;
+ }
+ mThumbnailView.setBackgroundColor(Color.TRANSPARENT);
mThumbnailView.setImageBitmap(thumbnail);
}
diff --git a/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java b/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java
index 96b0a9e..ab4b64c 100644
--- a/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java
+++ b/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java
@@ -61,6 +61,7 @@
mCanvas = new Canvas();
mCanvas.setDrawFilter(new PaintFlagsDrawFilter(DITHER_FLAG, FILTER_BITMAP_FLAG));
+ clear();
}
protected void clear() {
@@ -114,11 +115,6 @@
}
public BitmapInfo createBadgedIconBitmap(Drawable icon, UserHandle user,
- boolean shrinkNonAdaptiveIcons, boolean isInstantApp) {
- return createBadgedIconBitmap(icon, user, shrinkNonAdaptiveIcons, isInstantApp, null);
- }
-
- public BitmapInfo createBadgedIconBitmap(Drawable icon, UserHandle user,
int iconAppTargetSdk) {
return createBadgedIconBitmap(icon, user, iconAppTargetSdk, false);
}
diff --git a/protos/launcher_log.proto b/protos/launcher_log.proto
index 85f9826..4974dcb 100644
--- a/protos/launcher_log.proto
+++ b/protos/launcher_log.proto
@@ -106,7 +106,7 @@
RESIZE_HANDLE = 8;
VERTICAL_SCROLL = 9;
HOME_INTENT = 10; // Deprecated, use enum Command instead
- BACK_BUTTON = 11; // Deprecated, use enum Command instead
+ BACK_BUTTON = 11;
QUICK_SCRUB_BUTTON = 12;
CLEAR_ALL_BUTTON = 13;
CANCEL_TARGET = 14;
@@ -114,6 +114,7 @@
SPLIT_SCREEN_TARGET = 16;
REMOTE_ACTION_SHORTCUT = 17;
APP_USAGE_SETTINGS = 18;
+ BACK_GESTURE = 19;
}
enum TipType {
@@ -142,6 +143,7 @@
SWIPE = 3;
FLING = 4;
PINCH = 5;
+ SWIPE_NOOP = 6;
}
enum Direction {
@@ -150,6 +152,8 @@
DOWN = 2;
LEFT = 3;
RIGHT = 4;
+ UPRIGHT = 5;
+ UPLEFT = 6;
}
enum Command {
HOME_INTENT = 0;
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/FlingAndHoldTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/FlingAndHoldTouchController.java
deleted file mode 100644
index a41362f..0000000
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/FlingAndHoldTouchController.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.uioverrides;
-
-import static com.android.launcher3.LauncherState.NORMAL;
-import static com.android.launcher3.LauncherState.OVERVIEW;
-import static com.android.launcher3.LauncherStateManager.NON_ATOMIC_COMPONENT;
-
-import android.animation.ValueAnimator;
-
-import com.android.launcher3.Launcher;
-import com.android.launcher3.anim.AnimatorSetBuilder;
-import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
-import com.android.quickstep.util.MotionPauseDetector;
-import com.android.quickstep.views.RecentsView;
-
-/**
- * Touch controller which handles swipe and hold to go to Overview
- */
-public class FlingAndHoldTouchController extends PortraitStatesTouchController {
-
- private final MotionPauseDetector mMotionPauseDetector;
-
- public FlingAndHoldTouchController(Launcher l) {
- super(l, false /* allowDragToOverview */);
- mMotionPauseDetector = new MotionPauseDetector(l);
- }
-
- @Override
- public void onDragStart(boolean start) {
- mMotionPauseDetector.clear();
-
- super.onDragStart(start);
-
- if (mStartState == NORMAL) {
- mMotionPauseDetector.setOnMotionPauseListener(isPaused -> {
- RecentsView recentsView = mLauncher.getOverviewPanel();
- recentsView.setOverviewStateEnabled(isPaused);
- maybeUpdateAtomicAnim(NORMAL, OVERVIEW, isPaused ? 1 : 0);
- });
- }
- }
-
- @Override
- public boolean onDrag(float displacement) {
- mMotionPauseDetector.addPosition(displacement, 0);
- return super.onDrag(displacement);
- }
-
- @Override
- public void onDragEnd(float velocity, boolean fling) {
- if (mMotionPauseDetector.isPaused() && mStartState == NORMAL) {
- float range = getShiftRange();
- long maxAccuracy = (long) (2 * range);
-
- // Let the state manager know that the animation didn't go to the target state,
- // but don't cancel ourselves (we already clean up when the animation completes).
- Runnable onCancel = mCurrentAnimation.getOnCancelRunnable();
- mCurrentAnimation.setOnCancelRunnable(null);
- mCurrentAnimation.dispatchOnCancel();
- mCurrentAnimation = mLauncher.getStateManager()
- .createAnimationToNewWorkspace(OVERVIEW, new AnimatorSetBuilder(), maxAccuracy,
- onCancel, NON_ATOMIC_COMPONENT);
-
- final int logAction = fling ? Touch.FLING : Touch.SWIPE;
- mCurrentAnimation.setEndAction(() -> onSwipeInteractionCompleted(OVERVIEW, logAction));
-
-
- ValueAnimator anim = mCurrentAnimation.getAnimationPlayer();
- maybeUpdateAtomicAnim(NORMAL, OVERVIEW, 1f);
- mCurrentAnimation.dispatchOnStartWithVelocity(1, velocity);
-
- // TODO: Find a better duration
- anim.setDuration(100);
- anim.start();
- settleAtomicAnimation(1f, anim.getDuration());
- } else {
- super.onDragEnd(velocity, fling);
- }
- mMotionPauseDetector.clear();
- }
-}
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java
index 81ff0c7..f507d0f 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java
@@ -17,11 +17,9 @@
package com.android.launcher3.uioverrides;
import static android.view.View.VISIBLE;
-
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
-import static com.android.launcher3.config.FeatureFlags.SWIPE_HOME;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
@@ -30,10 +28,19 @@
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.uioverrides.touchcontrollers.FlingAndHoldTouchController;
+import com.android.launcher3.uioverrides.touchcontrollers.LandscapeEdgeSwipeController;
+import com.android.launcher3.uioverrides.touchcontrollers.NavBarToHomeTouchController;
+import com.android.launcher3.uioverrides.touchcontrollers.OverviewToAllAppsTouchController;
+import com.android.launcher3.uioverrides.touchcontrollers.PortraitStatesTouchController;
+import com.android.launcher3.uioverrides.touchcontrollers.StatusBarTouchController;
+import com.android.launcher3.uioverrides.touchcontrollers.QuickSwitchTouchController;
+import com.android.launcher3.uioverrides.touchcontrollers.TaskViewTouchController;
import com.android.launcher3.util.TouchController;
import com.android.launcher3.util.UiThreadHelper;
import com.android.launcher3.util.UiThreadHelper.AsyncCommand;
-import com.android.quickstep.OverviewInteractionState;
+import com.android.quickstep.SysUINavigationMode;
+import com.android.quickstep.SysUINavigationMode.Mode;
import com.android.quickstep.views.RecentsView;
import com.android.systemui.shared.system.WindowManagerWrapper;
@@ -52,15 +59,13 @@
private static final float RECENTS_PREPARE_SCALE = 1.33f;
public static TouchController[] createTouchControllers(Launcher launcher) {
- boolean swipeUpEnabled = OverviewInteractionState.INSTANCE.get(launcher)
- .isSwipeUpGestureEnabled();
- boolean swipeUpToHome = swipeUpEnabled && SWIPE_HOME.get();
-
+ Mode mode = SysUINavigationMode.INSTANCE.get(launcher).getMode();
ArrayList<TouchController> list = new ArrayList<>();
list.add(launcher.getDragController());
-
- if (swipeUpToHome) {
+ if (mode == Mode.NO_BUTTON) {
+ list.add(new QuickSwitchTouchController(launcher));
+ list.add(new NavBarToHomeTouchController(launcher));
list.add(new FlingAndHoldTouchController(launcher));
} else {
if (launcher.getDeviceProfile().isVerticalBarLayout()) {
@@ -68,7 +73,10 @@
list.add(new LandscapeEdgeSwipeController(launcher));
} else {
list.add(new PortraitStatesTouchController(launcher,
- swipeUpEnabled /* allowDragToOverview */));
+ mode.hasGestures /* allowDragToOverview */));
+ if (mode.hasGestures) {
+ list.add(new QuickSwitchTouchController(launcher));
+ }
}
}
@@ -98,6 +106,10 @@
* @param launcher the launcher activity
*/
public static void prepareToShowOverview(Launcher launcher) {
+ if (FeatureFlags.SWIPE_HOME.get()) {
+ // Overview lives on the side, so doesn't scale in from above.
+ return;
+ }
RecentsView overview = launcher.getOverviewPanel();
if (overview.getVisibility() != VISIBLE || overview.getContentAlpha() == 0) {
SCALE_PROPERTY.set(overview, RECENTS_PREPARE_SCALE);
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/BackgroundAppState.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
similarity index 94%
rename from quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/BackgroundAppState.java
rename to quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
index f712753..d8f1628 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/BackgroundAppState.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.launcher3.uioverrides;
+package com.android.launcher3.uioverrides.states;
import static com.android.launcher3.LauncherAnimUtils.OVERVIEW_TRANSITION_MS;
@@ -52,7 +52,7 @@
}
@Override
- public float[] getOverviewScaleAndTranslationY(Launcher launcher) {
+ public ScaleAndTranslation getOverviewScaleAndTranslation(Launcher launcher) {
// Initialize the recents view scale to what it would be when starting swipe up
RecentsView recentsView = launcher.getOverviewPanel();
recentsView.getTaskSize(sTempRect);
@@ -71,7 +71,7 @@
}
}
float scale = (float) appWidth / sTempRect.width();
- return new float[] { scale, 0f };
+ return new ScaleAndTranslation(scale, 0f, 0f);
}
@Override
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
new file mode 100644
index 0000000..bc1d4ba
--- /dev/null
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewPeekState.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.uioverrides.states;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.R;
+
+public class OverviewPeekState extends OverviewState {
+ public OverviewPeekState(int id) {
+ super(id);
+ }
+
+ @Override
+ public ScaleAndTranslation getOverviewScaleAndTranslation(Launcher launcher) {
+ ScaleAndTranslation result = super.getOverviewScaleAndTranslation(launcher);
+ result.translationX = NORMAL.getOverviewScaleAndTranslation(launcher).translationX
+ - launcher.getResources().getDimension(R.dimen.overview_peek_distance);
+ return result;
+ }
+}
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/OverviewState.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java
similarity index 84%
rename from quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/OverviewState.java
rename to quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java
index 2360eeb..94c1545 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/OverviewState.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java
@@ -13,11 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.launcher3.uioverrides;
+package com.android.launcher3.uioverrides.states;
import static com.android.launcher3.LauncherAnimUtils.OVERVIEW_TRANSITION_MS;
import static com.android.launcher3.anim.Interpolators.DEACCEL_2;
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
+import static com.android.launcher3.logging.LoggerUtils.getTargetStr;
import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
import static com.android.launcher3.states.RotationHelper.REQUEST_ROTATE;
@@ -52,11 +53,15 @@
}
protected OverviewState(int id, int transitionDuration, int stateFlags) {
- super(id, ContainerType.TASKSWITCHER, transitionDuration, stateFlags);
+ this(id, ContainerType.TASKSWITCHER, transitionDuration, stateFlags);
+ }
+
+ protected OverviewState(int id, int logContainer, int transitionDuration, int stateFlags) {
+ super(id, logContainer, transitionDuration, stateFlags);
}
@Override
- public float[] getWorkspaceScaleAndTranslation(Launcher launcher) {
+ public ScaleAndTranslation getWorkspaceScaleAndTranslation(Launcher launcher) {
RecentsView recentsView = launcher.getOverviewPanel();
Workspace workspace = launcher.getWorkspace();
View workspacePage = workspace.getPageAt(workspace.getCurrentPage());
@@ -65,12 +70,12 @@
recentsView.getTaskSize(sTempRect);
float scale = (float) sTempRect.width() / workspacePageWidth;
float parallaxFactor = 0.5f;
- return new float[]{scale, 0, -getDefaultSwipeHeight(launcher) * parallaxFactor};
+ return new ScaleAndTranslation(scale, 0, -getDefaultSwipeHeight(launcher) * parallaxFactor);
}
@Override
- public float[] getOverviewScaleAndTranslationY(Launcher launcher) {
- return new float[] {1f, 0f};
+ public ScaleAndTranslation getOverviewScaleAndTranslation(Launcher launcher) {
+ return new ScaleAndTranslation(1f, 0f, 0f);
}
@Override
@@ -92,6 +97,7 @@
DiscoveryBounce.showForOverviewIfNeeded(launcher);
}
+ @Override
public PageAlphaProvider getWorkspacePageAlphaProvider(Launcher launcher) {
return new PageAlphaProvider(DEACCEL_2) {
@Override
@@ -151,4 +157,16 @@
super.onBackPressed(launcher);
}
}
+
+ public static OverviewState newBackgroundState(int id) {
+ return new BackgroundAppState(id);
+ }
+
+ public static OverviewState newPeekState(int id) {
+ return new OverviewPeekState(id);
+ }
+
+ public static OverviewState newSwitchState(int id) {
+ return new QuickSwitchState(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
new file mode 100644
index 0000000..fa07e27
--- /dev/null
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.uioverrides.states;
+
+import static com.android.launcher3.LauncherAnimUtils.OVERVIEW_TRANSITION_MS;
+
+import android.graphics.Rect;
+
+import com.android.launcher3.Launcher;
+import com.android.launcher3.userevent.nano.LauncherLogProto;
+import com.android.quickstep.util.ClipAnimationHelper;
+import com.android.quickstep.views.RecentsView;
+import com.android.quickstep.views.TaskThumbnailView;
+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 WindowTransformSwipeHelper.
+ * @see com.android.quickstep.WindowTransformSwipeHandler.GestureEndTarget#NEW_TASK
+ */
+public class QuickSwitchState extends OverviewState {
+ private static final int STATE_FLAGS =
+ FLAG_DISABLE_RESTORE | FLAG_OVERVIEW_UI | FLAG_DISABLE_ACCESSIBILITY;
+
+ public QuickSwitchState(int id) {
+ super(id, LauncherLogProto.ContainerType.APP, OVERVIEW_TRANSITION_MS, STATE_FLAGS);
+ }
+
+ @Override
+ public ScaleAndTranslation getOverviewScaleAndTranslation(Launcher launcher) {
+ RecentsView recentsView = launcher.getOverviewPanel();
+ if (recentsView.getTaskViewCount() == 0) {
+ return super.getOverviewScaleAndTranslation(launcher);
+ }
+ // Compute scale and translation y such that the most recent task view fills the screen.
+ TaskThumbnailView dummyThumbnail = recentsView.getTaskViewAt(0).getThumbnail();
+ ClipAnimationHelper clipAnimationHelper = new ClipAnimationHelper(launcher);
+ clipAnimationHelper.fromTaskThumbnailView(dummyThumbnail, recentsView);
+ Rect targetRect = new Rect();
+ recentsView.getTaskSize(targetRect);
+ clipAnimationHelper.updateTargetRect(targetRect);
+ float toScale = clipAnimationHelper.getSourceRect().width()
+ / clipAnimationHelper.getTargetRect().width();
+ float toTranslationY = clipAnimationHelper.getSourceRect().centerY()
+ - clipAnimationHelper.getTargetRect().centerY();
+ return new ScaleAndTranslation(toScale, 0, toTranslationY);
+ }
+
+ @Override
+ public ScaleAndTranslation getWorkspaceScaleAndTranslation(Launcher launcher) {
+ float shiftRange = launcher.getAllAppsController().getShiftRange();
+ float shiftProgress = getVerticalProgress(launcher) - NORMAL.getVerticalProgress(launcher);
+ float translationY = shiftProgress * shiftRange;
+ return new ScaleAndTranslation(1, 0, translationY);
+ }
+
+ @Override
+ public float getVerticalProgress(Launcher launcher) {
+ return BACKGROUND_APP.getVerticalProgress(launcher);
+ }
+
+ @Override
+ 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);
+ } else {
+ launcher.getStateManager().goToState(NORMAL);
+ }
+ }
+}
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
new file mode 100644
index 0000000..6dd5e21
--- /dev/null
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.uioverrides.touchcontrollers;
+
+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.LauncherStateManager.ANIM_ALL;
+import static com.android.launcher3.LauncherStateManager.ATOMIC_OVERVIEW_PEEK_COMPONENT;
+import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.view.HapticFeedbackConstants;
+import android.view.MotionEvent;
+
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherState;
+import com.android.launcher3.anim.AnimatorSetBuilder;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
+import com.android.quickstep.util.MotionPauseDetector;
+import com.android.quickstep.views.RecentsView;
+
+/**
+ * Touch controller which handles swipe and hold to go to Overview
+ */
+public class FlingAndHoldTouchController extends PortraitStatesTouchController {
+
+ private static final long PEEK_ANIM_DURATION = 100;
+
+ private final MotionPauseDetector mMotionPauseDetector;
+
+ private AnimatorSet mPeekAnim;
+
+ public FlingAndHoldTouchController(Launcher l) {
+ super(l, false /* allowDragToOverview */);
+ mMotionPauseDetector = new MotionPauseDetector(l);
+ }
+
+ @Override
+ protected long getAtomicDuration() {
+ return 300;
+ }
+
+ @Override
+ public void onDragStart(boolean start) {
+ mMotionPauseDetector.clear();
+
+ super.onDragStart(start);
+
+ if (handlingOverviewAnim()) {
+ mMotionPauseDetector.setOnMotionPauseListener(isPaused -> {
+ RecentsView recentsView = mLauncher.getOverviewPanel();
+ recentsView.setOverviewStateEnabled(isPaused);
+ if (mPeekAnim != null) {
+ mPeekAnim.cancel();
+ }
+ LauncherState fromState = isPaused ? NORMAL : OVERVIEW_PEEK;
+ LauncherState toState = isPaused ? OVERVIEW_PEEK : NORMAL;
+ mPeekAnim = mLauncher.getStateManager().createAtomicAnimation(fromState, toState,
+ new AnimatorSetBuilder(), ATOMIC_OVERVIEW_PEEK_COMPONENT,
+ PEEK_ANIM_DURATION);
+ mPeekAnim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mPeekAnim = null;
+ }
+ });
+ mPeekAnim.start();
+ recentsView.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
+ HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
+ });
+ }
+ }
+
+ /**
+ * @return Whether we are handling the overview animation, rather than
+ * having it as part of the existing animation to the target state.
+ */
+ private boolean handlingOverviewAnim() {
+ return mStartState == NORMAL;
+ }
+
+ @Override
+ public boolean onDrag(float displacement, MotionEvent event) {
+ mMotionPauseDetector.addPosition(displacement, 0, event.getEventTime());
+ return super.onDrag(displacement, event);
+ }
+
+ @Override
+ public void onDragEnd(float velocity, boolean fling) {
+ if (mMotionPauseDetector.isPaused() && handlingOverviewAnim()) {
+ if (mPeekAnim != null) {
+ mPeekAnim.cancel();
+ }
+
+ AnimatorSetBuilder builder = new AnimatorSetBuilder();
+ builder.setInterpolator(AnimatorSetBuilder.ANIM_VERTICAL_PROGRESS, OVERSHOOT_1_2);
+ AnimatorSet overviewAnim = mLauncher.getStateManager().createAtomicAnimation(
+ NORMAL, OVERVIEW, builder, ANIM_ALL, ATOMIC_DURATION);
+ overviewAnim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ onSwipeInteractionCompleted(OVERVIEW, Touch.SWIPE);
+ }
+ });
+ overviewAnim.start();
+ } else {
+ super.onDragEnd(velocity, fling);
+ }
+ mMotionPauseDetector.clear();
+ }
+
+ @Override
+ protected void updateAnimatorBuilderOnReinit(AnimatorSetBuilder builder) {
+ if (handlingOverviewAnim()) {
+ // We don't want the state transition to all apps to animate overview,
+ // as that will cause a jump after our atomic animation.
+ builder.addFlag(AnimatorSetBuilder.FLAG_DONT_ANIMATE_OVERVIEW);
+ }
+ }
+}
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
new file mode 100644
index 0000000..673beff
--- /dev/null
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.uioverrides.touchcontrollers;
+
+import static com.android.launcher3.LauncherState.ALL_APPS;
+import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.LauncherState.OVERVIEW;
+import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PROGRESS;
+import static com.android.launcher3.anim.Interpolators.DEACCEL_3;
+
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.animation.Interpolator;
+
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherState;
+import com.android.launcher3.LauncherStateManager.AnimationConfig;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.allapps.AllAppsTransitionController;
+import com.android.launcher3.anim.AnimatorPlaybackController;
+import com.android.launcher3.anim.AnimatorSetBuilder;
+import com.android.launcher3.anim.Interpolators;
+import com.android.launcher3.touch.AbstractStateChangeTouchController;
+import com.android.launcher3.touch.SwipeDetector;
+import com.android.launcher3.userevent.nano.LauncherLogProto;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
+import com.android.quickstep.views.RecentsView;
+
+/**
+ * Handles swiping up on the nav bar to go home from overview or all apps.
+ */
+public class NavBarToHomeTouchController extends AbstractStateChangeTouchController {
+
+ private static final Interpolator PULLBACK_INTERPOLATOR = DEACCEL_3;
+
+ public NavBarToHomeTouchController(Launcher launcher) {
+ super(launcher, SwipeDetector.VERTICAL);
+ }
+
+ @Override
+ protected boolean canInterceptTouch(MotionEvent ev) {
+ boolean cameFromNavBar = (ev.getEdgeFlags() & Utilities.EDGE_NAV_BAR) != 0;
+ return cameFromNavBar && (mLauncher.isInState(OVERVIEW) || mLauncher.isInState(ALL_APPS));
+ }
+
+ @Override
+ protected LauncherState getTargetState(LauncherState fromState, boolean isDragTowardPositive) {
+ return isDragTowardPositive ? NORMAL : fromState;
+ }
+
+ @Override
+ protected float initCurrentAnimation(int animComponents) {
+ long accuracy = (long) (getShiftRange() * 2);
+ final AnimatorSet anim;
+ if (mFromState == OVERVIEW) {
+ anim = new AnimatorSet();
+ RecentsView recentsView = mLauncher.getOverviewPanel();
+ float pullbackDistance = recentsView.getPaddingStart() / 2;
+ if (!recentsView.isRtl()) {
+ pullbackDistance = -pullbackDistance;
+ }
+ anim.play(ObjectAnimator.ofFloat(recentsView, View.TRANSLATION_X, pullbackDistance));
+ anim.setInterpolator(PULLBACK_INTERPOLATOR);
+ } else { // if (mFromState == ALL_APPS)
+ AnimatorSetBuilder builder = new AnimatorSetBuilder();
+ AllAppsTransitionController allAppsController = mLauncher.getAllAppsController();
+ final float pullbackDistance = mLauncher.getDeviceProfile().allAppsIconSizePx / 2;
+ Animator allAppsProgress = ObjectAnimator.ofFloat(allAppsController, ALL_APPS_PROGRESS,
+ -pullbackDistance / allAppsController.getShiftRange());
+ allAppsProgress.setInterpolator(PULLBACK_INTERPOLATOR);
+ builder.play(allAppsProgress);
+ // Slightly fade out all apps content to further distinguish from scrolling.
+ builder.setInterpolator(AnimatorSetBuilder.ANIM_ALL_APPS_FADE, Interpolators
+ .mapToProgress(PULLBACK_INTERPOLATOR, 0, 0.5f));
+ AnimationConfig config = new AnimationConfig();
+ config.duration = accuracy;
+ allAppsController.setAlphas(mToState.getVisibleElements(mLauncher), config, builder);
+ anim = builder.build();
+ }
+ anim.setDuration(accuracy);
+ mCurrentAnimation = AnimatorPlaybackController.wrap(anim, accuracy, this::clearState);
+ return -1 / getShiftRange();
+ }
+
+ @Override
+ public void onDragStart(boolean start) {
+ super.onDragStart(start);
+ mStartContainerType = LauncherLogProto.ContainerType.NAVBAR;
+ }
+
+ @Override
+ public void onDragEnd(float velocity, boolean fling) {
+ final int logAction = fling ? Touch.FLING : Touch.SWIPE;
+ float interpolatedProgress = PULLBACK_INTERPOLATOR.getInterpolation(
+ mCurrentAnimation.getProgressFraction());
+ if (interpolatedProgress >= SUCCESS_TRANSITION_PROGRESS || velocity < 0 && fling) {
+ mLauncher.getStateManager().goToState(mToState, true,
+ () -> onSwipeInteractionCompleted(mToState, logAction));
+ } else {
+ // Quickly return to the state we came from (we didn't move far).
+ AnimatorPlaybackController anim = mLauncher.getStateManager()
+ .createAnimationToNewWorkspace(mFromState, 80);
+ anim.setEndAction(() -> onSwipeInteractionCompleted(mFromState, logAction));
+ anim.start();
+ }
+ mCurrentAnimation.dispatchOnCancel();
+ }
+
+ @Override
+ protected int getDirectionForLog() {
+ return LauncherLogProto.Action.Direction.UP;
+ }
+
+ @Override
+ protected boolean goingBetweenNormalAndOverview(LauncherState fromState,
+ LauncherState toState) {
+ // We don't want to create an atomic animation to/from overview.
+ return false;
+ }
+
+ @Override
+ protected int getLogContainerTypeForNormalState() {
+ return LauncherLogProto.ContainerType.NAVBAR;
+ }
+}
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/OverviewToAllAppsTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/OverviewToAllAppsTouchController.java
similarity index 97%
rename from quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/OverviewToAllAppsTouchController.java
rename to quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/OverviewToAllAppsTouchController.java
index a069ed5..82ab34b 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/OverviewToAllAppsTouchController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/OverviewToAllAppsTouchController.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.launcher3.uioverrides;
+package com.android.launcher3.uioverrides.touchcontrollers;
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.NORMAL;
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/PortraitOverviewStateTouchHelper.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitOverviewStateTouchHelper.java
similarity index 94%
rename from quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/PortraitOverviewStateTouchHelper.java
rename to quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitOverviewStateTouchHelper.java
index eead4c8..5337c39 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/PortraitOverviewStateTouchHelper.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitOverviewStateTouchHelper.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.launcher3.uioverrides;
+package com.android.launcher3.uioverrides.touchcontrollers;
-import static com.android.launcher3.uioverrides.PortraitStatesTouchController.isTouchOverHotseat;
+import static com.android.launcher3.uioverrides.touchcontrollers.PortraitStatesTouchController.isTouchOverHotseat;
import android.view.MotionEvent;
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
new file mode 100644
index 0000000..91a31dd
--- /dev/null
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.uioverrides.touchcontrollers;
+
+import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.LauncherState.QUICK_SWITCH;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_ALL_APPS_FADE;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_FADE;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_SCALE;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_TRANSLATE_Y;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_VERTICAL_PROGRESS;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_FADE;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_TRANSLATE;
+import static com.android.launcher3.anim.Interpolators.ACCEL_2;
+import static com.android.launcher3.anim.Interpolators.DEACCEL_2;
+import static com.android.launcher3.anim.Interpolators.INSTANT;
+import static com.android.launcher3.anim.Interpolators.LINEAR;
+
+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.AnimatorSetBuilder;
+import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.touch.AbstractStateChangeTouchController;
+import com.android.launcher3.touch.SwipeDetector;
+import com.android.launcher3.userevent.nano.LauncherLogProto;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
+import com.android.quickstep.views.RecentsView;
+import com.android.quickstep.views.TaskView;
+
+import androidx.annotation.Nullable;
+
+/**
+ * Handles quick switching to a recent task from the home screen.
+ */
+public class QuickSwitchTouchController extends AbstractStateChangeTouchController {
+
+ private @Nullable TaskView mTaskToLaunch;
+
+ public QuickSwitchTouchController(Launcher launcher) {
+ super(launcher, SwipeDetector.HORIZONTAL);
+ }
+
+ @Override
+ protected boolean canInterceptTouch(MotionEvent ev) {
+ if (mCurrentAnimation != null) {
+ return true;
+ }
+ if (!mLauncher.isInState(LauncherState.NORMAL)) {
+ return false;
+ }
+ if ((ev.getEdgeFlags() & Utilities.EDGE_NAV_BAR) == 0) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ protected LauncherState getTargetState(LauncherState fromState, boolean isDragTowardPositive) {
+ return isDragTowardPositive ? QUICK_SWITCH : NORMAL;
+ }
+
+ @Override
+ public void onDragStart(boolean start) {
+ super.onDragStart(start);
+ mStartContainerType = LauncherLogProto.ContainerType.NAVBAR;
+ mTaskToLaunch = mLauncher.<RecentsView>getOverviewPanel().getTaskViewAt(0);
+ }
+
+ @Override
+ protected void onSwipeInteractionCompleted(LauncherState targetState, int logAction) {
+ super.onSwipeInteractionCompleted(targetState, logAction);
+ mTaskToLaunch = null;
+ }
+
+ @Override
+ protected float initCurrentAnimation(int animComponents) {
+ AnimatorSetBuilder animatorSetBuilder = new AnimatorSetBuilder();
+ setupInterpolators(animatorSetBuilder);
+ long accuracy = (long) (getShiftRange() * 2);
+ mCurrentAnimation = mLauncher.getStateManager().createAnimationToNewWorkspace(mToState,
+ animatorSetBuilder, accuracy, this::clearState, LauncherStateManager.ANIM_ALL);
+ mCurrentAnimation.getAnimationPlayer().addUpdateListener(valueAnimator -> {
+ updateFullscreenProgress((Float) valueAnimator.getAnimatedValue());
+ });
+ return 1 / getShiftRange();
+ }
+
+ private void setupInterpolators(AnimatorSetBuilder animatorSetBuilder) {
+ animatorSetBuilder.setInterpolator(ANIM_WORKSPACE_FADE, DEACCEL_2);
+ animatorSetBuilder.setInterpolator(ANIM_ALL_APPS_FADE, DEACCEL_2);
+ if (FeatureFlags.SWIPE_HOME.get()) {
+ // Overview lives to the left of workspace, so translate down later than over
+ animatorSetBuilder.setInterpolator(ANIM_WORKSPACE_TRANSLATE, ACCEL_2);
+ animatorSetBuilder.setInterpolator(ANIM_VERTICAL_PROGRESS, ACCEL_2);
+ animatorSetBuilder.setInterpolator(ANIM_OVERVIEW_SCALE, ACCEL_2);
+ animatorSetBuilder.setInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, ACCEL_2);
+ animatorSetBuilder.setInterpolator(ANIM_OVERVIEW_FADE, INSTANT);
+ } else {
+ animatorSetBuilder.setInterpolator(ANIM_WORKSPACE_TRANSLATE, LINEAR);
+ animatorSetBuilder.setInterpolator(ANIM_VERTICAL_PROGRESS, LINEAR);
+ }
+ }
+
+ @Override
+ protected void updateProgress(float progress) {
+ super.updateProgress(progress);
+ updateFullscreenProgress(progress);
+ }
+
+ private void updateFullscreenProgress(float progress) {
+ if (mTaskToLaunch != null) {
+ mTaskToLaunch.setFullscreenProgress(progress);
+ }
+ }
+
+ @Override
+ protected float getShiftRange() {
+ return mLauncher.getDeviceProfile().widthPx / 2f;
+ }
+
+ @Override
+ protected int getLogContainerTypeForNormalState() {
+ return LauncherLogProto.ContainerType.NAVBAR;
+ }
+
+ @Override
+ protected int getDirectionForLog() {
+ return Utilities.isRtl(mLauncher.getResources()) ? Direction.LEFT : Direction.RIGHT;
+ }
+}
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/TaskViewTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
similarity index 97%
rename from quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/TaskViewTouchController.java
rename to quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
index fb1828b..62d954b 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/TaskViewTouchController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.launcher3.uioverrides;
+package com.android.launcher3.uioverrides.touchcontrollers;
import static com.android.launcher3.AbstractFloatingView.TYPE_ACCESSIBLE;
import static com.android.launcher3.Utilities.SINGLE_FRAME_MS;
@@ -38,7 +38,7 @@
import com.android.launcher3.util.PendingAnimation;
import com.android.launcher3.util.TouchController;
import com.android.launcher3.views.BaseDragLayer;
-import com.android.quickstep.OverviewInteractionState;
+import com.android.quickstep.SysUINavigationMode;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
@@ -123,8 +123,7 @@
if (mRecentsView.isTaskViewVisible(view) && mActivity.getDragLayer()
.isEventOverView(view, ev)) {
mTaskBeingDragged = view;
- if (!OverviewInteractionState.INSTANCE.get(mActivity)
- .isSwipeUpGestureEnabled()) {
+ if (!SysUINavigationMode.INSTANCE.get(mActivity).getMode().hasGestures) {
// Don't allow swipe down to open if we don't support swipe up
// to enter overview.
directionsToDetectScroll = SwipeDetector.DIRECTION_POSITIVE;
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/AssistantTouchConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/AssistantTouchConsumer.java
index c00b4dc..7c0791e 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/AssistantTouchConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/AssistantTouchConsumer.java
@@ -21,6 +21,11 @@
import static android.view.MotionEvent.ACTION_MOVE;
import static android.view.MotionEvent.ACTION_POINTER_UP;
import static android.view.MotionEvent.ACTION_UP;
+import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch.SWIPE;
+import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch.SWIPE_NOOP;
+import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction.UPLEFT;
+import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction.UPRIGHT;
+import static com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType.NAVBAR;
import android.animation.ValueAnimator;
import android.content.Context;
@@ -32,6 +37,7 @@
import android.util.Log;
import android.view.MotionEvent;
import com.android.launcher3.anim.Interpolators;
+import com.android.launcher3.logging.UserEventDispatcher;
import com.android.quickstep.util.MotionPauseDetector;
import com.android.systemui.shared.recents.ISystemUiProxy;
import com.android.launcher3.R;
@@ -66,6 +72,7 @@
private long mDragTime;
private float mLastProgress;
private int mState;
+ private int mDirection;
private final float mDistThreshold;
private final long mTimeThreshold;
@@ -74,10 +81,12 @@
private final MotionPauseDetector mMotionPauseDetector;
private final ISystemUiProxy mSysUiProxy;
private final InputConsumer mConsumerDelegate;
+ private final Context mContext;
public AssistantTouchConsumer(Context context, ISystemUiProxy systemUiProxy,
InputConsumer delegate) {
final Resources res = context.getResources();
+ mContext = context;
mSysUiProxy = systemUiProxy;
mConsumerDelegate = delegate;
mMotionPauseDetector = new MotionPauseDetector(context);
@@ -151,6 +160,7 @@
// Determine if angle is larger than threshold for assistant detection
float angle = (float) Math.toDegrees(
Math.atan2(mDownPos.y - mLastPos.y, mDownPos.x - mLastPos.x));
+ mDirection = angle > 90 ? UPLEFT : UPRIGHT;
angle = angle > 90 ? 180 - angle : angle;
if (angle > mAngleThreshold) {
mState = STATE_ASSISTANT_ACTIVE;
@@ -170,7 +180,7 @@
// Movement
mDistance = (float) Math.hypot(mLastPos.x - mStartDragPos.x,
mLastPos.y - mStartDragPos.y);
- mMotionPauseDetector.addPosition(mDistance, 0);
+ mMotionPauseDetector.addPosition(mDistance, 0, ev.getEventTime());
if (mDistance >= 0) {
final long diff = SystemClock.uptimeMillis() - mDragTime;
mTimeFraction = Math.min(diff * 1f / mTimeThreshold, 1);
@@ -184,9 +194,12 @@
if (mState != STATE_DELEGATE_ACTIVE && !mLaunchedAssistant) {
ValueAnimator animator = ValueAnimator.ofFloat(mLastProgress, 0)
.setDuration(RETRACT_ANIMATION_DURATION_MS);
+ UserEventDispatcher.newInstance(mContext).logActionOnContainer(
+ SWIPE_NOOP, mDirection, NAVBAR);
animator.addUpdateListener(valueAnimator -> {
float progress = (float) valueAnimator.getAnimatedValue();
try {
+
mSysUiProxy.onAssistantProgress(progress);
} catch (RemoteException e) {
Log.w(TAG, "Failed to send SysUI start/send assistant progress: "
@@ -211,8 +224,9 @@
mLastProgress = progress;
try {
mSysUiProxy.onAssistantProgress(progress);
-
if (mDistance >= mDistThreshold && mTimeFraction >= 1) {
+ UserEventDispatcher.newInstance(mContext).logActionOnContainer(
+ SWIPE, mDirection, NAVBAR);
mSysUiProxy.startAssistant(new Bundle());
mLaunchedAssistant = true;
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityControllerHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityControllerHelper.java
index ef46b3b..21e98f2 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityControllerHelper.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityControllerHelper.java
@@ -16,6 +16,7 @@
package com.android.quickstep;
import static com.android.launcher3.anim.Interpolators.LINEAR;
+import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
import static com.android.quickstep.views.RecentsView.CONTENT_ALPHA;
import android.animation.Animator;
@@ -59,7 +60,8 @@
@Override
public int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context, Rect outRect) {
LayoutUtils.calculateFallbackTaskSize(context, dp, outRect);
- if (dp.isVerticalBarLayout()) {
+ if (dp.isVerticalBarLayout()
+ && SysUINavigationMode.INSTANCE.get(context).getMode() != NO_BUTTON) {
Rect targetInsets = dp.getInsets();
int hotseatInset = dp.isSeascape() ? targetInsets.left : targetInsets.right;
return dp.hotseatBarSizePx + hotseatInset;
@@ -73,6 +75,11 @@
// TODO:
}
+ @Override
+ public void onAssistantVisibilityChanged(float visibility) {
+ // TODO:
+ }
+
@NonNull
@Override
public HomeAnimationFactory prepareHomeUI(RecentsActivity activity) {
@@ -185,7 +192,11 @@
@Override
public int getContainerType() {
- return LauncherLogProto.ContainerType.SIDELOADED_LAUNCHER;
+ RecentsActivity activity = getCreatedActivity();
+ boolean visible = activity != null && activity.isStarted() && activity.hasWindowFocus();
+ return visible
+ ? LauncherLogProto.ContainerType.SIDELOADED_LAUNCHER
+ : LauncherLogProto.ContainerType.APP;
}
@Override
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java
index 279b83c..766f484 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java
@@ -16,7 +16,6 @@
package com.android.quickstep;
import static android.view.View.TRANSLATION_Y;
-
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
import static com.android.launcher3.LauncherState.NORMAL;
@@ -25,6 +24,7 @@
import static com.android.launcher3.allapps.AllAppsTransitionController.SPRING_STIFFNESS;
import static com.android.launcher3.anim.Interpolators.DEACCEL_3;
import static com.android.launcher3.anim.Interpolators.LINEAR;
+import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -39,16 +39,13 @@
import android.view.View;
import android.view.animation.Interpolator;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.annotation.UiThread;
-
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherInitListener;
import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherStateManager;
+import com.android.launcher3.Workspace;
import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.allapps.DiscoveryBounce;
import com.android.launcher3.anim.AnimatorPlaybackController;
@@ -67,6 +64,10 @@
import java.util.function.BiPredicate;
import java.util.function.Consumer;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.UiThread;
+
/**
* {@link ActivityControlHelper} for the in-launcher recents.
*/
@@ -75,7 +76,8 @@
@Override
public int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context, Rect outRect) {
LayoutUtils.calculateLauncherTaskSize(context, dp, outRect);
- if (dp.isVerticalBarLayout()) {
+ if (dp.isVerticalBarLayout()
+ && SysUINavigationMode.INSTANCE.get(context).getMode() != NO_BUTTON) {
Rect targetInsets = dp.getInsets();
int hotseatInset = dp.isSeascape() ? targetInsets.left : targetInsets.right;
return dp.hotseatBarSizePx + hotseatInset;
@@ -97,6 +99,14 @@
DiscoveryBounce.showForOverviewIfNeeded(activity);
}
+ @Override
+ public void onAssistantVisibilityChanged(float visibility) {
+ Launcher launcher = getCreatedActivity();
+ if (launcher != null) {
+ launcher.setQuickSearchBarAlpha(1f - visibility);
+ }
+ }
+
@NonNull
@Override
public HomeAnimationFactory prepareHomeUI(Launcher activity) {
@@ -114,8 +124,7 @@
final Rect iconLocation = new Rect();
final FloatingIconView floatingView = workspaceView == null ? null
: FloatingIconView.getFloatingIconView(activity, workspaceView,
- true /* hideOriginal */, false /* useDrawableAsIs */,
- activity.getDeviceProfile().getAspectRatioWithInsets(), iconLocation, null);
+ true /* hideOriginal */, iconLocation, false /* isOpening */, null /* recycle */);
return new HomeAnimationFactory() {
@Nullable
@@ -305,7 +314,7 @@
// starting to line up the side pages during swipe up)
float prevRvScale = recentsView.getScaleX();
float prevRvTransY = recentsView.getTranslationY();
- float targetRvScale = endState.getOverviewScaleAndTranslationY(launcher)[0];
+ float targetRvScale = endState.getOverviewScaleAndTranslation(launcher).scale;
SCALE_PROPERTY.set(recentsView, targetRvScale);
recentsView.setTranslationY(0);
ClipAnimationHelper clipHelper = new ClipAnimationHelper(launcher);
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/OtherActivityInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/OtherActivityInputConsumer.java
index c8dcf80..aada84f 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/OtherActivityInputConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/OtherActivityInputConsumer.java
@@ -24,6 +24,7 @@
import static com.android.launcher3.util.RaceConditionTracker.ENTER;
import static com.android.launcher3.util.RaceConditionTracker.EXIT;
import static com.android.launcher3.Utilities.EDGE_NAV_BAR;
+import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
import static com.android.quickstep.TouchInteractionService.TOUCH_INTERACTION_LOG;
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
@@ -55,6 +56,7 @@
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.BackgroundExecutor;
import com.android.systemui.shared.system.InputConsumerController;
+import com.android.systemui.shared.system.InputMonitorCompat;
import com.android.systemui.shared.system.NavigationBarCompat;
import com.android.systemui.shared.system.WindowManagerWrapper;
@@ -80,6 +82,7 @@
private final TaskOverlayFactory mTaskOverlayFactory;
private final InputConsumerController mInputConsumer;
private final SwipeSharedState mSwipeSharedState;
+ private final InputMonitorCompat mInputMonitorCompat;
private final int mDisplayRotation;
private final Rect mStableInsets = new Rect();
@@ -117,7 +120,7 @@
boolean isDeferredDownTarget, OverviewCallbacks overviewCallbacks,
TaskOverlayFactory taskOverlayFactory, InputConsumerController inputConsumer,
Consumer<OtherActivityInputConsumer> onCompleteCallback,
- SwipeSharedState swipeSharedState) {
+ SwipeSharedState swipeSharedState, InputMonitorCompat inputMonitorCompat) {
super(base);
mMainThreadHandler = new Handler(Looper.getMainLooper());
@@ -128,6 +131,7 @@
mMotionPauseDetector = new MotionPauseDetector(base);
mOnCompleteCallback = onCompleteCallback;
mVelocityTracker = VelocityTracker.obtain();
+ mInputMonitorCompat = inputMonitorCompat;
mActivityControlHelper = activityControl;
boolean continuingPreviousGesture = swipeSharedState.getActiveListener() != null;
@@ -251,7 +255,8 @@
float orthogonalDisplacement = !isLandscape
? ev.getX() - mDownPos.x
: ev.getY() - mDownPos.y;
- mMotionPauseDetector.addPosition(displacement, orthogonalDisplacement);
+ mMotionPauseDetector.addPosition(displacement, orthogonalDisplacement,
+ ev.getEventTime());
}
}
break;
@@ -274,6 +279,7 @@
if (mInteractionHandler == null) {
return;
}
+ mInputMonitorCompat.pilferPointers();
mOverviewCallbacks.closeAllWindows();
ActivityManagerWrapper.getInstance().closeSystemWindows(
@@ -284,11 +290,13 @@
}
private boolean isNavBarOnRight() {
- return mDisplayRotation == Surface.ROTATION_90 && mStableInsets.right > 0;
+ return SysUINavigationMode.INSTANCE.get(getBaseContext()).getMode() != NO_BUTTON
+ && mDisplayRotation == Surface.ROTATION_90 && mStableInsets.right > 0;
}
private boolean isNavBarOnLeft() {
- return mDisplayRotation == Surface.ROTATION_270 && mStableInsets.left > 0;
+ return SysUINavigationMode.INSTANCE.get(getBaseContext()).getMode() != NO_BUTTON
+ && mDisplayRotation == Surface.ROTATION_270 && mStableInsets.left > 0;
}
private void startTouchTrackingForWindowAnimation(long touchTimeMs) {
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewInputConsumer.java
index cda2a1a..3ebe968 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewInputConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewInputConsumer.java
@@ -19,7 +19,6 @@
import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_MOVE;
import static android.view.MotionEvent.ACTION_UP;
-
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
import static com.android.quickstep.TouchInteractionService.TOUCH_INTERACTION_LOG;
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
@@ -46,7 +45,7 @@
private final BaseDragLayer mTarget;
private final int[] mLocationOnScreen = new int[2];
private final PointF mDownPos = new PointF();
- private final int mTouchSlop;
+ private final int mTouchSlopSquared;
private final boolean mStartingInActivityBounds;
@@ -56,7 +55,8 @@
OverviewInputConsumer(T activity, boolean startingInActivityBounds) {
mActivity = activity;
mTarget = activity.getDragLayer();
- mTouchSlop = ViewConfiguration.get(mActivity).getScaledTouchSlop();
+ int touchSlop = ViewConfiguration.get(mActivity).getScaledTouchSlop();
+ mTouchSlopSquared = touchSlop * touchSlop;
mStartingInActivityBounds = startingInActivityBounds;
}
@@ -88,10 +88,11 @@
false /* closeActiveWindows */);
break;
case ACTION_MOVE: {
- float displacement = mActivity.getDeviceProfile().isLandscape ?
- ev.getX() - mDownPos.x : ev.getY() - mDownPos.y;
- if (Math.abs(displacement) >= mTouchSlop) {
- // Start tracking only when mTouchSlop is crossed.
+ float x = ev.getX() - mDownPos.x;
+ float y = ev.getY() - mDownPos.y;
+ double hypotSquared = x * x + y * y;
+ if (hypotSquared >= mTouchSlopSquared) {
+ // Start tracking only when touch slop is crossed.
startTouchTracking(ev, true /* updateLocationOffset */,
true /* closeActiveWindows */);
}
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 8fe0461..87ae091 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
@@ -18,7 +18,7 @@
import static android.view.MotionEvent.ACTION_DOWN;
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
-import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_INPUT_CHANNEL;
+import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_INPUT_MONITOR;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY;
import android.annotation.TargetApi;
@@ -29,32 +29,41 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.res.Resources;
+import android.graphics.Point;
+import android.graphics.RectF;
import android.graphics.Region;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManager.DisplayListener;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Looper;
import android.os.Process;
+import android.os.RemoteException;
import android.util.Log;
-import android.util.Pair;
import android.view.Choreographer;
+import android.view.Display;
import android.view.InputEvent;
import android.view.MotionEvent;
+import android.view.Surface;
+import android.view.WindowManager;
import com.android.launcher3.MainThreadExecutor;
import com.android.launcher3.Utilities;
import com.android.launcher3.compat.UserManagerCompat;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.logging.EventLogArray;
+import com.android.launcher3.logging.UserEventDispatcher;
import com.android.launcher3.util.LooperExecutor;
import com.android.launcher3.util.UiThreadHelper;
+import com.android.quickstep.SysUINavigationMode.Mode;
+import com.android.quickstep.SysUINavigationMode.NavigationModeChangeListener;
import com.android.systemui.shared.recents.IOverviewProxy;
import com.android.systemui.shared.recents.ISystemUiProxy;
import com.android.systemui.shared.system.ActivityManagerWrapper;
-import com.android.systemui.shared.system.InputChannelCompat;
-import com.android.systemui.shared.system.InputChannelCompat.InputEventDispatcher;
import com.android.systemui.shared.system.InputChannelCompat.InputEventReceiver;
import com.android.systemui.shared.system.InputConsumerController;
+import com.android.systemui.shared.system.InputMonitorCompat;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -65,12 +74,16 @@
* Service connected by system-UI for handling touch interaction.
*/
@TargetApi(Build.VERSION_CODES.O)
-public class TouchInteractionService extends Service {
+public class TouchInteractionService extends Service implements
+ NavigationModeChangeListener, DisplayListener {
public static final MainThreadExecutor MAIN_THREAD_EXECUTOR = new MainThreadExecutor();
public static final LooperExecutor BACKGROUND_EXECUTOR =
new LooperExecutor(UiThreadHelper.getBackgroundLooper());
+ private static final String NAVBAR_VERTICAL_SIZE = "navigation_bar_frame_height";
+ private static final String NAVBAR_HORIZONTAL_SIZE = "navigation_bar_frame_width";
+
public static final EventLogArray TOUCH_INTERACTION_LOG =
new EventLogArray("touch_interaction_log", 40);
@@ -85,16 +98,12 @@
public void onInitialize(Bundle bundle) {
mISystemUiProxy = ISystemUiProxy.Stub
.asInterface(bundle.getBinder(KEY_EXTRA_SYSUI_PROXY));
+ MAIN_THREAD_EXECUTOR.execute(TouchInteractionService.this::initInputMonitor);
runWhenUserUnlocked(() -> {
mRecentsModel.setSystemUiProxy(mISystemUiProxy);
mRecentsModel.onInitializeSystemUI(bundle);
mOverviewInteractionState.setSystemUiProxy(mISystemUiProxy);
});
-
- disposeEventHandlers();
- mInputEventReceiver = InputChannelCompat.fromBundle(bundle, KEY_EXTRA_INPUT_CHANNEL,
- Looper.getMainLooper(), mMainChoreographer,
- TouchInteractionService.this::onInputEvent);
}
@Override
@@ -125,6 +134,22 @@
mAssistantAvailable = available;
}
+ @Override
+ public void onAssistantVisibilityChanged(float visibility) {
+ MAIN_THREAD_EXECUTOR.execute(() -> {
+ mOverviewComponentObserver.getActivityControlHelper()
+ .onAssistantVisibilityChanged(visibility);
+ });
+ }
+
+ public void onBackAction(boolean completed, int downX, int downY, boolean isButton,
+ boolean gestureSwipeLeft) {
+ final ActivityControlHelper activityControl =
+ mOverviewComponentObserver.getActivityControlHelper();
+ UserEventDispatcher.newInstance(getBaseContext()).logActionBack(completed, downX, downY,
+ isButton, gestureSwipeLeft, activityControl.getContainerType());
+ }
+
/** Deprecated methods **/
public void onQuickStep(MotionEvent motionEvent) { }
@@ -137,28 +162,10 @@
public void onPreMotionEvent(int downHitTarget) { }
public void onMotionEvent(MotionEvent ev) {
- if (mDeprecatedDispatcher == null) {
- ev.recycle();
- } else {
- mDeprecatedDispatcher.dispatch(ev);
- }
+ ev.recycle();
}
- public void onBind(ISystemUiProxy iSystemUiProxy) {
- mISystemUiProxy = iSystemUiProxy;
- runWhenUserUnlocked(() -> {
- mRecentsModel.setSystemUiProxy(mISystemUiProxy);
- mOverviewInteractionState.setSystemUiProxy(mISystemUiProxy);
- });
-
- // On Bind is received before onInitialize which will dispose these handlers
- disposeEventHandlers();
- Pair<InputEventDispatcher, InputEventReceiver> pair = InputChannelCompat.createPair(
- "sysui-callbacks", Looper.getMainLooper(), mMainChoreographer,
- TouchInteractionService.this::onInputEvent);
- mDeprecatedDispatcher = pair.first;
- mInputEventReceiver = pair.second;
- }
+ public void onBind(ISystemUiProxy iSystemUiProxy) { }
};
private static boolean sConnected = false;
@@ -191,13 +198,17 @@
}
};
+ private InputConsumer mUncheckedConsumer = InputConsumer.NO_OP;
private InputConsumer mConsumer = InputConsumer.NO_OP;
private Choreographer mMainChoreographer;
- private InputEventReceiver mInputEventReceiver;
private Region mActiveNavBarRegion = new Region();
- private InputEventDispatcher mDeprecatedDispatcher;
+ private InputMonitorCompat mInputMonitorCompat;
+ private InputEventReceiver mInputEventReceiver;
+ private Mode mMode = Mode.THREE_BUTTONS;
+ private int mDefaultDisplayId;
+ private final RectF mSwipeTouchRegion = new RectF();
@Override
public void onCreate() {
@@ -215,10 +226,112 @@
mIsUserUnlocked = false;
registerReceiver(mUserUnlockedReceiver, new IntentFilter(Intent.ACTION_USER_UNLOCKED));
}
+ onNavigationModeChanged(SysUINavigationMode.INSTANCE.get(this).addModeChangeListener(this));
+ mDefaultDisplayId = getSystemService(WindowManager.class).getDefaultDisplay()
+ .getDisplayId();
sConnected = true;
}
+ private void disposeEventHandlers() {
+ if (mInputEventReceiver != null) {
+ mInputEventReceiver.dispose();
+ mInputEventReceiver = null;
+ }
+ if (mInputMonitorCompat != null) {
+ mInputMonitorCompat.dispose();
+ mInputMonitorCompat = null;
+ }
+ }
+
+ private void initInputMonitor() {
+ if (!mMode.hasGestures || mISystemUiProxy == null) {
+ return;
+ }
+ disposeEventHandlers();
+
+ try {
+ mInputMonitorCompat = InputMonitorCompat.fromBundle(mISystemUiProxy
+ .monitorGestureInput("swipe-up", mDefaultDisplayId), KEY_EXTRA_INPUT_MONITOR);
+ mInputEventReceiver = mInputMonitorCompat.getInputReceiver(Looper.getMainLooper(),
+ mMainChoreographer, this::onInputEvent);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to create input monitor", e);
+ }
+ initTouchBounds();
+ }
+
+ private int getNavbarSize(String resName) {
+ int frameSize;
+ Resources res = getResources();
+ int frameSizeResID = res.getIdentifier(resName, "dimen", "android");
+ if (frameSizeResID != 0) {
+ frameSize = res.getDimensionPixelSize(frameSizeResID);
+ } else {
+ frameSize = Utilities.pxFromDp(48, res.getDisplayMetrics());
+ }
+ return frameSize;
+ }
+
+ private void initTouchBounds() {
+ if (!mMode.hasGestures) {
+ return;
+ }
+
+ Display defaultDisplay = getSystemService(WindowManager.class).getDefaultDisplay();
+ Point realSize = new Point();
+ defaultDisplay.getRealSize(realSize);
+ mSwipeTouchRegion.set(0, 0, realSize.x, realSize.y);
+ if (mMode == Mode.NO_BUTTON) {
+ mSwipeTouchRegion.top = mSwipeTouchRegion.bottom - getNavbarSize(NAVBAR_VERTICAL_SIZE);
+ } else {
+ switch (defaultDisplay.getRotation()) {
+ case Surface.ROTATION_90:
+ mSwipeTouchRegion.left = mSwipeTouchRegion.right
+ - getNavbarSize(NAVBAR_HORIZONTAL_SIZE);
+ break;
+ case Surface.ROTATION_270:
+ mSwipeTouchRegion.right = mSwipeTouchRegion.left
+ + getNavbarSize(NAVBAR_HORIZONTAL_SIZE);
+ break;
+ default:
+ mSwipeTouchRegion.top = mSwipeTouchRegion.bottom
+ - getNavbarSize(NAVBAR_VERTICAL_SIZE);
+ }
+ }
+ }
+
+ @Override
+ public void onNavigationModeChanged(Mode newMode) {
+ if (mMode.hasGestures != newMode.hasGestures) {
+ if (newMode.hasGestures) {
+ getSystemService(DisplayManager.class).registerDisplayListener(
+ this, MAIN_THREAD_EXECUTOR.getHandler());
+ } else {
+ getSystemService(DisplayManager.class).unregisterDisplayListener(this);
+ }
+ }
+ mMode = newMode;
+
+ disposeEventHandlers();
+ initInputMonitor();
+ }
+
+ @Override
+ public void onDisplayAdded(int i) { }
+
+ @Override
+ public void onDisplayRemoved(int i) { }
+
+ @Override
+ public void onDisplayChanged(int displayId) {
+ if (displayId != mDefaultDisplayId) {
+ return;
+ }
+
+ initTouchBounds();
+ }
+
private void initWhenUserUnlocked() {
mIsUserUnlocked = true;
@@ -260,20 +373,15 @@
mOverviewComponentObserver.onDestroy();
}
disposeEventHandlers();
+ if (mMode.hasGestures) {
+ getSystemService(DisplayManager.class).unregisterDisplayListener(this);
+ }
+
sConnected = false;
Utilities.unregisterReceiverSafely(this, mUserUnlockedReceiver);
- super.onDestroy();
- }
+ SysUINavigationMode.INSTANCE.get(this).removeModeChangeListener(this);
- private void disposeEventHandlers() {
- if (mInputEventReceiver != null) {
- mInputEventReceiver.dispose();
- mInputEventReceiver = null;
- }
- if (mDeprecatedDispatcher != null) {
- mDeprecatedDispatcher.dispose();
- mDeprecatedDispatcher = null;
- }
+ super.onDestroy();
}
@Override
@@ -290,12 +398,17 @@
MotionEvent event = (MotionEvent) ev;
TOUCH_INTERACTION_LOG.addLog("onMotionEvent", event.getActionMasked());
if (event.getAction() == ACTION_DOWN) {
- boolean useSharedState = mConsumer.isActive();
- mConsumer.onConsumerAboutToBeSwitched();
- mConsumer = newConsumer(useSharedState, event);
- TOUCH_INTERACTION_LOG.addLog("setInputConsumer", mConsumer.getType());
+ if (mSwipeTouchRegion.contains(event.getX(), event.getY())) {
+ boolean useSharedState = mConsumer.isActive();
+ mConsumer.onConsumerAboutToBeSwitched();
+ mConsumer = newConsumer(useSharedState, event);
+ TOUCH_INTERACTION_LOG.addLog("setInputConsumer", mConsumer.getType());
+ mUncheckedConsumer = mConsumer;
+ } else {
+ mUncheckedConsumer = InputConsumer.NO_OP;
+ }
}
- mConsumer.onMotionEvent(event);
+ mUncheckedConsumer.onMotionEvent(event);
}
private InputConsumer newConsumer(boolean useSharedState, MotionEvent event) {
@@ -315,8 +428,8 @@
mOverviewComponentObserver.getActivityControlHelper();
if (runningTaskInfo == null && !mSwipeSharedState.goingToLauncher) {
return InputConsumer.NO_OP;
- } else if (mAssistantAvailable && mOverviewInteractionState.isSwipeUpGestureEnabled()
- && FeatureFlags.ENABLE_ASSISTANT_GESTURE.get()
+ } else if (mAssistantAvailable
+ && SysUINavigationMode.INSTANCE.get(this).getMode() == Mode.NO_BUTTON
&& AssistantTouchConsumer.withinTouchRegion(this, event)) {
return new AssistantTouchConsumer(this, mISystemUiProxy, !activityControl.isResumed()
? createOtherActivityInputConsumer(event, runningTaskInfo) : null);
@@ -338,7 +451,7 @@
return new OtherActivityInputConsumer(this, runningTaskInfo, mRecentsModel,
mOverviewComponentObserver.getOverviewIntent(), activityControl,
shouldDefer, mOverviewCallbacks, mTaskOverlayFactory, mInputConsumer,
- this::onConsumerInactive, mSwipeSharedState);
+ this::onConsumerInactive, mSwipeSharedState, mInputMonitorCompat);
}
/**
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java
index e8d4c19..b1db780 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java
@@ -28,6 +28,7 @@
import static com.android.launcher3.config.FeatureFlags.SWIPE_HOME;
import static com.android.launcher3.util.RaceConditionTracker.ENTER;
import static com.android.launcher3.util.RaceConditionTracker.EXIT;
+import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION;
import static com.android.quickstep.ActivityControlHelper.AnimationFactory.ShelfAnimState.HIDE;
import static com.android.quickstep.ActivityControlHelper.AnimationFactory.ShelfAnimState.PEEK;
import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
@@ -202,6 +203,11 @@
private static final long SHELF_ANIM_DURATION = 120;
+ /**
+ * Used as the page index for logging when we return to the last task at the end of the gesture.
+ */
+ private static final int LOG_NO_OP_PAGE_INDEX = -1;
+
private final ClipAnimationHelper mClipAnimationHelper;
private final ClipAnimationHelper.TransformParams mTransformParams;
@@ -244,6 +250,7 @@
private boolean mPassedOverviewThreshold;
private boolean mGestureStarted;
private int mLogAction = Touch.SWIPE;
+ private int mLogDirection = Direction.UP;
private final RecentsAnimationWrapper mRecentsAnimationWrapper;
@@ -691,6 +698,12 @@
setStateOnUiThread(STATE_GESTURE_COMPLETED);
mLogAction = isFling ? Touch.FLING : Touch.SWIPE;
+ boolean isVelocityVertical = Math.abs(velocity.y) > Math.abs(velocity.x);
+ if (isVelocityVertical) {
+ mLogDirection = velocity.y < 0 ? Direction.UP : Direction.DOWN;
+ } else {
+ mLogDirection = velocity.x < 0 ? Direction.LEFT : Direction.RIGHT;
+ }
handleNormalGestureEnd(endVelocity, isFling, velocity);
}
@@ -823,19 +836,15 @@
// We probably never received an animation controller, skip logging.
return;
}
- boolean toLauncher = endTarget.isLauncher;
- final int direction;
- if (dp.isVerticalBarLayout()) {
- direction = (dp.isSeascape() ^ toLauncher) ? Direction.LEFT : Direction.RIGHT;
- } else {
- direction = toLauncher ? Direction.UP : Direction.DOWN;
- }
+ int pageIndex = endTarget == LAST_TASK
+ ? LOG_NO_OP_PAGE_INDEX
+ : mRecentsView.getNextPage();
UserEventDispatcher.newInstance(mContext).logStateChangeAction(
- mLogAction, direction,
+ mLogAction, mLogDirection,
ContainerType.NAVBAR, ContainerType.APP,
endTarget.containerType,
- 0);
+ pageIndex);
}
/** Animates to the given progress, where 0 is the current app and 1 is overview. */
@@ -851,16 +860,6 @@
Interpolator interpolator, GestureEndTarget target, PointF velocityPxPerMs) {
mGestureEndTarget = target;
- if (mGestureEndTarget.canBeContinued) {
- // Because we might continue this gesture, e.g. for consecutive quick switch, we need to
- // stabilize the task list so that tasks don't rearrange in the middle of the gesture.
- RecentsModel.INSTANCE.get(mContext).startStabilizationSession();
- } else if (mGestureEndTarget.isLauncher) {
- // Otherwise, if we're going to home or overview,
- // we reset the tasks to a consistent start state.
- RecentsModel.INSTANCE.get(mContext).endStabilizationSession();
- }
-
if (mGestureEndTarget == HOME) {
HomeAnimationFactory homeAnimFactory;
if (mActivity != null) {
@@ -940,7 +939,7 @@
HomeAnimationFactory homeAnimationFactory) {
final RemoteAnimationTargetSet targetSet = mRecentsAnimationWrapper.targetSet;
final RectF startRect = new RectF(mClipAnimationHelper.applyTransform(targetSet,
- mTransformParams.setProgress(startProgress)));
+ mTransformParams.setProgress(startProgress), false /* launcherOnTop */));
final RectF targetRect = homeAnimationFactory.getWindowTargetRect();
final View floatingView = homeAnimationFactory.getFloatingView();
@@ -955,7 +954,7 @@
// 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 ? 0.75f : 1f;
+ final float windowAlphaThreshold = isFloatingIconView ? 1f - SHAPE_PROGRESS_DURATION : 1f;
anim.addOnUpdateListener((currentRect, progress) -> {
float interpolatedProgress = Interpolators.ACCEL_1_5.getInterpolation(progress);
@@ -965,11 +964,12 @@
windowAlphaThreshold, 0f, 1f, Interpolators.LINEAR);
mTransformParams.setCurrentRectAndTargetAlpha(currentRect, 1f - iconAlpha)
.setSyncTransactionApplier(mSyncTransactionApplier);
- mClipAnimationHelper.applyTransform(targetSet, mTransformParams);
+ mClipAnimationHelper.applyTransform(targetSet, mTransformParams,
+ false /* launcherOnTop */);
if (isFloatingIconView) {
((FloatingIconView) floatingView).update(currentRect, iconAlpha, progress,
- windowAlphaThreshold);
+ windowAlphaThreshold, mClipAnimationHelper.getCurrentCornerRadius(), false);
}
});
@@ -977,6 +977,7 @@
@Override
public void onAnimationStart(Animator animation) {
homeAnim.dispatchOnStart();
+ mActivity.getRootView().getOverlay().remove(mLiveTileOverlay);
}
@Override
@@ -1003,10 +1004,12 @@
// 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.
- mRecentsView.getTaskViewAt(mRecentsView.getNextPage()).launchTask(false);
+ mRecentsView.getTaskViewAt(mRecentsView.getNextPage()).launchTask(false /* animate */,
+ true /* freezeTaskList */);
} else {
mRecentsAnimationWrapper.finish(true /* toRecents */, () -> {
- mRecentsView.getTaskViewAt(mRecentsView.getNextPage()).launchTask(false);
+ mRecentsView.getTaskViewAt(mRecentsView.getNextPage()).launchTask(
+ false /* animate */, true /* freezeTaskList */);
});
}
TOUCH_INTERACTION_LOG.addLog("finishRecentsAnimation", false);
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/RecentsRootView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/RecentsRootView.java
index 6b3f028..777e592 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/RecentsRootView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/RecentsRootView.java
@@ -17,12 +17,18 @@
import android.annotation.TargetApi;
import android.content.Context;
+import android.graphics.Insets;
import android.graphics.Point;
import android.graphics.Rect;
+import android.graphics.RectF;
import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.ViewDebug;
+import android.view.WindowInsets;
import com.android.launcher3.BaseActivity;
import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
import com.android.launcher3.util.Themes;
import com.android.launcher3.util.TouchController;
import com.android.launcher3.views.BaseDragLayer;
@@ -33,6 +39,9 @@
private static final int MIN_SIZE = 10;
private final RecentsActivity mActivity;
+ @ViewDebug.ExportedProperty(category = "launcher")
+ private final RectF mTouchExcludeRegion = new RectF();
+
private final Point mLastKnownSize = new Point(MIN_SIZE, MIN_SIZE);
public RecentsRootView(Context context, AttributeSet attrs) {
@@ -88,4 +97,29 @@
mActivity.getDeviceProfile().updateInsets(mInsets);
super.setInsets(mInsets);
}
+
+ @Override
+ public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) {
+ if (Utilities.ATLEAST_Q) {
+ Insets gestureInsets = insets.getMandatorySystemGestureInsets();
+ mTouchExcludeRegion.set(gestureInsets.left, gestureInsets.top,
+ gestureInsets.right, gestureInsets.bottom);
+ }
+ return super.dispatchApplyWindowInsets(insets);
+ }
+
+ @Override
+ public boolean dispatchTouchEvent(MotionEvent ev) {
+ if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+ float x = ev.getX();
+ float y = ev.getY();
+ if (y < mTouchExcludeRegion.top
+ || x < mTouchExcludeRegion.left
+ || x > (getWidth() - mTouchExcludeRegion.right)
+ || y > (getHeight() - mTouchExcludeRegion.bottom)) {
+ return false;
+ }
+ }
+ return super.dispatchTouchEvent(ev);
+ }
}
\ No newline at end of file
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/RecentsTaskController.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/RecentsTaskController.java
index 9463cc9..a113604 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/RecentsTaskController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/RecentsTaskController.java
@@ -15,7 +15,7 @@
*/
package com.android.quickstep.fallback;
-import com.android.launcher3.uioverrides.TaskViewTouchController;
+import com.android.launcher3.uioverrides.touchcontrollers.TaskViewTouchController;
import com.android.quickstep.RecentsActivity;
public class RecentsTaskController extends TaskViewTouchController<RecentsActivity> {
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/ClipAnimationHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/ClipAnimationHelper.java
index fe5a675..e1a39c6 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/ClipAnimationHelper.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/ClipAnimationHelper.java
@@ -149,6 +149,11 @@
}
public RectF applyTransform(RemoteAnimationTargetSet targetSet, TransformParams params) {
+ return applyTransform(targetSet, params, true /* launcherOnTop */);
+ }
+
+ public RectF applyTransform(RemoteAnimationTargetSet targetSet, TransformParams params,
+ boolean launcherOnTop) {
if (params.currentRect == null) {
RectF currentRect;
mTmpRectF.set(mTargetRect);
@@ -189,7 +194,7 @@
}
}
alpha = mTaskAlphaCallback.apply(app, params.targetAlpha);
- } else if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
+ } else if (ENABLE_QUICKSTEP_LIVE_TILE.get() && launcherOnTop) {
crop = null;
layer = Integer.MAX_VALUE;
}
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 8da1d2b..329436b 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
@@ -32,9 +32,7 @@
import android.graphics.Rect;
import android.os.Build;
import android.util.AttributeSet;
-import android.util.FloatProperty;
import android.view.View;
-import android.view.ViewDebug;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
@@ -44,7 +42,7 @@
import com.android.launcher3.util.PendingAnimation;
import com.android.launcher3.views.BaseDragLayer;
import com.android.launcher3.views.ScrimView;
-import com.android.quickstep.OverviewInteractionState;
+import com.android.quickstep.SysUINavigationMode;
import com.android.quickstep.hints.ChipsContainer;
import com.android.quickstep.util.ClipAnimationHelper;
import com.android.quickstep.util.ClipAnimationHelper.TransformParams;
@@ -132,7 +130,7 @@
ClipAnimationHelper helper) {
AnimatorSet anim = super.createAdjacentPageAnimForTaskLaunch(tv, helper);
- if (!OverviewInteractionState.INSTANCE.get(mActivity).isSwipeUpGestureEnabled()) {
+ if (!SysUINavigationMode.INSTANCE.get(mActivity).getMode().hasGestures) {
// Hotseat doesn't move when opening recents with the button,
// so don't animate it here either.
return anim;
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 a02df62..ddb94d2 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
@@ -24,7 +24,7 @@
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
import static com.android.launcher3.config.FeatureFlags.QUICKSTEP_SPRINGS;
-import static com.android.launcher3.uioverrides.TaskViewTouchController.SUCCESS_TRANSITION_PROGRESS;
+import static com.android.launcher3.uioverrides.touchcontrollers.TaskViewTouchController.SUCCESS_TRANSITION_PROGRESS;
import static com.android.launcher3.util.SystemUiController.UI_STATE_OVERVIEW;
import static com.android.quickstep.TaskUtils.checkCurrentOrManagedUserId;
import static com.android.launcher3.Utilities.EDGE_NAV_BAR;
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 90604ef..a9f6311 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
@@ -46,6 +46,7 @@
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.SystemUiController;
import com.android.launcher3.util.Themes;
+import com.android.quickstep.RecentsModel;
import com.android.quickstep.TaskOverlayFactory;
import com.android.quickstep.TaskOverlayFactory.TaskOverlay;
import com.android.systemui.shared.recents.model.Task;
@@ -81,6 +82,7 @@
private final Paint mBackgroundPaint = new Paint();
private final Paint mClearPaint = new Paint();
private final Paint mDimmingPaintAfterClearing = new Paint();
+ private final float mWindowCornerRadius;
private final Matrix mMatrix = new Matrix();
@@ -114,6 +116,7 @@
mDimmingPaintAfterClearing.setColor(Color.BLACK);
mActivity = BaseActivity.fromContext(context);
mIsDarkTextTheme = Themes.getAttrBoolean(mActivity, R.attr.isWorkspaceDarkText);
+ mWindowCornerRadius = RecentsModel.INSTANCE.get(context).getWindowCornerRadius();
}
public void bind(Task task) {
@@ -196,19 +199,22 @@
@Override
protected void onDraw(Canvas canvas) {
- float fullscreenProgress = ((TaskView) getParent()).getFullscreenProgress();
+ TaskView taskView = (TaskView) getParent();
+ float fullscreenProgress = taskView.getFullscreenProgress();
if (mIsRotated) {
// Don't show insets in the wrong orientation.
fullscreenProgress = 0;
}
if (fullscreenProgress > 0) {
// Draw the insets if we're being drawn fullscreen (we do this for quick switch).
+ float cornerRadius = Utilities.mapRange(fullscreenProgress, mCornerRadius,
+ mWindowCornerRadius);
drawOnCanvas(canvas,
-mScaledInsets.left * fullscreenProgress,
-mScaledInsets.top * fullscreenProgress,
getMeasuredWidth() + mScaledInsets.right * fullscreenProgress,
getMeasuredHeight() + mScaledInsets.bottom * fullscreenProgress,
- mCornerRadius);
+ cornerRadius / taskView.getRecentsView().getScaleX());
} else {
drawOnCanvas(canvas, 0, 0, getMeasuredWidth(), getMeasuredHeight(), mCornerRadius);
}
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 3889fd3..747c480 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
@@ -249,7 +249,11 @@
}
public void launchTask(boolean animate) {
- launchTask(animate, (result) -> {
+ launchTask(animate, false /* freezeTaskList */);
+ }
+
+ public void launchTask(boolean animate, boolean freezeTaskList) {
+ launchTask(animate, freezeTaskList, (result) -> {
if (!result) {
notifyTaskLaunchFailed(TAG);
}
@@ -258,25 +262,33 @@
public void launchTask(boolean animate, Consumer<Boolean> resultCallback,
Handler resultCallbackHandler) {
+ launchTask(animate, false /* freezeTaskList */, resultCallback, resultCallbackHandler);
+ }
+
+ public void launchTask(boolean animate, boolean freezeTaskList, Consumer<Boolean> resultCallback,
+ Handler resultCallbackHandler) {
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
if (isRunningTask()) {
getRecentsView().finishRecentsAnimation(false /* toRecents */,
() -> resultCallbackHandler.post(() -> resultCallback.accept(true)));
} else {
- launchTaskInternal(animate, resultCallback, resultCallbackHandler);
+ launchTaskInternal(animate, freezeTaskList, resultCallback, resultCallbackHandler);
}
} else {
- launchTaskInternal(animate, resultCallback, resultCallbackHandler);
+ launchTaskInternal(animate, freezeTaskList, resultCallback, resultCallbackHandler);
}
}
- private void launchTaskInternal(boolean animate, Consumer<Boolean> resultCallback,
- Handler resultCallbackHandler) {
+ private void launchTaskInternal(boolean animate, boolean freezeTaskList,
+ Consumer<Boolean> resultCallback, Handler resultCallbackHandler) {
if (mTask != null) {
final ActivityOptions opts;
if (animate) {
opts = ((BaseDraggingActivity) fromContext(getContext()))
.getActivityLaunchOptions(this);
+ if (freezeTaskList) {
+ ActivityOptionsCompat.setFreezeRecentTasksList(opts);
+ }
ActivityManagerWrapper.getInstance().startActivityFromRecentsAsync(mTask.key,
opts, resultCallback, resultCallbackHandler);
} else {
@@ -287,6 +299,9 @@
resultCallbackHandler.post(() -> resultCallback.accept(true));
}
}, resultCallbackHandler);
+ if (freezeTaskList) {
+ ActivityOptionsCompat.setFreezeRecentTasksList(opts);
+ }
ActivityManagerWrapper.getInstance().startActivityFromRecentsAsync(mTask.key,
opts, (success) -> {
if (resultCallback != null && !success) {
@@ -416,6 +431,7 @@
}
private void resetViewTransforms() {
+ setCurveScale(1);
setZoomScale(1);
setTranslationX(0f);
setTranslationY(0f);
diff --git a/quickstep/res/values-af/strings.xml b/quickstep/res/values-af/strings.xml
index 336eef8..88954b2 100644
--- a/quickstep/res/values-af/strings.xml
+++ b/quickstep/res/values-af/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Onlangse programme"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 minuut"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"Program in grysskaal"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"<xliff:g id="TIME">%1$s</xliff:g> oor vandag"</string>
</resources>
diff --git a/quickstep/res/values-am/strings.xml b/quickstep/res/values-am/strings.xml
index 8a565e4..34fb3be 100644
--- a/quickstep/res/values-am/strings.xml
+++ b/quickstep/res/values-am/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"የቅርብ ጊዜ መተግበሪያዎች"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>፣ <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 ደቂቃ"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"መተግበሪያ በግራጫ"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"ዛሬ <xliff:g id="TIME">%1$s</xliff:g> ቀርቷል"</string>
</resources>
diff --git a/quickstep/res/values-ar/strings.xml b/quickstep/res/values-ar/strings.xml
index d96397c..ebdcf73 100644
--- a/quickstep/res/values-ar/strings.xml
+++ b/quickstep/res/values-ar/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"التطبيقات التي تمّ استخدامها مؤخرًا"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>، <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"أقل من دقيقة"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"التطبيق بالتدرّج الرمادي"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"يتبقى اليوم <xliff:g id="TIME">%1$s</xliff:g>."</string>
</resources>
diff --git a/quickstep/res/values-as/strings.xml b/quickstep/res/values-as/strings.xml
index 7216b4f..a33973b 100644
--- a/quickstep/res/values-as/strings.xml
+++ b/quickstep/res/values-as/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"শেহতীয়া এপসমূহ"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< ১ মিনিট"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"এপ্ গ্ৰে’স্কে’লত আছে"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"আজি <xliff:g id="TIME">%1$s</xliff:g> বাকী আছ"</string>
</resources>
diff --git a/quickstep/res/values-az/strings.xml b/quickstep/res/values-az/strings.xml
index c07098e..02312f4 100644
--- a/quickstep/res/values-az/strings.xml
+++ b/quickstep/res/values-az/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Son tətbiqlər"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 dəq"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"Tətbiq ağ-qara rejimdədir"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"Bu gün <xliff:g id="TIME">%1$s</xliff:g> qaldı"</string>
</resources>
diff --git a/quickstep/res/values-b+sr+Latn/strings.xml b/quickstep/res/values-b+sr+Latn/strings.xml
index 6fea458..baab4a1 100644
--- a/quickstep/res/values-b+sr+Latn/strings.xml
+++ b/quickstep/res/values-b+sr+Latn/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Nedavne aplikacije"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 min"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"Aplikacija je u sivilu"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"Još <xliff:g id="TIME">%1$s</xliff:g> danas"</string>
</resources>
diff --git a/quickstep/res/values-be/strings.xml b/quickstep/res/values-be/strings.xml
index 8147031..b28f377 100644
--- a/quickstep/res/values-be/strings.xml
+++ b/quickstep/res/values-be/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Нядаўнія праграмы"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 хв"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"Праграма ў шэрым рэжыме"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"Сёння засталося <xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-bg/strings.xml b/quickstep/res/values-bg/strings.xml
index 00ba582..0475c0d 100644
--- a/quickstep/res/values-bg/strings.xml
+++ b/quickstep/res/values-bg/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Скорошни приложения"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 мин"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"Прилож. е в сивата скала"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"Оставащо време днес: <xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-bn/strings.xml b/quickstep/res/values-bn/strings.xml
index 9a30adf..e6764e0 100644
--- a/quickstep/res/values-bn/strings.xml
+++ b/quickstep/res/values-bn/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"সম্প্রতি ব্যবহৃত অ্যাপ"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< ১ মি."</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"অ্যাপে গ্রেস্কেল"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"আজকে <xliff:g id="TIME">%1$s</xliff:g> বাকি আছে"</string>
</resources>
diff --git a/quickstep/res/values-bs/strings.xml b/quickstep/res/values-bs/strings.xml
index e940616..77b4c46 100644
--- a/quickstep/res/values-bs/strings.xml
+++ b/quickstep/res/values-bs/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Nedavne aplikacije"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 min"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"Apl. je u nijansi sive"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"Preostalo vrijeme: <xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-ca/strings.xml b/quickstep/res/values-ca/strings.xml
index d120a2c..484f445 100644
--- a/quickstep/res/values-ca/strings.xml
+++ b/quickstep/res/values-ca/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Aplicacions recents"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>; <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 minut"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"App en escala de grisos"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"temps restant avui: <xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-cs/strings.xml b/quickstep/res/values-cs/strings.xml
index 435edd9..a698d49 100644
--- a/quickstep/res/values-cs/strings.xml
+++ b/quickstep/res/values-cs/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Poslední aplikace"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 minuta"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"Aplikace se zešednutím"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"dnes zbývá: <xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-da/strings.xml b/quickstep/res/values-da/strings.xml
index 3db6ab3..b3e8524 100644
--- a/quickstep/res/values-da/strings.xml
+++ b/quickstep/res/values-da/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Seneste apps"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 min"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"Nedtonet app"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"<xliff:g id="TIME">%1$s</xliff:g> tilbage i dag"</string>
</resources>
diff --git a/quickstep/res/values-de/strings.xml b/quickstep/res/values-de/strings.xml
index 48604f1..10e4fd7 100644
--- a/quickstep/res/values-de/strings.xml
+++ b/quickstep/res/values-de/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Zuletzt aktive Apps"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 min"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"App in Graustufen"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"Heute noch <xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-el/strings.xml b/quickstep/res/values-el/strings.xml
index fdc7464..6ef1e94 100644
--- a/quickstep/res/values-el/strings.xml
+++ b/quickstep/res/values-el/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Πρόσφατες εφαρμογές"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 λ."</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"Εφαρ. σε κλίμακα του γκρι"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"Απομένουν <xliff:g id="TIME">%1$s</xliff:g> σήμερα"</string>
</resources>
diff --git a/quickstep/res/values-en-rAU/strings.xml b/quickstep/res/values-en-rAU/strings.xml
index d625b60..d640b63 100644
--- a/quickstep/res/values-en-rAU/strings.xml
+++ b/quickstep/res/values-en-rAU/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Recent apps"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 minute"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"App in grayscale"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"<xliff:g id="TIME">%1$s</xliff:g> left today"</string>
</resources>
diff --git a/quickstep/res/values-en-rGB/strings.xml b/quickstep/res/values-en-rGB/strings.xml
index d625b60..d640b63 100644
--- a/quickstep/res/values-en-rGB/strings.xml
+++ b/quickstep/res/values-en-rGB/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Recent apps"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 minute"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"App in grayscale"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"<xliff:g id="TIME">%1$s</xliff:g> left today"</string>
</resources>
diff --git a/quickstep/res/values-en-rIN/strings.xml b/quickstep/res/values-en-rIN/strings.xml
index d625b60..d640b63 100644
--- a/quickstep/res/values-en-rIN/strings.xml
+++ b/quickstep/res/values-en-rIN/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Recent apps"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 minute"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"App in grayscale"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"<xliff:g id="TIME">%1$s</xliff:g> left today"</string>
</resources>
diff --git a/quickstep/res/values-es-rUS/strings.xml b/quickstep/res/values-es-rUS/strings.xml
index a9d303a..c93e8fc 100644
--- a/quickstep/res/values-es-rUS/strings.xml
+++ b/quickstep/res/values-es-rUS/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Apps recientes"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g> (<xliff:g id="REMAINING_TIME">%2$s</xliff:g>)"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 minuto"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"App en escala de grises"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"Tiempo restante: <xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-es/strings.xml b/quickstep/res/values-es/strings.xml
index 291512a..3a588e5 100644
--- a/quickstep/res/values-es/strings.xml
+++ b/quickstep/res/values-es/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Aplicaciones recientes"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g> (<xliff:g id="REMAINING_TIME">%2$s</xliff:g>)"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"<1 minuto"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"App en escala de grises"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"tiempo restante: <xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-et/strings.xml b/quickstep/res/values-et/strings.xml
index 96c27e7..7032765 100644
--- a/quickstep/res/values-et/strings.xml
+++ b/quickstep/res/values-et/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Hiljutised rakendused"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g> <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 minut"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"Rakendus halltoonides"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"Tääna jäänud <xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-eu/strings.xml b/quickstep/res/values-eu/strings.xml
index 15b682c..66e08b9 100644
--- a/quickstep/res/values-eu/strings.xml
+++ b/quickstep/res/values-eu/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Azken aplikazioak"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g> (<xliff:g id="REMAINING_TIME">%2$s</xliff:g>)"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 min"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"Aplikazioa grisen eskalan"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"<xliff:g id="TIME">%1$s</xliff:g> gelditzen dira gaur"</string>
</resources>
diff --git a/quickstep/res/values-fa/strings.xml b/quickstep/res/values-fa/strings.xml
index 0a482f8..112d04c 100644
--- a/quickstep/res/values-fa/strings.xml
+++ b/quickstep/res/values-fa/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"برنامههای اخیر"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>، <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< ۱ دقیقه"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"برنامه بهصورت سیاهوسفید"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"<xliff:g id="TIME">%1$s</xliff:g> باقیمانده برای امروز"</string>
</resources>
diff --git a/quickstep/res/values-fi/strings.xml b/quickstep/res/values-fi/strings.xml
index 69686bb..6a0a359 100644
--- a/quickstep/res/values-fi/strings.xml
+++ b/quickstep/res/values-fi/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Viimeisimmät sovellukset"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 min"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"Harmaasävyinen sovellus"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"<xliff:g id="TIME">%1$s</xliff:g> jäljellä tänään"</string>
</resources>
diff --git a/quickstep/res/values-fr-rCA/strings.xml b/quickstep/res/values-fr-rCA/strings.xml
index 068fd08..248a5da 100644
--- a/quickstep/res/values-fr-rCA/strings.xml
+++ b/quickstep/res/values-fr-rCA/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Applications récentes"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g> : <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 min"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"Application en nuances de gris"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"Il reste <xliff:g id="TIME">%1$s</xliff:g> aujourd\'hui"</string>
</resources>
diff --git a/quickstep/res/values-fr/strings.xml b/quickstep/res/values-fr/strings.xml
index ea5b0dc..338d9ba 100644
--- a/quickstep/res/values-fr/strings.xml
+++ b/quickstep/res/values-fr/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Applications récentes"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 min"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"Appli en nuances de gris"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"Encore <xliff:g id="TIME">%1$s</xliff:g> aujourd\'hui"</string>
</resources>
diff --git a/quickstep/res/values-gl/strings.xml b/quickstep/res/values-gl/strings.xml
index a6995d0..d6ddf3c 100644
--- a/quickstep/res/values-gl/strings.xml
+++ b/quickstep/res/values-gl/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Aplicacións recentes"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g> (<xliff:g id="REMAINING_TIME">%2$s</xliff:g>)"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"<1 min"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"App en escala de grises"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"Tempo restante hoxe <xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-gu/strings.xml b/quickstep/res/values-gu/strings.xml
index 72b70b0..4493e3b 100644
--- a/quickstep/res/values-gu/strings.xml
+++ b/quickstep/res/values-gu/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"તાજેતરની ઍપ"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 મિનિટ"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"ગ્રેસ્કેલમાં ઍપ"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"<xliff:g id="TIME">%1$s</xliff:g> આજે બાકી"</string>
</resources>
diff --git a/quickstep/res/values-hi/strings.xml b/quickstep/res/values-hi/strings.xml
index 4d15044..3c53cce 100644
--- a/quickstep/res/values-hi/strings.xml
+++ b/quickstep/res/values-hi/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"हाल ही में इस्तेमाल किए गए एेप्लिकेशन"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"<1 मिनट"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"ग्रेस्केल में ऐप्लिकेशन"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"आज <xliff:g id="TIME">%1$s</xliff:g> और चलेगा"</string>
</resources>
diff --git a/quickstep/res/values-hr/strings.xml b/quickstep/res/values-hr/strings.xml
index 1cec1fb..103710f 100644
--- a/quickstep/res/values-hr/strings.xml
+++ b/quickstep/res/values-hr/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Nedavne aplikacije"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 min"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"Apl. u nijansama sive"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"Još <xliff:g id="TIME">%1$s</xliff:g> danas"</string>
</resources>
diff --git a/quickstep/res/values-hu/strings.xml b/quickstep/res/values-hu/strings.xml
index 112c481..22b2380 100644
--- a/quickstep/res/values-hu/strings.xml
+++ b/quickstep/res/values-hu/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Legutóbbi alkalmazások"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 perc"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"Szürkeárnyalat aktív"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"Ma még <xliff:g id="TIME">%1$s</xliff:g> van hátra"</string>
</resources>
diff --git a/quickstep/res/values-hy/strings.xml b/quickstep/res/values-hy/strings.xml
index f39db5a..910265a 100644
--- a/quickstep/res/values-hy/strings.xml
+++ b/quickstep/res/values-hy/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Վերջին օգտագործած հավելվածները"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 ր"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"Մոխրագույն երանգներ"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"Այսօր մնացել է՝ <xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-in/strings.xml b/quickstep/res/values-in/strings.xml
index 48892c9..a7749df 100644
--- a/quickstep/res/values-in/strings.xml
+++ b/quickstep/res/values-in/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Aplikasi baru-baru ini"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 menit"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"Aplikasi hitam putih"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"<xliff:g id="TIME">%1$s</xliff:g> tersisa hari ini"</string>
</resources>
diff --git a/quickstep/res/values-is/strings.xml b/quickstep/res/values-is/strings.xml
index c3ec96c..ba0c672 100644
--- a/quickstep/res/values-is/strings.xml
+++ b/quickstep/res/values-is/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Nýleg forrit"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 mín."</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"Forrit í grátónum"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"<xliff:g id="TIME">%1$s</xliff:g> eftir í dag"</string>
</resources>
diff --git a/quickstep/res/values-it/strings.xml b/quickstep/res/values-it/strings.xml
index d7c57ee..746443e 100644
--- a/quickstep/res/values-it/strings.xml
+++ b/quickstep/res/values-it/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"App recenti"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 min"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"App in scala di grigi"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"Rimanente oggi: <xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-iw/strings.xml b/quickstep/res/values-iw/strings.xml
index 0b745cd..96a8adc 100644
--- a/quickstep/res/values-iw/strings.xml
+++ b/quickstep/res/values-iw/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"אפליקציות אחרונות"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< דקה"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"האפליקציה בגווני אפור"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"הזמן שנותר להיום: <xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-ja/strings.xml b/quickstep/res/values-ja/strings.xml
index c76c4a6..5484ae1 100644
--- a/quickstep/res/values-ja/strings.xml
+++ b/quickstep/res/values-ja/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"最近使ったアプリ"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>、<xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"1 分未満"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"グレースケールのアプリ"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"今日はあと <xliff:g id="TIME">%1$s</xliff:g>です"</string>
</resources>
diff --git a/quickstep/res/values-ka/strings.xml b/quickstep/res/values-ka/strings.xml
index 700522f..9218fb8 100644
--- a/quickstep/res/values-ka/strings.xml
+++ b/quickstep/res/values-ka/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"ბოლოდროინდელი აპები"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 წუთი"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"აპი ნაცრისფერ ტონებშია"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"დღეს დარჩენილია <xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-kk/strings.xml b/quickstep/res/values-kk/strings.xml
index 96f8956..0766150 100644
--- a/quickstep/res/values-kk/strings.xml
+++ b/quickstep/res/values-kk/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Соңғы пайдаланылған қолданбалар"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 мин"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"Сұр түстегі қолданба"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"Бүгін <xliff:g id="TIME">%1$s</xliff:g> қалды"</string>
</resources>
diff --git a/quickstep/res/values-km/strings.xml b/quickstep/res/values-km/strings.xml
index 323efdf..8737ae8 100644
--- a/quickstep/res/values-km/strings.xml
+++ b/quickstep/res/values-km/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"កម្មវិធីថ្មីៗ"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 នាទី"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"កម្មវិធីស្ថិតក្នុងមាត្រដ្ឋានពណ៌ប្រផេះ"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"នៅសល់ <xliff:g id="TIME">%1$s</xliff:g> ទៀតនៅថ្ងៃនេះ"</string>
</resources>
diff --git a/quickstep/res/values-kn/strings.xml b/quickstep/res/values-kn/strings.xml
index b5e5738..099957c 100644
--- a/quickstep/res/values-kn/strings.xml
+++ b/quickstep/res/values-kn/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"ಇತ್ತೀಚಿನ ಅಪ್ಲಿಕೇಶನ್ಗಳು"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 ನಿ"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"ಗ್ರೇಸ್ಕೇಲ್ನಲ್ಲಿ ಆ್ಯಪ್"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"ಇಂದು <xliff:g id="TIME">%1$s</xliff:g> ಸಮಯ ಉಳಿದಿದೆ"</string>
</resources>
diff --git a/quickstep/res/values-ko/strings.xml b/quickstep/res/values-ko/strings.xml
index 5daa508..9543e79 100644
--- a/quickstep/res/values-ko/strings.xml
+++ b/quickstep/res/values-ko/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"최근 앱"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1분"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"앱이 그레이 스케일로 전환됨"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"오늘 <xliff:g id="TIME">%1$s</xliff:g> 남음"</string>
</resources>
diff --git a/quickstep/res/values-ky/strings.xml b/quickstep/res/values-ky/strings.xml
index be960ec..d1d2d20 100644
--- a/quickstep/res/values-ky/strings.xml
+++ b/quickstep/res/values-ky/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Акыркы колдонмолор"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 мүнөт"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"Колдонмо жигерсиз"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"Бүгүн <xliff:g id="TIME">%1$s</xliff:g> мүнөт калды"</string>
</resources>
diff --git a/quickstep/res/values-lo/strings.xml b/quickstep/res/values-lo/strings.xml
index ef70ee7..aba4156 100644
--- a/quickstep/res/values-lo/strings.xml
+++ b/quickstep/res/values-lo/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"ແອັບຫຼ້າສຸດ"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 ນາທີ"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"ແອັບເປັນສີຂາວດຳ"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"ເຫຼືອ <xliff:g id="TIME">%1$s</xliff:g> ມື້ນີ້"</string>
</resources>
diff --git a/quickstep/res/values-lt/strings.xml b/quickstep/res/values-lt/strings.xml
index f10866b..933b3f0 100644
--- a/quickstep/res/values-lt/strings.xml
+++ b/quickstep/res/values-lt/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Naujausios programos"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 min."</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"Programa su pilkumo tonu"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"Šiandien liko: <xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-lv/strings.xml b/quickstep/res/values-lv/strings.xml
index 9ae124a..1e2ed00 100644
--- a/quickstep/res/values-lv/strings.xml
+++ b/quickstep/res/values-lv/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Pēdējās izmantotās lietotnes"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"<1 minūte"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"Lietotne pelēktoņos"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"Šodien atlicis: <xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-mk/strings.xml b/quickstep/res/values-mk/strings.xml
index 688cb93..7a6c094 100644
--- a/quickstep/res/values-mk/strings.xml
+++ b/quickstep/res/values-mk/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Неодамнешни апликации"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 минута"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"Апликација во сиви тонови"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"Уште <xliff:g id="TIME">%1$s</xliff:g> за денес"</string>
</resources>
diff --git a/quickstep/res/values-ml/strings.xml b/quickstep/res/values-ml/strings.xml
index e66116c..b5eac1d 100644
--- a/quickstep/res/values-ml/strings.xml
+++ b/quickstep/res/values-ml/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"സമീപകാല ആപ്പുകൾ"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 മിനിറ്റ്"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"ആപ്പ് ഗ്രേസ്കെയിലിൽ"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"ഇന്ന് <xliff:g id="TIME">%1$s</xliff:g> ശേഷിക്കുന്നു"</string>
</resources>
diff --git a/quickstep/res/values-mn/strings.xml b/quickstep/res/values-mn/strings.xml
index 5c57237..a105ef1 100644
--- a/quickstep/res/values-mn/strings.xml
+++ b/quickstep/res/values-mn/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Саяхны аппууд"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 минут"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"Саарал өнгөтэй болсон апп"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"Өнөөдөр <xliff:g id="TIME">%1$s</xliff:g> үлдсэн"</string>
</resources>
diff --git a/quickstep/res/values-mr/strings.xml b/quickstep/res/values-mr/strings.xml
index f4f2904..bf725e3 100644
--- a/quickstep/res/values-mr/strings.xml
+++ b/quickstep/res/values-mr/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"अलीकडील अॅप्स"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"१मिहून कमी"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"ग्रेस्केल मधील अॅप"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"आज <xliff:g id="TIME">%1$s</xliff:g>शिल्लक आहे"</string>
</resources>
diff --git a/quickstep/res/values-ms/strings.xml b/quickstep/res/values-ms/strings.xml
index d8561eb..2e3f236 100644
--- a/quickstep/res/values-ms/strings.xml
+++ b/quickstep/res/values-ms/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Apl terbaharu"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 minit"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"Apl dalam skala kelabu"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"<xliff:g id="TIME">%1$s</xliff:g> lagi hari ini"</string>
</resources>
diff --git a/quickstep/res/values-my/strings.xml b/quickstep/res/values-my/strings.xml
index f609c89..7b93125 100644
--- a/quickstep/res/values-my/strings.xml
+++ b/quickstep/res/values-my/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"လတ်တလောသုံး အက်ပ်များ"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>၊ <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< ၁ မိနစ်"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"အဖြူအမည်းနှင့်ပြသော အက်ပ်"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"ယနေ့ <xliff:g id="TIME">%1$s</xliff:g> ခု ကျန်သည်"</string>
</resources>
diff --git a/quickstep/res/values-nb/strings.xml b/quickstep/res/values-nb/strings.xml
index cff48d8..74f43d2 100644
--- a/quickstep/res/values-nb/strings.xml
+++ b/quickstep/res/values-nb/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Nylige apper"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 minutt"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"App i gråtoner"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"<xliff:g id="TIME">%1$s</xliff:g> gjenstår i dag"</string>
</resources>
diff --git a/quickstep/res/values-ne/strings.xml b/quickstep/res/values-ne/strings.xml
index cc450c4..6053def 100644
--- a/quickstep/res/values-ne/strings.xml
+++ b/quickstep/res/values-ne/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"हालसालैका अनुप्रयोगहरू"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< १ मिनेट"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"ग्रेस्केल पारिएको एप"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"आज: <xliff:g id="TIME">%1$s</xliff:g> बाँकी"</string>
</resources>
diff --git a/quickstep/res/values-nl/strings.xml b/quickstep/res/values-nl/strings.xml
index 4a3607d..4e3a34c 100644
--- a/quickstep/res/values-nl/strings.xml
+++ b/quickstep/res/values-nl/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Recente apps"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 minuut"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"App in grijstinten"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"Nog <xliff:g id="TIME">%1$s</xliff:g> vandaag"</string>
</resources>
diff --git a/quickstep/res/values-or/strings.xml b/quickstep/res/values-or/strings.xml
index 4dd5920..bd88671 100644
--- a/quickstep/res/values-or/strings.xml
+++ b/quickstep/res/values-or/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"ସାମ୍ପ୍ରତିକ ଆପ୍"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g> <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 ମିନିଟ୍"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"ଗ୍ରେସ୍କେଲ୍ରେ ଥିବା ଆପ୍"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"ଆଜି <xliff:g id="TIME">%1$s</xliff:g> ବାକି ଅଛି"</string>
</resources>
diff --git a/quickstep/res/values-pa/strings.xml b/quickstep/res/values-pa/strings.xml
index 078d8a0..5aeeae6 100644
--- a/quickstep/res/values-pa/strings.xml
+++ b/quickstep/res/values-pa/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"ਹਾਲੀਆ ਐਪਾਂ"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 ਮਿੰਟ"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"ਐਪ ਗ੍ਰੇਸਕੇਲ ਵਿੱਚ ਹੈ"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"ਅੱਜ <xliff:g id="TIME">%1$s</xliff:g> ਬਾਕੀ"</string>
</resources>
diff --git a/quickstep/res/values-pl/strings.xml b/quickstep/res/values-pl/strings.xml
index aa7920c..210edcf 100644
--- a/quickstep/res/values-pl/strings.xml
+++ b/quickstep/res/values-pl/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Ostatnie aplikacje"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"> 1 min"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"Aplikacja wyszarzona"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"Na dziś zostało <xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-pt-rPT/strings.xml b/quickstep/res/values-pt-rPT/strings.xml
index 22dc654..8a129d5 100644
--- a/quickstep/res/values-pt-rPT/strings.xml
+++ b/quickstep/res/values-pt-rPT/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Aplicações recentes"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 minuto"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"Aplic. na Escala de cinz."</string>
<string name="time_left_for_app" msgid="3111996412933644358">"Resta(m) <xliff:g id="TIME">%1$s</xliff:g> hoje."</string>
</resources>
diff --git a/quickstep/res/values-pt/strings.xml b/quickstep/res/values-pt/strings.xml
index b838c96..e5380d5 100644
--- a/quickstep/res/values-pt/strings.xml
+++ b/quickstep/res/values-pt/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Apps recentes"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 min"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"App em escala de cinza"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"<xliff:g id="TIME">%1$s</xliff:g> restante(s) hoje"</string>
</resources>
diff --git a/quickstep/res/values-ro/strings.xml b/quickstep/res/values-ro/strings.xml
index a33524e..54452a0 100644
--- a/quickstep/res/values-ro/strings.xml
+++ b/quickstep/res/values-ro/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Aplicații recente"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 minut"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"Aplicație în tonuri de gri"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"Au mai rămas <xliff:g id="TIME">%1$s</xliff:g> astăzi"</string>
</resources>
diff --git a/quickstep/res/values-ru/strings.xml b/quickstep/res/values-ru/strings.xml
index 2df583c..8b2016a 100644
--- a/quickstep/res/values-ru/strings.xml
+++ b/quickstep/res/values-ru/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Недавние приложения"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>: <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 мин."</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"В режиме оттенков серого"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"Осталось сегодня: <xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-si/strings.xml b/quickstep/res/values-si/strings.xml
index 010a56e..2163390 100644
--- a/quickstep/res/values-si/strings.xml
+++ b/quickstep/res/values-si/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"මෑත යෙදුම්"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 විනාඩියක්"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"අලු පැහැ යෙදුම"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"අද <xliff:g id="TIME">%1$s</xliff:g>ක් ඉතුරුයි"</string>
</resources>
diff --git a/quickstep/res/values-sk/strings.xml b/quickstep/res/values-sk/strings.xml
index c73a597..12983db 100644
--- a/quickstep/res/values-sk/strings.xml
+++ b/quickstep/res/values-sk/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Nedávne aplikácie"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"Menej ako 1 minúta"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"Aplikácia je odfarbená"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"Dnes ešte zostáva: <xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-sl/strings.xml b/quickstep/res/values-sl/strings.xml
index a7f0704..a940f2b 100644
--- a/quickstep/res/values-sl/strings.xml
+++ b/quickstep/res/values-sl/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Nedavne aplikacije"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 min"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"Črnobela aplikacija"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"Danes je ostalo še <xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-sq/strings.xml b/quickstep/res/values-sq/strings.xml
index b70f142..e41bcb5 100644
--- a/quickstep/res/values-sq/strings.xml
+++ b/quickstep/res/values-sq/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Aplikacionet e fundit"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 minutë"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"Apl. në shkallën e grisë"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"<xliff:g id="TIME">%1$s</xliff:g> të mbetura sot"</string>
</resources>
diff --git a/quickstep/res/values-sr/strings.xml b/quickstep/res/values-sr/strings.xml
index 2cf43f5..8f26c66 100644
--- a/quickstep/res/values-sr/strings.xml
+++ b/quickstep/res/values-sr/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Недавне апликације"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 мин"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"Апликација је у сивилу"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"Још <xliff:g id="TIME">%1$s</xliff:g> данас"</string>
</resources>
diff --git a/quickstep/res/values-sv/strings.xml b/quickstep/res/values-sv/strings.xml
index bec4893..70740e5 100644
--- a/quickstep/res/values-sv/strings.xml
+++ b/quickstep/res/values-sv/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Senaste apparna"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 min"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"App visas i gråskala"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"<xliff:g id="TIME">%1$s</xliff:g> kvar i dag"</string>
</resources>
diff --git a/quickstep/res/values-sw/strings.xml b/quickstep/res/values-sw/strings.xml
index 53d095d..c646b6a 100644
--- a/quickstep/res/values-sw/strings.xml
+++ b/quickstep/res/values-sw/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Programu za hivi karibuni"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< dak 1"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"Programu katika kijivu"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"Umebakisha <xliff:g id="TIME">%1$s</xliff:g> leo"</string>
</resources>
diff --git a/quickstep/res/values-ta/strings.xml b/quickstep/res/values-ta/strings.xml
index ecc8f6c..19bfaa9 100644
--- a/quickstep/res/values-ta/strings.xml
+++ b/quickstep/res/values-ta/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"சமீபத்திய ஆப்ஸ்"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 நி"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"கிரேஸ்கேலில் உள்ள ஆப்ஸ்"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"இன்று <xliff:g id="TIME">%1$s</xliff:g> மீதமுள்ளது"</string>
</resources>
diff --git a/quickstep/res/values-te/strings.xml b/quickstep/res/values-te/strings.xml
index b6eeb40..071755a 100644
--- a/quickstep/res/values-te/strings.xml
+++ b/quickstep/res/values-te/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"ఇటీవలి యాప్లు"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 నిమిషం"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"యాప్ గ్రేస్కేల్లో ఉంది"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"నేటికి <xliff:g id="TIME">%1$s</xliff:g> మిగిలి ఉంది"</string>
</resources>
diff --git a/quickstep/res/values-th/strings.xml b/quickstep/res/values-th/strings.xml
index c2e173a..c0e78ce 100644
--- a/quickstep/res/values-th/strings.xml
+++ b/quickstep/res/values-th/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"แอปล่าสุด"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g> <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"<1 นาที"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"แอปที่เป็นโทนสีเทา"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"วันนี้เหลืออีก <xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-tl/strings.xml b/quickstep/res/values-tl/strings.xml
index 5588d03..76a0b25 100644
--- a/quickstep/res/values-tl/strings.xml
+++ b/quickstep/res/values-tl/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Mga kamakailang app"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 min"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"App na grayscale"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"<xliff:g id="TIME">%1$s</xliff:g> na lang ngayon"</string>
</resources>
diff --git a/quickstep/res/values-tr/strings.xml b/quickstep/res/values-tr/strings.xml
index 40e0d89..8b59c7b 100644
--- a/quickstep/res/values-tr/strings.xml
+++ b/quickstep/res/values-tr/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Son uygulamalar"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 dk."</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"Uygulama gri tonlamada"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"Bugün <xliff:g id="TIME">%1$s</xliff:g> kaldı"</string>
</resources>
diff --git a/quickstep/res/values-uk/strings.xml b/quickstep/res/values-uk/strings.xml
index 104c82c..39c3848 100644
--- a/quickstep/res/values-uk/strings.xml
+++ b/quickstep/res/values-uk/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Нещодавні додатки"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 хв"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"Додаток у відтінку сірого"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"Сьогодні залишилося <xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-ur/strings.xml b/quickstep/res/values-ur/strings.xml
index 481bda0..4fd9e69 100644
--- a/quickstep/res/values-ur/strings.xml
+++ b/quickstep/res/values-ur/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"حالیہ ایپس"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>،<xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 منٹ"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"ایپ خاکستری کیا گیا"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"آج <xliff:g id="TIME">%1$s</xliff:g> بچا ہے"</string>
</resources>
diff --git a/quickstep/res/values-uz/strings.xml b/quickstep/res/values-uz/strings.xml
index 7e9f955..466d79e 100644
--- a/quickstep/res/values-uz/strings.xml
+++ b/quickstep/res/values-uz/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Yaqinda ishlatilgan ilovalar"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 daqiqa"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"Ilova kulrang rejimida"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"Bugun <xliff:g id="TIME">%1$s</xliff:g> qoldi"</string>
</resources>
diff --git a/quickstep/res/values-vi/strings.xml b/quickstep/res/values-vi/strings.xml
index 3d42063..842b22b 100644
--- a/quickstep/res/values-vi/strings.xml
+++ b/quickstep/res/values-vi/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Ứng dụng gần đây"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 phút"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"Ứng dụng có thang màu xám"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"Hôm nay còn <xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-zh-rCN/strings.xml b/quickstep/res/values-zh-rCN/strings.xml
index 4a13d14..951489f 100644
--- a/quickstep/res/values-zh-rCN/strings.xml
+++ b/quickstep/res/values-zh-rCN/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"最近用过的应用"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>(<xliff:g id="REMAINING_TIME">%2$s</xliff:g>)"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"不到 1 分钟"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"灰度模式下的应用"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"今天还可使用 <xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-zh-rHK/strings.xml b/quickstep/res/values-zh-rHK/strings.xml
index 02d9b8e..361623d 100644
--- a/quickstep/res/values-zh-rHK/strings.xml
+++ b/quickstep/res/values-zh-rHK/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"最近使用的應用程式"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>,<xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"少於 1 分鐘"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"切換至灰階螢幕的應用程式"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"今天剩餘時間:<xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-zh-rTW/strings.xml b/quickstep/res/values-zh-rTW/strings.xml
index 20181fd..6938d3e 100644
--- a/quickstep/res/values-zh-rTW/strings.xml
+++ b/quickstep/res/values-zh-rTW/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"最近使用的應用程式"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g> (<xliff:g id="REMAINING_TIME">%2$s</xliff:g>)"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 分鐘"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"切換為灰階模式的應用程式"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"今天還能使用 <xliff:g id="TIME">%1$s</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-zu/strings.xml b/quickstep/res/values-zu/strings.xml
index abbbc95..98f7b02 100644
--- a/quickstep/res/values-zu/strings.xml
+++ b/quickstep/res/values-zu/strings.xml
@@ -30,6 +30,5 @@
<string name="accessibility_recent_apps" msgid="4058661986695117371">"Izinhlelo zokusebenza zakamuva"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 iminithi"</string>
- <string name="app_in_grayscale" msgid="1108706002158384887">"Uhlelo lokusebenza nge-grayscale"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"<xliff:g id="TIME">%1$s</xliff:g> esele namhlanje"</string>
</resources>
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 9c97c8c..97f2de7 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -24,7 +24,7 @@
<dimen name="task_corner_radius_small">2dp</dimen>
<dimen name="recents_page_spacing">10dp</dimen>
<dimen name="recents_clear_all_deadzone_vertical_margin">70dp</dimen>
- <dimen name="quickscrub_adjacent_visible_width">20dp</dimen>
+ <dimen name="overview_peek_distance">32dp</dimen>
<!-- The speed in dp/s at which the user needs to be scrolling in recents such that we start
loading full resolution screenshots. -->
diff --git a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
index c5475d6..f77bd65 100644
--- a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
+++ b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
@@ -20,15 +20,16 @@
import static com.android.launcher3.BaseActivity.INVISIBLE_BY_APP_TRANSITIONS;
import static com.android.launcher3.BaseActivity.INVISIBLE_BY_PENDING_FLAGS;
import static com.android.launcher3.BaseActivity.PENDING_INVISIBLE_BY_WALLPAPER_ANIMATION;
-import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.Utilities.postAsyncCallback;
import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PROGRESS;
import static com.android.launcher3.anim.Interpolators.AGGRESSIVE_EASE;
import static com.android.launcher3.anim.Interpolators.DEACCEL_1_7;
+import static com.android.launcher3.anim.Interpolators.EXAGGERATED_EASE;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.dragndrop.DragLayer.ALPHA_INDEX_TRANSITIONS;
+import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION;
import static com.android.quickstep.TaskUtils.taskIsATargetWithMode;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING;
@@ -45,6 +46,7 @@
import android.content.res.Resources;
import android.graphics.Matrix;
import android.graphics.Rect;
+import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.CancellationSignal;
@@ -52,10 +54,8 @@
import android.os.Looper;
import android.util.Pair;
import android.view.View;
-import android.view.ViewGroup;
import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
-import com.android.launcher3.InsettableFrameLayout.LayoutParams;
import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.dragndrop.DragLayer;
@@ -103,13 +103,18 @@
private static final String CONTROL_REMOTE_APP_TRANSITION_PERMISSION =
"android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS";
- private static final int APP_LAUNCH_DURATION = 500;
+ private static final long APP_LAUNCH_DURATION = 500;
// Use a shorter duration for x or y translation to create a curve effect
- private static final int APP_LAUNCH_CURVED_DURATION = APP_LAUNCH_DURATION / 2;
+ private static final long APP_LAUNCH_CURVED_DURATION = APP_LAUNCH_DURATION / 2;
+ private static final long APP_LAUNCH_ALPHA_DURATION = 50;
+
// We scale the durations for the downward app launch animations (minus the scale animation).
private static final float APP_LAUNCH_DOWN_DUR_SCALE_FACTOR = 0.8f;
- private static final int APP_LAUNCH_ALPHA_START_DELAY = 32;
- private static final int APP_LAUNCH_ALPHA_DURATION = 50;
+ private static final long APP_LAUNCH_DOWN_DURATION =
+ (long) (APP_LAUNCH_DURATION * APP_LAUNCH_DOWN_DUR_SCALE_FACTOR);
+ private static final long APP_LAUNCH_DOWN_CURVED_DURATION = APP_LAUNCH_DOWN_DURATION / 2;
+ private static final long APP_LAUNCH_ALPHA_DOWN_DURATION =
+ (long) (APP_LAUNCH_ALPHA_DURATION * APP_LAUNCH_DOWN_DUR_SCALE_FACTOR);
public static final int RECENTS_LAUNCH_DURATION = 336;
private static final int LAUNCHER_RESUME_START_DELAY = 100;
@@ -207,11 +212,11 @@
// Note that this duration is a guess as we do not know if the animation will be a
// recents launch or not for sure until we know the opening app targets.
- int duration = fromRecents
+ long duration = fromRecents
? RECENTS_LAUNCH_DURATION
: APP_LAUNCH_DURATION;
- int statusBarTransitionDelay = duration - STATUS_BAR_TRANSITION_DURATION
+ long statusBarTransitionDelay = duration - STATUS_BAR_TRANSITION_DURATION
- STATUS_BAR_TRANSITION_PRE_DELAY;
return ActivityOptionsCompat.makeRemoteAnimation(new RemoteAnimationAdapterCompat(
runner, duration, statusBarTransitionDelay));
@@ -266,7 +271,8 @@
}
if (!isAllOpeningTargetTrs) break;
}
- playIconAnimators(anim, v, windowTargetBounds, !isAllOpeningTargetTrs);
+ anim.play(getOpeningWindowAnimators(v, targets, windowTargetBounds,
+ !isAllOpeningTargetTrs));
if (launcherClosing) {
Pair<AnimatorSet, Runnable> launcherContentAnimator =
getLauncherContentAnimator(true /* isAppOpening */,
@@ -279,7 +285,6 @@
}
});
}
- anim.play(getOpeningWindowAnimators(v, targets, windowTargetBounds));
}
/**
@@ -398,124 +403,13 @@
float[] alphas, float[] trans);
/**
- * Animators for the "floating view" of the view used to launch the target.
- */
- private void playIconAnimators(AnimatorSet appOpenAnimator, View v, Rect windowTargetBounds,
- boolean toggleVisibility) {
- final boolean isBubbleTextView = v instanceof BubbleTextView;
- if (mFloatingView != null) {
- mFloatingView.setTranslationX(0);
- mFloatingView.setTranslationY(0);
- mFloatingView.setScaleX(1);
- mFloatingView.setScaleY(1);
- mFloatingView.setAlpha(1);
- mFloatingView.setBackground(null);
- }
- Rect rect = new Rect();
- mFloatingView = FloatingIconView.getFloatingIconView(mLauncher, v, toggleVisibility,
- true /* useDrawableAsIs */, -1 /* aspectRatio */, rect, mFloatingView);
-
- int viewLocationStart = mIsRtl ? windowTargetBounds.width() - rect.right : rect.left;
- LayoutParams lp = (LayoutParams) mFloatingView.getLayoutParams();
- // Special RTL logic is needed to handle the window target bounds.
- lp.leftMargin = mIsRtl ? windowTargetBounds.width() - rect.right : rect.left;
- mFloatingView.setLayoutParams(lp);
-
- int[] dragLayerBounds = new int[2];
- mDragLayer.getLocationOnScreen(dragLayerBounds);
-
- // Animate the app icon to the center of the window bounds in screen coordinates.
- float centerX = windowTargetBounds.centerX() - dragLayerBounds[0];
- float centerY = windowTargetBounds.centerY() - dragLayerBounds[1];
-
- float xPosition = mIsRtl
- ? windowTargetBounds.width() - lp.getMarginStart() - rect.width()
- : lp.getMarginStart();
- float dX = centerX - xPosition - (lp.width / 2f);
- float dY = centerY - lp.topMargin - (lp.height / 2f);
-
- ObjectAnimator x = ObjectAnimator.ofFloat(mFloatingView, View.TRANSLATION_X, 0f, dX);
- ObjectAnimator y = ObjectAnimator.ofFloat(mFloatingView, View.TRANSLATION_Y, 0f, dY);
-
- // Use upward animation for apps that are either on the bottom half of the screen, or are
- // relatively close to the center.
- boolean useUpwardAnimation = lp.topMargin > centerY
- || Math.abs(dY) < mLauncher.getDeviceProfile().cellHeightPx;
- if (useUpwardAnimation) {
- x.setDuration(APP_LAUNCH_CURVED_DURATION);
- y.setDuration(APP_LAUNCH_DURATION);
- } else {
- x.setDuration((long) (APP_LAUNCH_DOWN_DUR_SCALE_FACTOR * APP_LAUNCH_DURATION));
- y.setDuration((long) (APP_LAUNCH_DOWN_DUR_SCALE_FACTOR * APP_LAUNCH_CURVED_DURATION));
- }
- x.setInterpolator(AGGRESSIVE_EASE);
- y.setInterpolator(AGGRESSIVE_EASE);
- appOpenAnimator.play(x);
- appOpenAnimator.play(y);
-
- // Scale the app icon to take up the entire screen. This simplifies the math when
- // animating the app window position / scale.
- float maxScaleX = windowTargetBounds.width() / (float) rect.width();
- float maxScaleY = windowTargetBounds.height() / (float) rect.height();
- float scale = Math.max(maxScaleX, maxScaleY);
- float startScale = 1f;
- if (isBubbleTextView && !(v.getParent() instanceof DeepShortcutView)) {
- Drawable dr = ((BubbleTextView) v).getIcon();
- if (dr instanceof FastBitmapDrawable) {
- startScale = ((FastBitmapDrawable) dr).getAnimatedScale();
- }
- }
-
- ObjectAnimator scaleAnim = ObjectAnimator
- .ofFloat(mFloatingView, SCALE_PROPERTY, startScale, scale);
- scaleAnim.setDuration(APP_LAUNCH_DURATION)
- .setInterpolator(Interpolators.EXAGGERATED_EASE);
- appOpenAnimator.play(scaleAnim);
-
- // Fade out the app icon.
- ObjectAnimator alpha = ObjectAnimator.ofFloat(mFloatingView, View.ALPHA, 1f, 0f);
- if (useUpwardAnimation) {
- alpha.setStartDelay(APP_LAUNCH_ALPHA_START_DELAY);
- alpha.setDuration(APP_LAUNCH_ALPHA_DURATION);
- } else {
- alpha.setStartDelay((long) (APP_LAUNCH_DOWN_DUR_SCALE_FACTOR
- * APP_LAUNCH_ALPHA_START_DELAY));
- alpha.setDuration((long) (APP_LAUNCH_DOWN_DUR_SCALE_FACTOR * APP_LAUNCH_ALPHA_DURATION));
- }
- alpha.setInterpolator(LINEAR);
- appOpenAnimator.play(alpha);
-
- appOpenAnimator.addListener(mFloatingView);
- appOpenAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- // Reset launcher to normal state
- if (isBubbleTextView) {
- ((BubbleTextView) v).setStayPressed(false);
- }
- v.setVisibility(View.VISIBLE);
- ((ViewGroup) mDragLayer.getParent()).getOverlay().remove(mFloatingView);
- }
- });
- }
-
- /**
* @return Animator that controls the window of the opening targets.
*/
private ValueAnimator getOpeningWindowAnimators(View v, RemoteAnimationTargetCompat[] targets,
- Rect windowTargetBounds) {
+ Rect windowTargetBounds, boolean toggleVisibility) {
Rect bounds = new Rect();
- if (v.getParent() instanceof DeepShortcutView) {
- // Deep shortcut views have their icon drawn in a separate view.
- DeepShortcutView view = (DeepShortcutView) v.getParent();
- mDragLayer.getDescendantRectRelativeToSelf(view.getIconView(), bounds);
- } else if (v instanceof BubbleTextView) {
- ((BubbleTextView) v).getIconBounds(bounds);
- } else {
- mDragLayer.getDescendantRectRelativeToSelf(v, bounds);
- }
- int[] floatingViewBounds = new int[2];
-
+ mFloatingView = FloatingIconView.getFloatingIconView(mLauncher, v, toggleVisibility,
+ bounds, true /* isOpening */, mFloatingView);
Rect crop = new Rect();
Matrix matrix = new Matrix();
@@ -526,37 +420,99 @@
SyncRtSurfaceTransactionApplierCompat surfaceApplier =
new SyncRtSurfaceTransactionApplierCompat(mFloatingView);
+ // Scale the app icon to take up the entire screen. This simplifies the math when
+ // animating the app window position / scale.
+ float maxScaleX = windowTargetBounds.width() / (float) bounds.width();
+ // We use windowTargetBounds.width for scaleY too since we start off the animation where the
+ // window is clipped to a square.
+ float maxScaleY = windowTargetBounds.width() / (float) bounds.height();
+ float scale = Math.max(maxScaleX, maxScaleY);
+ float startScale = 1f;
+ if (v instanceof BubbleTextView && !(v.getParent() instanceof DeepShortcutView)) {
+ Drawable dr = ((BubbleTextView) v).getIcon();
+ if (dr instanceof FastBitmapDrawable) {
+ startScale = ((FastBitmapDrawable) dr).getAnimatedScale();
+ }
+ }
+ final float initialStartScale = startScale;
+
+ int[] dragLayerBounds = new int[2];
+ mDragLayer.getLocationOnScreen(dragLayerBounds);
+
+ // Animate the app icon to the center of the window bounds in screen coordinates.
+ float centerX = windowTargetBounds.centerX() - dragLayerBounds[0];
+ float centerY = windowTargetBounds.centerY() - dragLayerBounds[1];
+
+ float dX = centerX - bounds.centerX();
+ float dY = centerY - bounds.centerY();
+
+ boolean useUpwardAnimation = bounds.top > centerY
+ || Math.abs(dY) < mLauncher.getDeviceProfile().cellHeightPx;
+ final long xDuration = useUpwardAnimation ? APP_LAUNCH_CURVED_DURATION
+ : APP_LAUNCH_DOWN_DURATION;
+ final long yDuration = useUpwardAnimation ? APP_LAUNCH_DURATION
+ : APP_LAUNCH_DOWN_CURVED_DURATION;
+ final long alphaDuration = useUpwardAnimation ? APP_LAUNCH_ALPHA_DURATION
+ : APP_LAUNCH_ALPHA_DOWN_DURATION;
+
+ RectF targetBounds = new RectF(windowTargetBounds);
+ RectF currentBounds = new RectF();
+ RectF temp = new RectF();
+
ValueAnimator appAnimator = ValueAnimator.ofFloat(0, 1);
appAnimator.setDuration(APP_LAUNCH_DURATION);
+ appAnimator.setInterpolator(LINEAR);
+ appAnimator.addListener(mFloatingView);
+ appAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (v instanceof BubbleTextView) {
+ ((BubbleTextView) v).setStayPressed(false);
+ }
+ }
+ });
+
+ float shapeRevealDuration = APP_LAUNCH_DURATION * SHAPE_PROGRESS_DURATION;
appAnimator.addUpdateListener(new MultiValueUpdateListener() {
- // Fade alpha for the app window.
- FloatProp mAlpha = new FloatProp(0f, 1f, 0, 60, LINEAR);
+ 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,
+ EXAGGERATED_EASE);
+ FloatProp mIconAlpha = new FloatProp(1f, 0f, shapeRevealDuration, alphaDuration,
+ LINEAR);
+ FloatProp mCropHeight = new FloatProp(windowTargetBounds.width(),
+ windowTargetBounds.height(), 0, shapeRevealDuration, AGGRESSIVE_EASE);
@Override
public void onUpdate(float percent) {
- final float easePercent = AGGRESSIVE_EASE.getInterpolation(percent);
-
// Calculate app icon size.
- float iconWidth = bounds.width() * mFloatingView.getScaleX();
- float iconHeight = bounds.height() * mFloatingView.getScaleY();
+ float iconWidth = bounds.width() * mIconScale.value;
+ float iconHeight = bounds.height() * mIconScale.value;
+
+ // Animate the window crop so that it starts off as a square, and then reveals
+ // horizontally.
+ int windowWidth = windowTargetBounds.width();
+ int windowHeight = (int) mCropHeight.value;
+ crop.set(0, 0, windowWidth, windowHeight);
// Scale the app window to match the icon size.
- float scaleX = iconWidth / windowTargetBounds.width();
- float scaleY = iconHeight / windowTargetBounds.height();
- float scale = Math.min(1f, Math.min(scaleX, scaleY));
+ float scaleX = iconWidth / windowWidth;
+ float scaleY = iconHeight / windowHeight;
+ float scale = Math.min(1f, Math.max(scaleX, scaleY));
- // Position the scaled window on top of the icon
- int windowWidth = windowTargetBounds.width();
- int windowHeight = windowTargetBounds.height();
float scaledWindowWidth = windowWidth * scale;
float scaledWindowHeight = windowHeight * scale;
float offsetX = (scaledWindowWidth - iconWidth) / 2;
float offsetY = (scaledWindowHeight - iconHeight) / 2;
- mFloatingView.getLocationOnScreen(floatingViewBounds);
- float transX0 = floatingViewBounds[0] - offsetX;
- float transY0 = floatingViewBounds[1] - offsetY;
+ // 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;
float windowRadius = 0;
if (!mDeviceProfile.isMultiWindowMode &&
@@ -565,19 +521,9 @@
.getWindowCornerRadius();
}
- // Animate the window crop so that it starts off as a square, and then reveals
- // horizontally.
- float cropHeight = windowHeight * easePercent + windowWidth * (1 - easePercent);
- float initialTop = (windowHeight - windowWidth) / 2f;
- crop.left = 0;
- crop.top = (int) (initialTop * (1 - easePercent));
- crop.right = windowWidth;
- crop.bottom = (int) (crop.top + cropHeight);
-
SurfaceParams[] params = new SurfaceParams[targets.length];
for (int i = targets.length - 1; i >= 0; i--) {
RemoteAnimationTargetCompat target = targets[i];
-
Rect targetCrop;
final float alpha;
final float cornerRadius;
@@ -585,12 +531,15 @@
matrix.setScale(scale, scale);
matrix.postTranslate(transX0, transY0);
targetCrop = crop;
- alpha = mAlpha.value;
+ alpha = 1f - mIconAlpha.value;
cornerRadius = windowRadius;
+ matrix.mapRect(currentBounds, targetBounds);
+ mFloatingView.update(currentBounds, mIconAlpha.value, percent, 0f,
+ cornerRadius * scale, true /* isOpening */);
} else {
matrix.setTranslate(target.position.x, target.position.y);
- alpha = 1f;
targetCrop = target.sourceContainerBounds;
+ alpha = 1f;
cornerRadius = 0;
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
index e74d84d..f0204b9 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
@@ -19,6 +19,9 @@
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_FADE;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_SCALE;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_TRANSLATE_X;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_TRANSLATE_Y;
+import static com.android.launcher3.anim.AnimatorSetBuilder.FLAG_DONT_ANIMATE_OVERVIEW;
import static com.android.launcher3.anim.Interpolators.AGGRESSIVE_EASE_IN_OUT;
import static com.android.launcher3.anim.Interpolators.LINEAR;
@@ -28,6 +31,7 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
+import com.android.launcher3.LauncherState.ScaleAndTranslation;
import com.android.launcher3.LauncherStateManager.AnimationConfig;
import com.android.launcher3.LauncherStateManager.StateHandler;
import com.android.launcher3.anim.AnimatorSetBuilder;
@@ -53,19 +57,30 @@
@Override
public void setState(@NonNull LauncherState state) {
- float[] scaleTranslationY = state.getOverviewScaleAndTranslationY(mLauncher);
- SCALE_PROPERTY.set(mRecentsView, scaleTranslationY[0]);
- mRecentsView.setTranslationY(scaleTranslationY[1]);
+ ScaleAndTranslation scaleAndTranslation = state
+ .getOverviewScaleAndTranslation(mLauncher);
+ SCALE_PROPERTY.set(mRecentsView, scaleAndTranslation.scale);
+ float translationX = scaleAndTranslation.translationX;
+ if (mRecentsView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
+ translationX = -translationX;
+ }
+ mRecentsView.setTranslationX(translationX);
+ mRecentsView.setTranslationY(scaleAndTranslation.translationY);
getContentAlphaProperty().set(mRecentsView, state.overviewUi ? 1f : 0);
}
@Override
public final void setStateWithAnimation(@NonNull final LauncherState toState,
@NonNull AnimatorSetBuilder builder, @NonNull AnimationConfig config) {
- if (!config.playAtomicComponent()) {
+ boolean playAtomicOverviewComponent = config.playAtomicOverviewScaleComponent()
+ || config.playAtomicOverviewPeekComponent();
+ if (!playAtomicOverviewComponent) {
// The entire recents animation is played atomically.
return;
}
+ if (builder.hasFlag(FLAG_DONT_ANIMATE_OVERVIEW)) {
+ return;
+ }
setStateWithAnimationInternal(toState, builder, config);
}
@@ -79,29 +94,25 @@
void setStateWithAnimationInternal(@NonNull final LauncherState toState,
@NonNull AnimatorSetBuilder builder, @NonNull AnimationConfig config) {
PropertySetter setter = config.getPropertySetter(builder);
- float[] scaleTranslationY = toState.getOverviewScaleAndTranslationY(mLauncher);
- Interpolator scaleAndTransYInterpolator = getScaleAndTransYInterpolator(toState, builder);
- setter.setFloat(mRecentsView, SCALE_PROPERTY, scaleTranslationY[0],
- scaleAndTransYInterpolator);
- setter.setFloat(mRecentsView, View.TRANSLATION_Y, scaleTranslationY[1],
- scaleAndTransYInterpolator);
+ ScaleAndTranslation scaleAndTranslation = toState.getOverviewScaleAndTranslation(mLauncher);
+ Interpolator scaleInterpolator = builder.getInterpolator(ANIM_OVERVIEW_SCALE, LINEAR);
+ setter.setFloat(mRecentsView, SCALE_PROPERTY, scaleAndTranslation.scale, scaleInterpolator);
+ Interpolator translateXInterpolator = builder.getInterpolator(
+ ANIM_OVERVIEW_TRANSLATE_X, LINEAR);
+ Interpolator translateYInterpolator = builder.getInterpolator(
+ ANIM_OVERVIEW_TRANSLATE_Y, LINEAR);
+ float translationX = scaleAndTranslation.translationX;
+ if (mRecentsView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
+ translationX = -translationX;
+ }
+ setter.setFloat(mRecentsView, View.TRANSLATION_X, translationX, translateXInterpolator);
+ setter.setFloat(mRecentsView, View.TRANSLATION_Y, scaleAndTranslation.translationY,
+ translateYInterpolator);
setter.setFloat(mRecentsView, getContentAlphaProperty(), toState.overviewUi ? 1 : 0,
builder.getInterpolator(ANIM_OVERVIEW_FADE, AGGRESSIVE_EASE_IN_OUT));
}
/**
- * Get the interpolator to use for the scale and translation Y animation for the view.
- *
- * @param toState state to animate to
- * @param builder animator set builder
- * @return interpolator for scale and trans Y recents view animation
- */
- Interpolator getScaleAndTransYInterpolator(@NonNull final LauncherState toState,
- @NonNull AnimatorSetBuilder builder) {
- return builder.getInterpolator(ANIM_OVERVIEW_SCALE, LINEAR);
- }
-
- /**
* Get property for content alpha for the recents view.
*
* @return the float property for the view's content alpha
diff --git a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
index 25e1c89..6d730b6 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
@@ -41,8 +41,11 @@
import com.android.launcher3.LauncherStateManager.StateHandler;
import com.android.launcher3.QuickstepAppTransitionManagerImpl;
import com.android.launcher3.Utilities;
+import com.android.launcher3.dragndrop.DragLayer;
import com.android.quickstep.OverviewInteractionState;
import com.android.quickstep.RecentsModel;
+import com.android.quickstep.SysUINavigationMode;
+import com.android.quickstep.SysUINavigationMode.NavigationModeChangeListener;
import com.android.quickstep.util.RemoteFadeOutAnimationListener;
import com.android.systemui.shared.system.ActivityCompat;
@@ -52,8 +55,11 @@
public class UiFactory extends RecentsUiFactory {
- public static void setOnTouchControllersChangedListener(Context context, Runnable listener) {
- OverviewInteractionState.INSTANCE.get(context).setOnSwipeUpSettingChangedListener(listener);
+ public static Runnable enableLiveTouchControllerChanges(DragLayer dl) {
+ NavigationModeChangeListener listener = m -> dl.recreateControllers();
+ SysUINavigationMode mode = SysUINavigationMode.INSTANCE.get(dl.getContext());
+ mode.addModeChangeListener(listener);
+ return () -> mode.removeModeChangeListener(listener);
}
public static StateHandler[] getStateHandler(Launcher launcher) {
@@ -89,8 +95,8 @@
@Override
public void onStateTransitionComplete(LauncherState finalState) {
- boolean swipeUpEnabled = OverviewInteractionState.INSTANCE.get(launcher)
- .isSwipeUpGestureEnabled();
+ boolean swipeUpEnabled = SysUINavigationMode.INSTANCE.get(launcher).getMode()
+ .hasGestures;
LauncherState prevState = launcher.getStateManager().getLastState();
if (((swipeUpEnabled && finalState == OVERVIEW) || (!swipeUpEnabled
diff --git a/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
similarity index 84%
rename from quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java
rename to quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
index 5ae562e..ab24f5f 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.launcher3.uioverrides;
+package com.android.launcher3.uioverrides.states;
import static com.android.launcher3.LauncherAnimUtils.ALL_APPS_TRANSITION_MS;
import static com.android.launcher3.anim.Interpolators.DEACCEL_2;
@@ -60,10 +60,10 @@
}
@Override
- public float[] getWorkspaceScaleAndTranslation(Launcher launcher) {
- float[] scaleAndTranslation = LauncherState.OVERVIEW.getWorkspaceScaleAndTranslation(
- launcher);
- scaleAndTranslation[0] = 1;
+ public ScaleAndTranslation getWorkspaceScaleAndTranslation(Launcher launcher) {
+ ScaleAndTranslation scaleAndTranslation = LauncherState.OVERVIEW
+ .getWorkspaceScaleAndTranslation(launcher);
+ scaleAndTranslation.scale = 1;
return scaleAndTranslation;
}
@@ -78,9 +78,9 @@
}
@Override
- public float[] getOverviewScaleAndTranslationY(Launcher launcher) {
+ public ScaleAndTranslation getOverviewScaleAndTranslation(Launcher launcher) {
float slightParallax = -launcher.getDeviceProfile().allAppsCellHeightPx * 0.3f;
- return new float[] {0.9f, slightParallax};
+ return new ScaleAndTranslation(0.9f, 0f, slightParallax);
}
@Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/LandscapeEdgeSwipeController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/LandscapeEdgeSwipeController.java
similarity index 96%
rename from quickstep/src/com/android/launcher3/uioverrides/LandscapeEdgeSwipeController.java
rename to quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/LandscapeEdgeSwipeController.java
index 086cbdb..0605953 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/LandscapeEdgeSwipeController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/LandscapeEdgeSwipeController.java
@@ -1,4 +1,4 @@
-package com.android.launcher3.uioverrides;
+package com.android.launcher3.uioverrides.touchcontrollers;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
@@ -41,7 +41,7 @@
@Override
protected LauncherState getTargetState(LauncherState fromState, boolean isDragTowardPositive) {
- boolean draggingFromNav = mLauncher.getDeviceProfile().isSeascape() != isDragTowardPositive;
+ boolean draggingFromNav = mLauncher.getDeviceProfile().isSeascape() == isDragTowardPositive;
return draggingFromNav ? OVERVIEW : NORMAL;
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/PortraitStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
similarity index 96%
rename from quickstep/src/com/android/launcher3/uioverrides/PortraitStatesTouchController.java
rename to quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
index d20ffbb..ce50b68 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/PortraitStatesTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.launcher3.uioverrides;
+package com.android.launcher3.uioverrides.touchcontrollers;
import static com.android.launcher3.AbstractFloatingView.TYPE_ACCESSIBLE;
import static com.android.launcher3.LauncherState.ALL_APPS;
@@ -43,6 +43,8 @@
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.touch.AbstractStateChangeTouchController;
import com.android.launcher3.touch.SwipeDetector;
+import com.android.launcher3.uioverrides.states.OverviewState;
+import com.android.launcher3.uioverrides.touchcontrollers.PortraitOverviewStateTouchHelper;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.quickstep.RecentsModel;
@@ -195,6 +197,7 @@
final AnimatorSetBuilder builder = totalShift == 0 ? new AnimatorSetBuilder()
: getAnimatorSetBuilderForStates(mFromState, mToState);
+ updateAnimatorBuilderOnReinit(builder);
cancelPendingAnim();
@@ -228,6 +231,12 @@
return 1 / totalShift;
}
+ /**
+ * Give subclasses the chance to update the animation when we re-initialize towards a new state.
+ */
+ protected void updateAnimatorBuilderOnReinit(AnimatorSetBuilder builder) {
+ }
+
private void cancelPendingAnim() {
if (mPendingAnimation != null) {
mPendingAnimation.finish(false, Touch.SWIPE);
diff --git a/quickstep/src/com/android/launcher3/uioverrides/StatusBarTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/StatusBarTouchController.java
similarity index 98%
rename from quickstep/src/com/android/launcher3/uioverrides/StatusBarTouchController.java
rename to quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/StatusBarTouchController.java
index 8f33e40..12e6f12 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/StatusBarTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/StatusBarTouchController.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.launcher3.uioverrides;
+package com.android.launcher3.uioverrides.touchcontrollers;
import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_MOVE;
diff --git a/quickstep/src/com/android/quickstep/ActivityControlHelper.java b/quickstep/src/com/android/quickstep/ActivityControlHelper.java
index 418f7f4..a71b7bb 100644
--- a/quickstep/src/com/android/quickstep/ActivityControlHelper.java
+++ b/quickstep/src/com/android/quickstep/ActivityControlHelper.java
@@ -53,6 +53,8 @@
void onSwipeUpComplete(T activity);
+ void onAssistantVisibilityChanged(float visibility);
+
@NonNull HomeAnimationFactory prepareHomeUI(T activity);
AnimationFactory prepareRecentsUI(T activity, boolean activityVisible,
diff --git a/quickstep/src/com/android/quickstep/InstantAppResolverImpl.java b/quickstep/src/com/android/quickstep/InstantAppResolverImpl.java
index 12757c0..3e9872a 100644
--- a/quickstep/src/com/android/quickstep/InstantAppResolverImpl.java
+++ b/quickstep/src/com/android/quickstep/InstantAppResolverImpl.java
@@ -19,16 +19,11 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ApplicationInfo;
-import android.content.pm.InstantAppInfo;
import android.content.pm.PackageManager;
-import android.util.Log;
import com.android.launcher3.AppInfo;
import com.android.launcher3.util.InstantAppResolver;
-import java.util.ArrayList;
-import java.util.List;
-
/**
* Implementation of InstantAppResolver using platform APIs
*/
@@ -40,8 +35,7 @@
private final PackageManager mPM;
- public InstantAppResolverImpl(Context context)
- throws NoSuchMethodException, ClassNotFoundException {
+ public InstantAppResolverImpl(Context context) {
mPM = context.getPackageManager();
}
@@ -55,23 +49,4 @@
ComponentName cn = info.getTargetComponent();
return cn != null && cn.getClassName().equals(COMPONENT_CLASS_MARKER);
}
-
- @Override
- public List<ApplicationInfo> getInstantApps() {
- try {
- List<ApplicationInfo> result = new ArrayList<>();
- for (InstantAppInfo iai : mPM.getInstantApps()) {
- ApplicationInfo info = iai.getApplicationInfo();
- if (info != null) {
- result.add(info);
- }
- }
- return result;
- } catch (SecurityException se) {
- Log.w(TAG, "getInstantApps failed. Launcher may not be the default home app.", se);
- } catch (Exception e) {
- Log.e(TAG, "Error calling API: getInstantApps", e);
- }
- return super.getInstantApps();
- }
}
diff --git a/quickstep/src/com/android/quickstep/NavBarModeOverlayResourceObserver.java b/quickstep/src/com/android/quickstep/NavBarModeOverlayResourceObserver.java
deleted file mode 100644
index d44c253..0000000
--- a/quickstep/src/com/android/quickstep/NavBarModeOverlayResourceObserver.java
+++ /dev/null
@@ -1,85 +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.Intent.ACTION_OVERLAY_CHANGED;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.res.Resources;
-import android.util.Log;
-
-import com.android.systemui.shared.system.QuickStepContract;
-
-/**
- * Observer for the resource config that specifies the navigation bar mode.
- */
-public class NavBarModeOverlayResourceObserver extends BroadcastReceiver {
-
- private static final String TAG = "NavBarModeOverlayResourceObserver";
-
- private static final String NAV_BAR_INTERACTION_MODE_RES_NAME =
- "config_navBarInteractionMode";
-
- private final Context mContext;
- private final OnChangeListener mOnChangeListener;
-
- public NavBarModeOverlayResourceObserver(Context context, OnChangeListener listener) {
- mContext = context;
- mOnChangeListener = listener;
- }
-
- public void register() {
- IntentFilter filter = new IntentFilter(ACTION_OVERLAY_CHANGED);
- filter.addDataScheme("package");
- mContext.registerReceiver(this, filter);
- }
-
- @Override
- public void onReceive(Context context, Intent intent) {
- mOnChangeListener.onNavBarModeChanged(getSystemIntegerRes(context,
- NAV_BAR_INTERACTION_MODE_RES_NAME));
- }
-
- public interface OnChangeListener {
- void onNavBarModeChanged(int mode);
- }
-
- public static boolean isSwipeUpModeEnabled(Context context) {
- return QuickStepContract.isSwipeUpMode(getSystemIntegerRes(context,
- NAV_BAR_INTERACTION_MODE_RES_NAME));
- }
-
- public static boolean isEdgeToEdgeModeEnabled(Context context) {
- return QuickStepContract.isGesturalMode(getSystemIntegerRes(context,
- NAV_BAR_INTERACTION_MODE_RES_NAME));
- }
-
- private static int getSystemIntegerRes(Context context, String resName) {
- Resources res = context.getResources();
- int resId = res.getIdentifier(resName, "integer", "android");
-
- if (resId != 0) {
- return res.getInteger(resId);
- } else {
- Log.e(TAG, "Failed to get system resource ID. Incompatible framework version?");
- return -1;
- }
- }
-}
diff --git a/quickstep/src/com/android/quickstep/OverviewInteractionState.java b/quickstep/src/com/android/quickstep/OverviewInteractionState.java
index 903701d..ce472c6 100644
--- a/quickstep/src/com/android/quickstep/OverviewInteractionState.java
+++ b/quickstep/src/com/android/quickstep/OverviewInteractionState.java
@@ -30,8 +30,8 @@
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.UiThreadHelper;
+import com.android.quickstep.SysUINavigationMode.Mode;
import com.android.systemui.shared.recents.ISystemUiProxy;
-import com.android.systemui.shared.system.QuickStepContract;
import androidx.annotation.WorkerThread;
@@ -56,10 +56,7 @@
private static final int MSG_SET_PROXY = 200;
private static final int MSG_SET_BACK_BUTTON_ALPHA = 201;
- private static final int MSG_SET_SWIPE_UP_ENABLED = 202;
-
- // TODO: Discriminate between swipe up and edge to edge
- private final NavBarModeOverlayResourceObserver mSwipeUpSettingObserver;
+ private static final int MSG_APPLY_FLAGS = 202;
private final Context mContext;
private final Handler mUiHandler;
@@ -70,8 +67,6 @@
private boolean mSwipeUpEnabled;
private float mBackButtonAlpha = 1;
- private Runnable mOnSwipeUpSettingChangedListener;
-
private OverviewInteractionState(Context context) {
mContext = context;
@@ -81,20 +76,8 @@
mUiHandler = new Handler(this::handleUiMessage);
mBgHandler = new Handler(UiThreadHelper.getBackgroundLooper(), this::handleBgMessage);
- mSwipeUpEnabled = NavBarModeOverlayResourceObserver.isSwipeUpModeEnabled(mContext)
- || NavBarModeOverlayResourceObserver.isEdgeToEdgeModeEnabled(mContext);
- if (SwipeUpSetting.isSystemNavigationSettingAvailable()) {
- mSwipeUpSettingObserver = new NavBarModeOverlayResourceObserver(context,
- this::notifySwipeUpSettingChanged);
- mSwipeUpSettingObserver.register();
- resetHomeBounceSeenOnQuickstepEnabledFirstTime();
- } else {
- mSwipeUpSettingObserver = null;
- }
- }
-
- public boolean isSwipeUpGestureEnabled() {
- return mSwipeUpEnabled;
+ onNavigationModeChanged(SysUINavigationMode.INSTANCE.get(context)
+ .addModeChangeListener(this::onNavigationModeChanged));
}
public float getBackButtonAlpha() {
@@ -130,23 +113,13 @@
case MSG_SET_BACK_BUTTON_ALPHA:
applyBackButtonAlpha((float) msg.obj, msg.arg1 == 1);
return true;
- case MSG_SET_SWIPE_UP_ENABLED:
- mSwipeUpEnabled = msg.arg1 != 0;
- resetHomeBounceSeenOnQuickstepEnabledFirstTime();
-
- if (mOnSwipeUpSettingChangedListener != null) {
- mOnSwipeUpSettingChangedListener.run();
- }
+ case MSG_APPLY_FLAGS:
break;
}
applyFlags();
return true;
}
- public void setOnSwipeUpSettingChangedListener(Runnable listener) {
- mOnSwipeUpSettingChangedListener = listener;
- }
-
@WorkerThread
private void applyFlags() {
if (mISystemUiProxy == null) {
@@ -176,16 +149,12 @@
}
}
- private void notifySwipeUpSettingChanged(int mode) {
- boolean swipeUpEnabled = !QuickStepContract.isLegacyMode(mode);
- boolean gesturalEnabled = QuickStepContract.isGesturalMode(mode);
+ private void onNavigationModeChanged(SysUINavigationMode.Mode mode) {
+ FeatureFlags.SWIPE_HOME.updateStorage(mContext, mode == Mode.NO_BUTTON);
- FeatureFlags.SWIPE_HOME.updateStorage(mContext, gesturalEnabled);
- FeatureFlags.ENABLE_ASSISTANT_GESTURE.updateStorage(mContext, gesturalEnabled);
-
- mUiHandler.removeMessages(MSG_SET_SWIPE_UP_ENABLED);
- mUiHandler.obtainMessage(MSG_SET_SWIPE_UP_ENABLED, swipeUpEnabled ? 1 : 0, 0).
- sendToTarget();
+ mSwipeUpEnabled = mode.hasGestures;
+ resetHomeBounceSeenOnQuickstepEnabledFirstTime();
+ mBgHandler.obtainMessage(MSG_APPLY_FLAGS).sendToTarget();
}
private void resetHomeBounceSeenOnQuickstepEnabledFirstTime() {
diff --git a/quickstep/src/com/android/quickstep/RecentTasksList.java b/quickstep/src/com/android/quickstep/RecentTasksList.java
index e15a3f1..06a36c9 100644
--- a/quickstep/src/com/android/quickstep/RecentTasksList.java
+++ b/quickstep/src/com/android/quickstep/RecentTasksList.java
@@ -44,7 +44,6 @@
private final KeyguardManagerCompat mKeyguardManager;
private final MainThreadExecutor mMainThreadExecutor;
private final BackgroundExecutor mBgThreadExecutor;
- private final TaskListStabilizer mStabilizer = new TaskListStabilizer();
// The list change id, increments as the task list changes in the system
private int mChangeId;
@@ -74,14 +73,6 @@
});
}
- public void startStabilizationSession() {
- mStabilizer.startStabilizationSession();
- }
-
- public void endStabilizationSession() {
- mStabilizer.endStabilizationSession();
- }
-
/**
* Asynchronously fetches the list of recent tasks, reusing cached list if available.
*
@@ -93,7 +84,7 @@
final int requestLoadId = mChangeId;
Runnable resultCallback = callback == null
? () -> { }
- : () -> callback.accept(mStabilizer.reorder(mTasks));
+ : () -> callback.accept(mTasks);
if (mLastLoadedId == mChangeId && (!mLastLoadHadKeysOnly || loadKeysOnly)) {
// The list is up to date, callback with the same list
diff --git a/quickstep/src/com/android/quickstep/RecentsModel.java b/quickstep/src/com/android/quickstep/RecentsModel.java
index 56bc857..a65bc33 100644
--- a/quickstep/src/com/android/quickstep/RecentsModel.java
+++ b/quickstep/src/com/android/quickstep/RecentsModel.java
@@ -90,14 +90,6 @@
return mThumbnailCache;
}
- public void startStabilizationSession() {
- mTaskList.startStabilizationSession();
- }
-
- public void endStabilizationSession() {
- mTaskList.endStabilizationSession();
- }
-
/**
* Fetches the list of recent tasks.
*
diff --git a/quickstep/src/com/android/quickstep/SwipeUpSetting.java b/quickstep/src/com/android/quickstep/SwipeUpSetting.java
deleted file mode 100644
index 7f830f9..0000000
--- a/quickstep/src/com/android/quickstep/SwipeUpSetting.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.quickstep;
-
-import android.content.res.Resources;
-import android.util.Log;
-
-public final class SwipeUpSetting {
- private static final String TAG = "SwipeUpSetting";
-
- private static final String SWIPE_UP_SETTING_AVAILABLE_RES_NAME =
- "config_swipe_up_gesture_setting_available";
-
- public static boolean isSystemNavigationSettingAvailable() {
- return getSystemBooleanRes(SWIPE_UP_SETTING_AVAILABLE_RES_NAME);
- }
-
- private static boolean getSystemBooleanRes(String resName) {
- Resources res = Resources.getSystem();
- int resId = res.getIdentifier(resName, "bool", "android");
-
- if (resId != 0) {
- return res.getBoolean(resId);
- } else {
- Log.e(TAG, "Failed to get system resource ID. Incompatible framework version?");
- return false;
- }
- }
-}
diff --git a/quickstep/src/com/android/quickstep/SysUINavigationMode.java b/quickstep/src/com/android/quickstep/SysUINavigationMode.java
new file mode 100644
index 0000000..1953ecb
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/SysUINavigationMode.java
@@ -0,0 +1,127 @@
+/*
+ * 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 android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.Resources;
+import android.util.Log;
+
+import com.android.launcher3.util.MainThreadInitializedObject;
+import com.android.systemui.shared.system.QuickStepContract;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Observer for the resource config that specifies the navigation bar mode.
+ */
+public class SysUINavigationMode {
+
+ public enum Mode {
+ THREE_BUTTONS(false, 0),
+ TWO_BUTTONS(true, 1),
+ NO_BUTTON(true, 2);
+
+ public final boolean hasGestures;
+ public final int resValue;
+
+ Mode(boolean hasGestures, int resValue) {
+ this.hasGestures = hasGestures;
+ this.resValue = resValue;
+ }
+ }
+
+ public static MainThreadInitializedObject<SysUINavigationMode> INSTANCE =
+ new MainThreadInitializedObject<>(SysUINavigationMode::new);
+
+ private static final String TAG = "SysUINavigationMode";
+
+ private final String ACTION_OVERLAY_CHANGED = "android.intent.action.OVERLAY_CHANGED";
+ private static final String NAV_BAR_INTERACTION_MODE_RES_NAME =
+ "config_navBarInteractionMode";
+
+ private final Context mContext;
+ private Mode mMode;
+
+ private final List<NavigationModeChangeListener> mChangeListeners = new ArrayList<>();
+
+ public SysUINavigationMode(Context context) {
+ mContext = context;
+ initializeMode();
+
+ IntentFilter filter = new IntentFilter(ACTION_OVERLAY_CHANGED);
+ filter.addDataScheme("package");
+ mContext.registerReceiver(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Mode oldMode = mMode;
+ initializeMode();
+ if (mMode != oldMode) {
+ dispatchModeChange();
+ }
+ }
+ }, filter);
+ }
+
+ private void initializeMode() {
+ int modeInt = getSystemIntegerRes(mContext, NAV_BAR_INTERACTION_MODE_RES_NAME);
+ for(Mode m : Mode.values()) {
+ if (m.resValue == modeInt) {
+ mMode = m;
+ }
+ }
+ }
+
+ private void dispatchModeChange() {
+ for (NavigationModeChangeListener listener : mChangeListeners) {
+ listener.onNavigationModeChanged(mMode);
+ }
+ }
+
+ public Mode addModeChangeListener(NavigationModeChangeListener listener) {
+ mChangeListeners.add(listener);
+ return mMode;
+ }
+
+ public void removeModeChangeListener(NavigationModeChangeListener listener) {
+ mChangeListeners.remove(listener);
+ }
+
+ public Mode getMode() {
+ return mMode;
+ }
+
+ private static int getSystemIntegerRes(Context context, String resName) {
+ Resources res = context.getResources();
+ int resId = res.getIdentifier(resName, "integer", "android");
+
+ if (resId != 0) {
+ return res.getInteger(resId);
+ } else {
+ Log.e(TAG, "Failed to get system resource ID. Incompatible framework version?");
+ return -1;
+ }
+ }
+
+ public interface NavigationModeChangeListener {
+
+ void onNavigationModeChanged(Mode newMode);
+ }
+}
\ No newline at end of file
diff --git a/quickstep/src/com/android/quickstep/TaskListStabilizer.java b/quickstep/src/com/android/quickstep/TaskListStabilizer.java
deleted file mode 100644
index 4c63f81..0000000
--- a/quickstep/src/com/android/quickstep/TaskListStabilizer.java
+++ /dev/null
@@ -1,145 +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 android.app.ActivityManager.RecentTaskInfo;
-import android.content.ComponentName;
-import android.os.Process;
-import android.os.SystemClock;
-
-import com.android.launcher3.util.IntArray;
-import com.android.systemui.shared.recents.model.Task;
-import com.android.systemui.shared.recents.model.Task.TaskKey;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
-import com.android.systemui.shared.system.TaskStackChangeListener;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Keeps the task list stable during quick switch gestures. So if you swipe right to switch from app
- * A to B, you can then swipe right again to get to app C or left to get back to A.
- */
-public class TaskListStabilizer {
-
- private static final long TASK_CACHE_TIMEOUT_MS = 5000;
-
- private final TaskStackChangeListener mTaskStackListener = new TaskStackChangeListener() {
-
- @Override
- public void onTaskCreated(int taskId, ComponentName componentName) {
- endStabilizationSession();
- }
-
- @Override
- public void onTaskRemoved(int taskId) {
- endStabilizationSession();
- }
- };
-
- // Task ids ordered based on recency, 0th index is the least recent task
- private final IntArray mSystemOrder;
- private final IntArray mStabilizedOrder;
-
- // Wrapper objects used for sorting tasks
- private final ArrayList<TaskWrapper> mTaskWrappers = new ArrayList<>();
-
- private boolean mInStabilizationSession;
- private long mSessionStartTime;
-
- public TaskListStabilizer() {
- // Initialize the task ids map
- List<RecentTaskInfo> rawTasks = ActivityManagerWrapper.getInstance().getRecentTasks(
- Integer.MAX_VALUE, Process.myUserHandle().getIdentifier());
- mSystemOrder = new IntArray(rawTasks.size());
- for (RecentTaskInfo info : rawTasks) {
- mSystemOrder.add(new TaskKey(info).id);
- }
- // We will lazily copy the task id's from mSystemOrder when a stabilization session starts.
- mStabilizedOrder = new IntArray(rawTasks.size());
-
- ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
- }
-
- public synchronized void startStabilizationSession() {
- if (!mInStabilizationSession) {
- mStabilizedOrder.clear();
- mStabilizedOrder.addAll(mSystemOrder);
- }
- mInStabilizationSession = true;
- mSessionStartTime = SystemClock.uptimeMillis();
- }
-
- public synchronized void endStabilizationSession() {
- mInStabilizationSession = false;
- }
-
- public synchronized ArrayList<Task> reorder(ArrayList<Task> tasks) {
- mSystemOrder.clear();
- for (Task task : tasks) {
- mSystemOrder.add(task.key.id);
- }
-
- if ((SystemClock.uptimeMillis() - mSessionStartTime) > TASK_CACHE_TIMEOUT_MS) {
- endStabilizationSession();
- }
-
- if (!mInStabilizationSession) {
- return tasks;
- }
-
- // Ensure that we have enough wrappers
- int taskCount = tasks.size();
- for (int i = taskCount - mTaskWrappers.size(); i > 0; i--) {
- mTaskWrappers.add(new TaskWrapper());
- }
-
- List<TaskWrapper> listToSort = mTaskWrappers.size() == taskCount
- ? mTaskWrappers : mTaskWrappers.subList(0, taskCount);
- int missingTaskIndex = -taskCount;
-
- for (int i = 0; i < taskCount; i++){
- TaskWrapper wrapper = listToSort.get(i);
- wrapper.task = tasks.get(i);
- wrapper.index = mStabilizedOrder.indexOf(wrapper.task.key.id);
-
- // Ensure that missing tasks are put in the front, in the order they appear in the
- // original list
- if (wrapper.index < 0) {
- wrapper.index = missingTaskIndex;
- missingTaskIndex++;
- }
- }
- Collections.sort(listToSort);
-
- ArrayList<Task> result = new ArrayList<>(taskCount);
- for (int i = 0; i < taskCount; i++) {
- result.add(listToSort.get(i).task);
- }
- return result;
- }
-
- private static class TaskWrapper implements Comparable<TaskWrapper> {
- Task task;
- int index;
-
- @Override
- public int compareTo(TaskWrapper other) {
- return Integer.compare(index, other.index);
- }
- }
-}
diff --git a/quickstep/src/com/android/quickstep/TestInformationProvider.java b/quickstep/src/com/android/quickstep/TestInformationProvider.java
index e57d3ec..b37ddda 100644
--- a/quickstep/src/com/android/quickstep/TestInformationProvider.java
+++ b/quickstep/src/com/android/quickstep/TestInformationProvider.java
@@ -30,7 +30,7 @@
import com.android.launcher3.LauncherState;
import com.android.launcher3.TestProtocol;
import com.android.launcher3.Utilities;
-import com.android.launcher3.uioverrides.OverviewState;
+import com.android.launcher3.uioverrides.states.OverviewState;
import com.android.quickstep.util.LayoutUtils;
public class TestInformationProvider extends ContentProvider {
diff --git a/quickstep/src/com/android/quickstep/logging/UserEventDispatcherExtension.java b/quickstep/src/com/android/quickstep/logging/UserEventDispatcherExtension.java
index 4392851..6dff187 100644
--- a/quickstep/src/com/android/quickstep/logging/UserEventDispatcherExtension.java
+++ b/quickstep/src/com/android/quickstep/logging/UserEventDispatcherExtension.java
@@ -34,7 +34,6 @@
* quickstep interactions.
*/
@SuppressWarnings("unused")
-@Deprecated
public class UserEventDispatcherExtension extends UserEventDispatcher {
private static final String TAG = "UserEventDispatcher";
diff --git a/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java b/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java
index 8a117c8..ae5f390 100644
--- a/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java
+++ b/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java
@@ -17,7 +17,6 @@
import android.content.Context;
import android.content.res.Resources;
-import android.os.SystemClock;
import android.view.MotionEvent;
import com.android.launcher3.Alarm;
@@ -71,9 +70,6 @@
*/
public void setOnMotionPauseListener(OnMotionPauseListener listener) {
mOnMotionPauseListener = listener;
- if (mOnMotionPauseListener != null) {
- mOnMotionPauseListener.onMotionPauseChanged(mIsPaused);
- }
}
/**
@@ -83,7 +79,7 @@
*
* TODO: Use historical positions as well, e.g. {@link MotionEvent#getHistoricalY(int, int)}.
*/
- public void addPosition(float position, float orthogonalPosition) {
+ public void addPosition(float position, float orthogonalPosition, long time) {
if (mFirstPosition == null) {
mFirstPosition = position;
}
@@ -91,7 +87,6 @@
mFirstOrthogonalPosition = orthogonalPosition;
}
mForcePauseTimeout.setAlarm(FORCE_PAUSE_TIMEOUT);
- long time = SystemClock.uptimeMillis();
if (mPreviousTime != null && mPreviousPosition != null) {
long changeInTime = Math.max(1, time - mPreviousTime);
float changeInPosition = position - mPreviousPosition;
diff --git a/quickstep/tests/src/com/android/quickstep/AbstractQuickStepTest.java b/quickstep/tests/src/com/android/quickstep/AbstractQuickStepTest.java
index 6854aa8..c77726e 100644
--- a/quickstep/tests/src/com/android/quickstep/AbstractQuickStepTest.java
+++ b/quickstep/tests/src/com/android/quickstep/AbstractQuickStepTest.java
@@ -27,5 +27,5 @@
public abstract class AbstractQuickStepTest extends AbstractLauncherUiTest {
@Rule
public TestRule mQuickstepOnOffExecutor =
- new QuickStepOnOffRule(mMainThreadExecutor, mLauncher);
+ new NavigationModeSwitchRule(mLauncher);
}
diff --git a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
index 88b50d9..f436831 100644
--- a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
+++ b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
@@ -17,26 +17,31 @@
import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS;
+import static androidx.test.InstrumentationRegistry.getInstrumentation;
+
import static com.android.launcher3.tapl.LauncherInstrumentation.WAIT_TIME_MS;
import static com.android.launcher3.tapl.TestHelpers.getHomeIntentInPackage;
import static com.android.launcher3.tapl.TestHelpers.getLauncherInMyProcess;
import static com.android.launcher3.util.rule.ShellCommandRule.disableHeadsUpNotification;
import static com.android.launcher3.util.rule.ShellCommandRule.getLauncherCommand;
-import static com.android.quickstep.QuickStepOnOffRule.Mode.OFF;
+import static com.android.quickstep.NavigationModeSwitchRule.Mode.THREE_BUTTON;
import static org.junit.Assert.assertTrue;
-import static androidx.test.InstrumentationRegistry.getInstrumentation;
-
import android.app.Instrumentation;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
-import com.android.launcher3.MainThreadExecutor;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.Until;
+
import com.android.launcher3.tapl.LauncherInstrumentation;
import com.android.launcher3.testcomponent.TestCommandReceiver;
-import com.android.quickstep.QuickStepOnOffRule.QuickstepOnOff;
+import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
import org.junit.Rule;
import org.junit.Test;
@@ -44,12 +49,6 @@
import org.junit.runner.RunWith;
import org.junit.runners.model.Statement;
-import androidx.test.filters.LargeTest;
-import androidx.test.runner.AndroidJUnit4;
-import androidx.test.uiautomator.By;
-import androidx.test.uiautomator.UiDevice;
-import androidx.test.uiautomator.Until;
-
@LargeTest
@RunWith(AndroidJUnit4.class)
/**
@@ -72,7 +71,7 @@
mDevice = UiDevice.getInstance(instrumentation);
mLauncher = new LauncherInstrumentation(instrumentation);
- mQuickstepOnOffExecutor = new QuickStepOnOffRule(new MainThreadExecutor(), mLauncher);
+ mQuickstepOnOffExecutor = new NavigationModeSwitchRule(mLauncher);
mOtherLauncherActivity = context.getPackageManager().queryIntentActivities(
getHomeIntentInPackage(context),
MATCH_DISABLED_COMPONENTS).get(0).activityInfo;
@@ -94,7 +93,7 @@
};
}
- @QuickstepOnOff(mode = OFF)
+ @NavigationModeSwitch(mode = THREE_BUTTON)
@Test
public void goToOverviewFromHome() {
mDevice.pressHome();
@@ -104,7 +103,7 @@
mLauncher.getBackground().switchToOverview();
}
- @QuickstepOnOff(mode = OFF)
+ @NavigationModeSwitch(mode = THREE_BUTTON)
@Test
public void goToOverviewFromApp() {
startAppFast("com.android.settings");
diff --git a/quickstep/tests/src/com/android/quickstep/QuickStepOnOffRule.java b/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
similarity index 60%
rename from quickstep/tests/src/com/android/quickstep/QuickStepOnOffRule.java
rename to quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
index 12bd0ca..f5ac9c9 100644
--- a/quickstep/tests/src/com/android/quickstep/QuickStepOnOffRule.java
+++ b/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
@@ -17,84 +17,80 @@
package com.android.quickstep;
import static androidx.test.InstrumentationRegistry.getInstrumentation;
-
-import static com.android.quickstep.QuickStepOnOffRule.Mode.BOTH;
-import static com.android.quickstep.QuickStepOnOffRule.Mode.OFF;
-import static com.android.quickstep.QuickStepOnOffRule.Mode.ON;
+import static com.android.quickstep.NavigationModeSwitchRule.Mode.ALL;
+import static com.android.quickstep.NavigationModeSwitchRule.Mode.THREE_BUTTON;
+import static com.android.quickstep.NavigationModeSwitchRule.Mode.TWO_BUTTON;
import static com.android.systemui.shared.system.QuickStepContract.NAV_BAR_MODE_2BUTTON_OVERLAY;
import static com.android.systemui.shared.system.QuickStepContract.NAV_BAR_MODE_3BUTTON_OVERLAY;
import static com.android.systemui.shared.system.QuickStepContract.NAV_BAR_MODE_GESTURAL_OVERLAY;
import android.content.Context;
import android.util.Log;
-
import androidx.test.uiautomator.UiDevice;
-
import com.android.launcher3.tapl.LauncherInstrumentation;
import com.android.launcher3.tapl.TestHelpers;
-import com.android.systemui.shared.system.QuickStepContract;
-
-import org.junit.rules.TestRule;
-import org.junit.runner.Description;
-import org.junit.runners.model.Statement;
-
-import java.io.IOException;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
-import java.util.concurrent.Executor;
+import org.junit.Assert;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
/**
* Test rule that allows executing a test with Quickstep on and then Quickstep off.
* The test should be annotated with @QuickstepOnOff.
*/
-public class QuickStepOnOffRule implements TestRule {
+public class NavigationModeSwitchRule implements TestRule {
static final String TAG = "QuickStepOnOffRule";
public enum Mode {
- ON, OFF, BOTH
+ THREE_BUTTON, TWO_BUTTON, ZERO_BUTTON, ALL
}
// Annotation for tests that need to be run with quickstep enabled and disabled.
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
- public @interface QuickstepOnOff {
- Mode mode() default BOTH;
+ public @interface NavigationModeSwitch {
+ Mode mode() default ALL;
}
- private final Executor mMainThreadExecutor;
private final LauncherInstrumentation mLauncher;
- public QuickStepOnOffRule(Executor mainThreadExecutor, LauncherInstrumentation launcher) {
+ public NavigationModeSwitchRule(LauncherInstrumentation launcher) {
mLauncher = launcher;
- this.mMainThreadExecutor = mainThreadExecutor;
}
@Override
public Statement apply(Statement base, Description description) {
if (TestHelpers.isInLauncherProcess() &&
- description.getAnnotation(QuickstepOnOff.class) != null) {
- Mode mode = description.getAnnotation(QuickstepOnOff.class).mode();
+ description.getAnnotation(NavigationModeSwitch.class) != null) {
+ Mode mode = description.getAnnotation(NavigationModeSwitch.class).mode();
return new Statement() {
@Override
public void evaluate() throws Throwable {
final Context context = getInstrumentation().getContext();
- final String prevOverlayPkg = QuickStepContract.isGesturalMode(context)
+ final String prevOverlayPkg = LauncherInstrumentation.isGesturalMode(context)
? NAV_BAR_MODE_GESTURAL_OVERLAY
- : QuickStepContract.isSwipeUpMode(context)
+ : LauncherInstrumentation.isSwipeUpMode(context)
? NAV_BAR_MODE_2BUTTON_OVERLAY
: NAV_BAR_MODE_3BUTTON_OVERLAY;
+ final LauncherInstrumentation.NavigationModel originalMode =
+ mLauncher.getNavigationModel();
try {
- if (mode == ON || mode == BOTH) {
- evaluateWithQuickstepOn();
+// if (mode == ZERO_BUTTON || mode == ALL) {
+// evaluateWithZeroButtons();
+// }
+ if (mode == TWO_BUTTON || mode == ALL) {
+ evaluateWithTwoButtons();
}
- if (mode == OFF || mode == BOTH) {
- evaluateWithQuickstepOff();
+ if (mode == THREE_BUTTON || mode == ALL) {
+ evaluateWithThreeButtons();
}
} finally {
- setActiveOverlay(prevOverlayPkg);
+ setActiveOverlay(prevOverlayPkg, originalMode);
}
}
@@ -102,17 +98,26 @@
base.evaluate();
}
- private void evaluateWithQuickstepOff() throws Throwable {
- setActiveOverlay(NAV_BAR_MODE_3BUTTON_OVERLAY);
+ private void evaluateWithThreeButtons() throws Throwable {
+ setActiveOverlay(NAV_BAR_MODE_3BUTTON_OVERLAY,
+ LauncherInstrumentation.NavigationModel.THREE_BUTTON);
evaluateWithoutChangingSetting(base);
}
- private void evaluateWithQuickstepOn() throws Throwable {
- setActiveOverlay(NAV_BAR_MODE_2BUTTON_OVERLAY);
+ private void evaluateWithTwoButtons() throws Throwable {
+ setActiveOverlay(NAV_BAR_MODE_2BUTTON_OVERLAY,
+ LauncherInstrumentation.NavigationModel.TWO_BUTTON);
base.evaluate();
}
- private void setActiveOverlay(String overlayPackage) {
+ private void evaluateWithZeroButtons() throws Throwable {
+ setActiveOverlay(NAV_BAR_MODE_GESTURAL_OVERLAY,
+ LauncherInstrumentation.NavigationModel.ZERO_BUTTON);
+ base.evaluate();
+ }
+
+ private void setActiveOverlay(String overlayPackage,
+ LauncherInstrumentation.NavigationModel expectedMode) throws Exception {
setOverlayPackageEnabled(NAV_BAR_MODE_3BUTTON_OVERLAY,
overlayPackage == NAV_BAR_MODE_3BUTTON_OVERLAY);
setOverlayPackageEnabled(NAV_BAR_MODE_2BUTTON_OVERLAY,
@@ -120,18 +125,19 @@
setOverlayPackageEnabled(NAV_BAR_MODE_GESTURAL_OVERLAY,
overlayPackage == NAV_BAR_MODE_GESTURAL_OVERLAY);
- // TODO: Wait until nav bar mode has applied
+ for (int i = 0; i != 100; ++i) {
+ if (mLauncher.getNavigationModel() == expectedMode) return;
+ Thread.sleep(100);
+ }
+ Assert.fail("Couldn't switch to " + overlayPackage);
}
- private void setOverlayPackageEnabled(String overlayPackage, boolean enable) {
+ private void setOverlayPackageEnabled(String overlayPackage, boolean enable)
+ throws Exception {
Log.d(TAG, "setOverlayPackageEnabled: " + overlayPackage + " " + enable);
final String action = enable ? "enable" : "disable";
- try {
- UiDevice.getInstance(getInstrumentation()).executeShellCommand(
- "cmd overlay " + action + " " + overlayPackage);
- } catch (IOException e) {
- e.printStackTrace();
- }
+ UiDevice.getInstance(getInstrumentation()).executeShellCommand(
+ "cmd overlay " + action + " " + overlayPackage);
}
};
} else {
diff --git a/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java b/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java
index 6031dcd..dc83e87 100644
--- a/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java
+++ b/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java
@@ -26,8 +26,8 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.util.RaceConditionReproducer;
-import com.android.quickstep.QuickStepOnOffRule.Mode;
-import com.android.quickstep.QuickStepOnOffRule.QuickstepOnOff;
+import com.android.quickstep.NavigationModeSwitchRule.Mode;
+import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
import org.junit.Before;
import org.junit.Ignore;
@@ -62,7 +62,7 @@
@Test
@Ignore // Ignoring until gestural navigation event sequence settles
- @QuickstepOnOff(mode = Mode.ON)
+ @NavigationModeSwitch(mode = Mode.TWO_BUTTON)
public void testPressHome() {
runTest(enterEvt(Launcher.ON_CREATE_EVT),
exitEvt(Launcher.ON_CREATE_EVT),
@@ -77,14 +77,14 @@
@Test
@Ignore // Ignoring until gestural navigation event sequence settles
- @QuickstepOnOff(mode = Mode.ON)
+ @NavigationModeSwitch(mode = Mode.TWO_BUTTON)
public void testSwipeToOverview() {
closeLauncherActivity();
mLauncher.getBackground().switchToOverview();
}
@Test
- @QuickstepOnOff
+ @NavigationModeSwitch
public void testStressPressHome() {
for (int i = 0; i < STRESS_REPEAT_COUNT; ++i) {
// Destroy Launcher activity.
@@ -96,7 +96,8 @@
}
@Test
- @QuickstepOnOff
+ @Ignore // b/129723135
+ @NavigationModeSwitch
public void testStressSwipeToOverview() {
for (int i = 0; i < STRESS_REPEAT_COUNT; ++i) {
// Destroy Launcher activity.
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index c60cf45..4112ccf 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -37,10 +37,11 @@
import com.android.launcher3.tapl.OverviewTask;
import com.android.launcher3.tapl.TestHelpers;
import com.android.launcher3.ui.TaplTestsLauncher3;
-import com.android.quickstep.QuickStepOnOffRule.QuickstepOnOff;
+import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
import com.android.quickstep.views.RecentsView;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestWatcher;
@@ -59,7 +60,7 @@
}
private void startTestApps() throws Exception {
- startAppFast(resolveSystemApp(Intent.CATEGORY_APP_MESSAGING));
+ startAppFast(resolveSystemApp(Intent.CATEGORY_APP_MARKET));
startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CONTACTS));
@@ -71,6 +72,7 @@
@Test
@PortraitLandscape
+ @Ignore
public void testPressRecentAppsLauncherAndGetOverview() throws RemoteException {
mDevice.pressRecentApps();
waitForState("Launcher internal state didn't switch to Overview", LauncherState.OVERVIEW);
@@ -79,7 +81,7 @@
}
@Test
- @QuickstepOnOff
+ @NavigationModeSwitch
@PortraitLandscape
public void testWorkspaceSwitchToAllApps() {
assertNotNull("switchToAllApps() returned null",
@@ -198,7 +200,7 @@
}
@Test
- @QuickstepOnOff
+ @NavigationModeSwitch
@PortraitLandscape
public void testSwitchToOverview() throws Exception {
assertNotNull("Workspace.switchToOverview() returned null",
@@ -208,7 +210,7 @@
}
@Test
- @QuickstepOnOff
+ @NavigationModeSwitch
@PortraitLandscape
public void testBackground() throws Exception {
startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index 56ef414..19f537f 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -33,7 +33,7 @@
<string name="long_accessible_way_to_add" msgid="4289502106628154155">"Fes doble toc i mantén premut per seleccionar un widget o per utilitzar les accions personalitzades."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d d\'amplada per %2$d d\'alçada"</string>
- <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Toca i mantén premut l\'element per col·locar-lo manualment"</string>
+ <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Mantén premut l\'element per afegir-lo manualment"</string>
<string name="place_automatically" msgid="8064208734425456485">"Afegeix automàticament"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Cerca aplicacions"</string>
<string name="all_apps_loading_message" msgid="5813968043155271636">"S\'estan carregant les aplicacions…"</string>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index c58620e..58b65da 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -33,7 +33,7 @@
<string name="long_accessible_way_to_add" msgid="4289502106628154155">"위젯을 선택하려면 두 번 탭한 다음 길게 터치하거나 맞춤 액션을 사용합니다."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d×%2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"너비 %1$d, 높이 %2$d"</string>
- <string name="add_item_request_drag_hint" msgid="5899764264480397019">"길게 터치하여 직접 장소 추가"</string>
+ <string name="add_item_request_drag_hint" msgid="5899764264480397019">"길게 터치하여 직접 추가"</string>
<string name="place_automatically" msgid="8064208734425456485">"자동으로 추가"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"앱 검색"</string>
<string name="all_apps_loading_message" msgid="5813968043155271636">"앱 로드 중…"</string>
diff --git a/res/values-land/dimens.xml b/res/values-land/dimens.xml
index b2f3575..bc658e4 100644
--- a/res/values-land/dimens.xml
+++ b/res/values-land/dimens.xml
@@ -27,9 +27,6 @@
<!-- Dynamic grid -->
<dimen name="dynamic_grid_icon_drawable_padding">4dp</dimen>
- <dimen name="dynamic_grid_cell_layout_padding">0dp</dimen>
- <dimen name="dynamic_grid_cell_layout_bottom_padding">5.5dp</dimen>
-
<!-- Hotseat -->
<dimen name="dynamic_grid_hotseat_side_padding">16dp</dimen>
</resources>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index b26b812..68a08a9 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -104,7 +104,7 @@
<string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"Widgets de <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="widgets_list" msgid="796804551140113767">"Lista de widgets"</string>
<string name="widgets_list_closed" msgid="6141506579418771922">"Lista de widgets fechada."</string>
- <string name="action_add_to_workspace" msgid="8902165848117513641">"Adicionar ao Ecrã principal"</string>
+ <string name="action_add_to_workspace" msgid="8902165848117513641">"Adicionar ao ecrã principal"</string>
<string name="action_move_here" msgid="2170188780612570250">"Mover o item para aqui"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"Item adicionado ao ecrã principal"</string>
<string name="item_removed" msgid="851119963877842327">"Item removido"</string>
diff --git a/res/values/config.xml b/res/values/config.xml
index 6bd01b5..4b68b50 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -70,6 +70,7 @@
<string name="instant_app_resolver_class" translatable="false"></string>
<string name="main_process_initializer_class" translatable="false"></string>
<string name="system_shortcut_factory_class" translatable="false"></string>
+ <string name="app_launch_tracker_class" translatable="false"></string>
<!-- Package name of the default wallpaper picker. -->
<string name="wallpaper_picker_package" translatable="false"></string>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 04e4591..7822e05 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -22,13 +22,10 @@
<dimen name="dynamic_grid_edge_margin">8dp</dimen>
<dimen name="dynamic_grid_page_indicator_line_height">1dp</dimen>
<dimen name="dynamic_grid_icon_drawable_padding">8dp</dimen>
- <dimen name="dynamic_grid_workspace_top_padding">8dp</dimen>
- <dimen name="dynamic_grid_workspace_page_spacing">8dp</dimen>
<!-- Minimum space between workspace and hotseat in spring loaded mode -->
<dimen name="dynamic_grid_min_spring_loaded_space">8dp</dimen>
<dimen name="dynamic_grid_cell_layout_padding">5.5dp</dimen>
- <dimen name="dynamic_grid_cell_layout_bottom_padding">0dp</dimen>
<dimen name="dynamic_grid_cell_padding_x">8dp</dimen>
<!-- Hotseat -->
diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java
index 8e2ffe9..f9a8d1b 100644
--- a/src/com/android/launcher3/AppWidgetResizeFrame.java
+++ b/src/com/android/launcher3/AppWidgetResizeFrame.java
@@ -24,6 +24,9 @@
import com.android.launcher3.util.FocusLogic;
import com.android.launcher3.widget.LauncherAppWidgetHostView;
+import java.util.ArrayList;
+import java.util.List;
+
public class AppWidgetResizeFrame extends AbstractFloatingView implements View.OnKeyListener {
private static final int SNAP_DURATION = 150;
private static final float DIMMED_HANDLE_ALPHA = 0f;
@@ -45,6 +48,7 @@
private final FirstFrameAnimatorHelper mFirstFrameAnimatorHelper;
private final View[] mDragHandles = new View[HANDLE_COUNT];
+ private final List<Rect> mSystemGestureExclusionRects = new ArrayList<>(HANDLE_COUNT);
private LauncherAppWidgetHostView mWidgetView;
private CellLayout mCellLayout;
@@ -106,6 +110,10 @@
.getDimensionPixelSize(R.dimen.resize_frame_background_padding);
mTouchTargetWidth = 2 * mBackgroundPadding;
mFirstFrameAnimatorHelper = new FirstFrameAnimatorHelper(this);
+
+ for (int i = 0; i < HANDLE_COUNT; i++) {
+ mSystemGestureExclusionRects.add(new Rect());
+ }
}
@Override
@@ -118,6 +126,19 @@
}
}
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ super.onLayout(changed, l, t, r, b);
+ if (Utilities.ATLEAST_Q) {
+ for (int i = 0; i < HANDLE_COUNT; i++) {
+ View dragHandle = mDragHandles[i];
+ mSystemGestureExclusionRects.get(i).set(dragHandle.getLeft(), dragHandle.getTop(),
+ dragHandle.getRight(), dragHandle.getBottom());
+ }
+ setSystemGestureExclusionRects(mSystemGestureExclusionRects);
+ }
+ }
+
public static void showForWidget(LauncherAppWidgetHostView widget, CellLayout cellLayout) {
Launcher launcher = Launcher.getLauncher(cellLayout.getContext());
AbstractFloatingView.closeAllOpenViews(launcher);
diff --git a/src/com/android/launcher3/BaseDraggingActivity.java b/src/com/android/launcher3/BaseDraggingActivity.java
index ff9dd13..18599ac 100644
--- a/src/com/android/launcher3/BaseDraggingActivity.java
+++ b/src/com/android/launcher3/BaseDraggingActivity.java
@@ -16,6 +16,8 @@
package com.android.launcher3;
+import static com.android.launcher3.model.AppLaunchTracker.CONTAINER_SEARCH;
+
import android.app.ActivityOptions;
import android.content.ActivityNotFoundException;
import android.content.Intent;
@@ -32,10 +34,13 @@
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.compat.LauncherAppsCompat;
+import com.android.launcher3.model.AppLaunchTracker;
import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.uioverrides.DisplayRotationListener;
import com.android.launcher3.uioverrides.WallpaperColorInfo;
+import androidx.annotation.Nullable;
+
/**
* Extension of BaseActivity allowing support for drag-n-drop
*/
@@ -148,7 +153,8 @@
public abstract ActivityOptions getActivityLaunchOptions(View v);
- public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {
+ public boolean startActivitySafely(View v, Intent intent, @Nullable ItemInfo item,
+ @Nullable String sourceContainer) {
if (mIsSafeModeEnabled && !Utilities.isSystemApp(this, intent)) {
Toast.makeText(this, R.string.safemode_shortcut_error, Toast.LENGTH_SHORT).show();
return false;
@@ -169,13 +175,17 @@
&& !((ShortcutInfo) item).isPromise();
if (isShortcut) {
// Shortcuts need some special checks due to legacy reasons.
- startShortcutIntentSafely(intent, optsBundle, item);
+ startShortcutIntentSafely(intent, optsBundle, item, sourceContainer);
} else if (user == null || user.equals(Process.myUserHandle())) {
// Could be launching some bookkeeping activity
startActivity(intent, optsBundle);
+ AppLaunchTracker.INSTANCE.get(this).onStartApp(intent.getComponent(),
+ Process.myUserHandle(), sourceContainer);
} else {
LauncherAppsCompat.getInstance(this).startActivityForProfile(
intent.getComponent(), user, intent.getSourceBounds(), optsBundle);
+ AppLaunchTracker.INSTANCE.get(this).onStartApp(intent.getComponent(), user,
+ sourceContainer);
}
getUserEventDispatcher().logAppLaunch(v, intent);
getStatsLogManager().logAppLaunch(v, intent);
@@ -187,7 +197,8 @@
return false;
}
- private void startShortcutIntentSafely(Intent intent, Bundle optsBundle, ItemInfo info) {
+ private void startShortcutIntentSafely(Intent intent, Bundle optsBundle, ItemInfo info,
+ @Nullable String sourceContainer) {
try {
StrictMode.VmPolicy oldPolicy = StrictMode.getVmPolicy();
try {
@@ -202,6 +213,8 @@
String packageName = intent.getPackage();
DeepShortcutManager.getInstance(this).startShortcut(
packageName, id, intent.getSourceBounds(), optsBundle, info.user);
+ AppLaunchTracker.INSTANCE.get(this).onStartShortcut(packageName, id, info.user,
+ sourceContainer);
} else {
// Could be launching some bookkeeping activity
startActivity(intent, optsBundle);
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index d75006e..4dd2e0a 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -480,7 +480,8 @@
*/
public ObjectAnimator createTextAlphaAnimator(boolean fadeIn) {
float toAlpha = shouldTextBeVisible() && fadeIn ? 1 : 0;
- return ObjectAnimator.ofFloat(this, TEXT_ALPHA_PROPERTY, toAlpha);
+ float fromAlpha = toAlpha == 1 ? 0 : 1f;
+ return ObjectAnimator.ofFloat(this, TEXT_ALPHA_PROPERTY, fromAlpha, toAlpha);
}
@Override
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 7919d29..6a3a26f 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -16,8 +16,6 @@
package com.android.launcher3;
-import android.appwidget.AppWidgetHostView;
-import android.content.ComponentName;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -53,6 +51,9 @@
public final int heightPx;
public final int availableWidthPx;
public final int availableHeightPx;
+
+ public final float aspectRatio;
+
/**
* The maximum amount of left/right workspace padding as a percentage of the screen width.
* To be clear, this means that up to 7% of the screen width can be used as left padding, and
@@ -70,9 +71,6 @@
public final int cellLayoutPaddingLeftRightPx;
public final int cellLayoutBottomPaddingPx;
public final int edgeMarginPx;
- public final Rect defaultWidgetPadding;
- public final int defaultPageSpacingPx;
- private final int topWorkspacePadding;
public float workspaceSpringLoadShrinkFactor;
public final int workspaceSpringLoadedBottomSpace;
@@ -165,7 +163,7 @@
isTablet = res.getBoolean(R.bool.is_tablet);
isLargeTablet = res.getBoolean(R.bool.is_large_tablet);
isPhone = !isTablet && !isLargeTablet;
- float aspectRatio = ((float) Math.max(widthPx, heightPx)) / Math.min(widthPx, heightPx);
+ aspectRatio = ((float) Math.max(widthPx, heightPx)) / Math.min(widthPx, heightPx);
boolean isTallDevice = Float.compare(aspectRatio, TALL_DEVICE_ASPECT_RATIO_THRESHOLD) >= 0;
// Some more constants
@@ -177,26 +175,25 @@
: Configuration.ORIENTATION_PORTRAIT);
res = context.getResources();
-
- ComponentName cn = new ComponentName(context.getPackageName(),
- this.getClass().getName());
- defaultWidgetPadding = AppWidgetHostView.getDefaultPaddingForWidget(context, cn, null);
edgeMarginPx = res.getDimensionPixelSize(R.dimen.dynamic_grid_edge_margin);
desiredWorkspaceLeftRightMarginPx = isVerticalBarLayout() ? 0 : edgeMarginPx;
+
int cellLayoutPaddingLeftRightMultiplier = !isVerticalBarLayout() && isTablet
? PORTRAIT_TABLET_LEFT_RIGHT_PADDING_MULTIPLIER : 1;
- cellLayoutPaddingLeftRightPx = cellLayoutPaddingLeftRightMultiplier *
- res.getDimensionPixelSize(R.dimen.dynamic_grid_cell_layout_padding);
- cellLayoutBottomPaddingPx =
- res.getDimensionPixelSize(R.dimen.dynamic_grid_cell_layout_bottom_padding);
+ int cellLayoutPadding = res.getDimensionPixelSize(R.dimen.dynamic_grid_cell_layout_padding);
+ if (isLandscape) {
+ cellLayoutPaddingLeftRightPx = 0;
+ cellLayoutBottomPaddingPx = cellLayoutPadding;
+ } else {
+ cellLayoutPaddingLeftRightPx = cellLayoutPaddingLeftRightMultiplier * cellLayoutPadding;
+ cellLayoutBottomPaddingPx = 0;
+ }
+
verticalDragHandleSizePx = res.getDimensionPixelSize(
R.dimen.vertical_drag_handle_size);
verticalDragHandleOverlapWorkspace =
res.getDimensionPixelSize(R.dimen.vertical_drag_handle_overlap_workspace);
- defaultPageSpacingPx =
- res.getDimensionPixelSize(R.dimen.dynamic_grid_workspace_page_spacing);
- topWorkspacePadding =
- res.getDimensionPixelSize(R.dimen.dynamic_grid_workspace_top_padding);
+
iconDrawablePaddingOriginalPx =
res.getDimensionPixelSize(R.dimen.dynamic_grid_icon_drawable_padding);
dropTargetBarSizePx = res.getDimensionPixelSize(R.dimen.dynamic_grid_drop_target_size);
@@ -360,7 +357,7 @@
if (!isVerticalLayout) {
int expectedWorkspaceHeight = availableHeightPx - hotseatBarSizePx
- - verticalDragHandleSizePx - topWorkspacePadding;
+ - verticalDragHandleSizePx - edgeMarginPx;
float minRequiredHeight = dropTargetBarSizePx + workspaceSpringLoadedBottomSpace;
workspaceSpringLoadShrinkFactor = Math.min(
res.getInteger(R.integer.config_workspaceSpringLoadShrinkPercentage) / 100.0f,
@@ -471,15 +468,15 @@
((inv.numColumns - 1) * cellWidthPx)));
availablePaddingX = (int) Math.min(availablePaddingX,
widthPx * MAX_HORIZONTAL_PADDING_PERCENT);
- int availablePaddingY = Math.max(0, heightPx - topWorkspacePadding - paddingBottom
+ int availablePaddingY = Math.max(0, heightPx - edgeMarginPx - paddingBottom
- (2 * inv.numRows * cellHeightPx) - hotseatBarTopPaddingPx
- hotseatBarBottomPaddingPx);
- padding.set(availablePaddingX / 2, topWorkspacePadding + availablePaddingY / 2,
+ padding.set(availablePaddingX / 2, edgeMarginPx + availablePaddingY / 2,
availablePaddingX / 2, paddingBottom + availablePaddingY / 2);
} else {
// Pad the top and bottom of the workspace with search/hotseat bar sizes
padding.set(desiredWorkspaceLeftRightMarginPx,
- topWorkspacePadding,
+ edgeMarginPx,
desiredWorkspaceLeftRightMarginPx,
paddingBottom);
}
@@ -624,12 +621,6 @@
}
}
- public float getAspectRatioWithInsets() {
- int w = widthPx - mInsets.left - mInsets.right;
- int h = heightPx - mInsets.top - mInsets.bottom;
- return ((float) Math.max(w, h)) / Math.min(w, h);
- }
-
private static Context getContext(Context c, int orientation) {
Configuration context = new Configuration(c.getResources().getConfiguration());
context.orientation = orientation;
diff --git a/src/com/android/launcher3/DropTargetBar.java b/src/com/android/launcher3/DropTargetBar.java
index d025a9b..0543e8d 100644
--- a/src/com/android/launcher3/DropTargetBar.java
+++ b/src/com/android/launcher3/DropTargetBar.java
@@ -104,7 +104,7 @@
/ (2 * (grid.inv.numColumns + 1)))
+ grid.edgeMarginPx;
} else {
- gap = grid.desiredWorkspaceLeftRightMarginPx - grid.defaultWidgetPadding.right;
+ gap = grid.desiredWorkspaceLeftRightMarginPx - grid.inv.defaultWidgetPadding.right;
}
lp.width = grid.availableWidthPx - 2 * gap;
diff --git a/src/com/android/launcher3/FastBitmapDrawable.java b/src/com/android/launcher3/FastBitmapDrawable.java
index 964e8b6..7ab88a0 100644
--- a/src/com/android/launcher3/FastBitmapDrawable.java
+++ b/src/com/android/launcher3/FastBitmapDrawable.java
@@ -103,9 +103,14 @@
}
protected FastBitmapDrawable(Bitmap b, int iconColor) {
+ this(b, iconColor, false);
+ }
+
+ protected FastBitmapDrawable(Bitmap b, int iconColor, boolean isDisabled) {
mBitmap = b;
mIconColor = iconColor;
setFilterBitmap(true);
+ setIsDisabled(isDisabled);
}
@Override
@@ -249,6 +254,10 @@
}
}
+ protected boolean isDisabled() {
+ return mIsDisabled;
+ }
+
/**
* Sets the saturation of this icon, 0 [full color] -> 1 [desaturated]
*/
@@ -338,21 +347,23 @@
@Override
public ConstantState getConstantState() {
- return new MyConstantState(mBitmap, mIconColor);
+ return new MyConstantState(mBitmap, mIconColor, mIsDisabled);
}
protected static class MyConstantState extends ConstantState {
protected final Bitmap mBitmap;
protected final int mIconColor;
+ protected final boolean mIsDisabled;
- public MyConstantState(Bitmap bitmap, int color) {
+ public MyConstantState(Bitmap bitmap, int color, boolean isDisabled) {
mBitmap = bitmap;
mIconColor = color;
+ mIsDisabled = isDisabled;
}
@Override
public Drawable newDrawable() {
- return new FastBitmapDrawable(mBitmap, mIconColor);
+ return new FastBitmapDrawable(mBitmap, mIconColor, mIsDisabled);
}
@Override
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index f081303..c4495c7 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -20,7 +20,9 @@
import static com.android.launcher3.Utilities.getDevicePrefs;
import android.annotation.TargetApi;
+import android.appwidget.AppWidgetHostView;
import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -29,6 +31,7 @@
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.graphics.Point;
+import android.graphics.Rect;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
@@ -114,6 +117,7 @@
public DeviceProfile portraitProfile;
public Point defaultWallpaperSize;
+ public Rect defaultWidgetPadding;
private final ArrayList<OnIDPChangeListener> mChangeListeners = new ArrayList<>();
private ConfigMonitor mConfigMonitor;
@@ -235,6 +239,10 @@
} else {
defaultWallpaperSize = new Point(Math.max(smallSide * 2, largeSide), largeSide);
}
+
+ ComponentName cn = new ComponentName(context.getPackageName(), getClass().getName());
+ defaultWidgetPadding = AppWidgetHostView.getDefaultPaddingForWidget(context, cn, null);
+
return closestProfile.name;
}
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index f283a6c..f8d9959 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -97,6 +97,7 @@
import com.android.launcher3.logging.StatsLogUtils;
import com.android.launcher3.logging.UserEventDispatcher;
import com.android.launcher3.logging.UserEventDispatcher.UserEventDelegate;
+import com.android.launcher3.model.AppLaunchTracker;
import com.android.launcher3.model.ModelWriter;
import com.android.launcher3.notification.NotificationListener;
import com.android.launcher3.popup.PopupContainerWithArrow;
@@ -256,6 +257,7 @@
public ViewGroupFocusHelper mFocusHandler;
private RotationHelper mRotationHelper;
+ private Runnable mCancelTouchController;
final Handler mHandler = new Handler();
private final Runnable mHandleDeferredResume = this::handleDeferredResume;
@@ -406,6 +408,13 @@
onIdpChanged(idp);
}
+ public void setQuickSearchBarAlpha(float alpha) {
+ View qsbAllApps = findViewById(R.id.search_container_all_apps);
+ if (qsbAllApps != null) {
+ qsbAllApps.setAlpha(alpha);
+ }
+ }
+
private void onIdpChanged(InvariantDeviceProfile idp) {
mUserEventDispatcher = null;
@@ -694,7 +703,7 @@
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
- startActivitySafely(v, intent, null);
+ startActivitySafely(v, intent, null, null);
} else {
// TODO: Show a snack bar with link to settings
Toast.makeText(this, getString(R.string.msg_no_phone_permission,
@@ -798,6 +807,7 @@
getUserEventDispatcher().startSession();
UiFactory.onLauncherStateOrResumeChanged(this);
+ AppLaunchTracker.INSTANCE.get(this).onReturnedToHome();
}
}
@@ -944,7 +954,7 @@
// Setup the drag layer
mDragLayer.setup(mDragController, mWorkspace);
- UiFactory.setOnTouchControllersChangedListener(this, mDragLayer::recreateControllers);
+ mCancelTouchController = UiFactory.enableLiveTouchControllerChanges(mDragLayer);
mWorkspace.setup(mDragController);
// Until the workspace is bound, ensure that we keep the wallpaper offset locked to the
@@ -1316,7 +1326,10 @@
unregisterReceiver(mScreenOffReceiver);
mWorkspace.removeFolderListeners();
- UiFactory.setOnTouchControllersChangedListener(this, null);
+ if (mCancelTouchController != null) {
+ mCancelTouchController.run();
+ mCancelTouchController = null;
+ }
// Stop callbacks from LauncherModel
// It's possible to receive onDestroy after a new Launcher activity has
@@ -1652,8 +1665,9 @@
}
}
- public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {
- boolean success = super.startActivitySafely(v, intent, item);
+ public boolean startActivitySafely(View v, Intent intent, ItemInfo item,
+ @Nullable String sourceContainer) {
+ boolean success = super.startActivitySafely(v, intent, item, sourceContainer);
if (success && v instanceof BubbleTextView) {
// This is set to the view that launched the activity that navigated the user away
// from launcher. Since there is no callback for when the activity has finished
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index 7bb6071..dc27516 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -131,6 +131,7 @@
if ((changeFlags & CHANGE_FLAG_ICON_PARAMS) != 0) {
LauncherIcons.clearPool();
mIconCache.updateIconParams(idp.fillResIconDpi, idp.iconBitmapSize);
+ mWidgetCache.refresh();
}
mModel.forceReload();
diff --git a/src/com/android/launcher3/LauncherRootView.java b/src/com/android/launcher3/LauncherRootView.java
index 9f6e5cd..e738eb7 100644
--- a/src/com/android/launcher3/LauncherRootView.java
+++ b/src/com/android/launcher3/LauncherRootView.java
@@ -8,11 +8,15 @@
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
+import android.graphics.Insets;
import android.graphics.Paint;
import android.graphics.Rect;
+import android.graphics.RectF;
import android.util.AttributeSet;
+import android.view.MotionEvent;
import android.view.View;
import android.view.ViewDebug;
+import android.view.WindowInsets;
public class LauncherRootView extends InsettableFrameLayout {
@@ -23,6 +27,9 @@
@ViewDebug.ExportedProperty(category = "launcher")
private final Rect mConsumedInsets = new Rect();
+ @ViewDebug.ExportedProperty(category = "launcher")
+ private final RectF mTouchExcludeRegion = new RectF();
+
private View mAlignedView;
private WindowStateListener mWindowStateListener;
@@ -145,6 +152,31 @@
}
}
+ @Override
+ public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) {
+ if (Utilities.ATLEAST_Q) {
+ Insets gestureInsets = insets.getMandatorySystemGestureInsets();
+ mTouchExcludeRegion.set(gestureInsets.left, gestureInsets.top,
+ gestureInsets.right, gestureInsets.bottom);
+ }
+ return super.dispatchApplyWindowInsets(insets);
+ }
+
+ @Override
+ public boolean dispatchTouchEvent(MotionEvent ev) {
+ if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+ float x = ev.getX();
+ float y = ev.getY();
+ if (y < mTouchExcludeRegion.top
+ || x < mTouchExcludeRegion.left
+ || x > (getWidth() - mTouchExcludeRegion.right)
+ || y > (getHeight() - mTouchExcludeRegion.bottom)) {
+ return false;
+ }
+ }
+ return super.dispatchTouchEvent(ev);
+ }
+
public interface WindowStateListener {
void onWindowFocusChanged(boolean hasFocus);
diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java
index 875288a..c65a871 100644
--- a/src/com/android/launcher3/LauncherState.java
+++ b/src/com/android/launcher3/LauncherState.java
@@ -18,22 +18,23 @@
import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_AUTO;
import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS;
import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED;
-
import static com.android.launcher3.TestProtocol.ALL_APPS_STATE_ORDINAL;
import static com.android.launcher3.TestProtocol.BACKGROUND_APP_STATE_ORDINAL;
import static com.android.launcher3.TestProtocol.NORMAL_STATE_ORDINAL;
+import static com.android.launcher3.TestProtocol.OVERVIEW_PEEK_STATE_ORDINAL;
import static com.android.launcher3.TestProtocol.OVERVIEW_STATE_ORDINAL;
+import static com.android.launcher3.TestProtocol.QUICK_SWITCH_STATE_ORDINAL;
import static com.android.launcher3.TestProtocol.SPRING_LOADED_STATE_ORDINAL;
import static com.android.launcher3.anim.Interpolators.ACCEL_2;
import static com.android.launcher3.states.RotationHelper.REQUEST_NONE;
import android.view.animation.Interpolator;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.states.SpringLoadedState;
-import com.android.launcher3.uioverrides.AllAppsState;
-import com.android.launcher3.uioverrides.BackgroundAppState;
-import com.android.launcher3.uioverrides.OverviewState;
import com.android.launcher3.uioverrides.UiFactory;
+import com.android.launcher3.uioverrides.states.AllAppsState;
+import com.android.launcher3.uioverrides.states.OverviewState;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
@@ -77,7 +78,7 @@
}
};
- private static final LauncherState[] sAllStates = new LauncherState[6];
+ private static final LauncherState[] sAllStates = new LauncherState[7];
/**
* TODO: Create a separate class for NORMAL state.
@@ -92,10 +93,15 @@
*/
public static final LauncherState SPRING_LOADED = new SpringLoadedState(
SPRING_LOADED_STATE_ORDINAL);
- public static final LauncherState OVERVIEW = new OverviewState(OVERVIEW_STATE_ORDINAL);
public static final LauncherState ALL_APPS = new AllAppsState(ALL_APPS_STATE_ORDINAL);
- public static final LauncherState BACKGROUND_APP = new BackgroundAppState(
- BACKGROUND_APP_STATE_ORDINAL);
+
+ public static final LauncherState OVERVIEW = new OverviewState(OVERVIEW_STATE_ORDINAL);
+ public static final LauncherState OVERVIEW_PEEK =
+ OverviewState.newPeekState(OVERVIEW_PEEK_STATE_ORDINAL);
+ public static final LauncherState QUICK_SWITCH =
+ OverviewState.newSwitchState(QUICK_SWITCH_STATE_ORDINAL);
+ public static final LauncherState BACKGROUND_APP =
+ OverviewState.newBackgroundState(BACKGROUND_APP_STATE_ORDINAL);
public final int ordinal;
@@ -183,17 +189,22 @@
return Arrays.copyOf(sAllStates, sAllStates.length);
}
- public float[] getWorkspaceScaleAndTranslation(Launcher launcher) {
- return new float[] {1, 0, 0};
+ public ScaleAndTranslation getWorkspaceScaleAndTranslation(Launcher launcher) {
+ return new ScaleAndTranslation(1, 0, 0);
}
- public float[] getHotseatScaleAndTranslation(Launcher launcher) {
+ public ScaleAndTranslation getHotseatScaleAndTranslation(Launcher launcher) {
// For most states, treat the hotseat as if it were part of the workspace.
return getWorkspaceScaleAndTranslation(launcher);
}
- public float[] getOverviewScaleAndTranslationY(Launcher launcher) {
- return new float[] {1.1f, 0f};
+ public ScaleAndTranslation getOverviewScaleAndTranslation(Launcher launcher) {
+ if (FeatureFlags.SWIPE_HOME.get()) {
+ float offscreenTranslationX = launcher.getDragLayer().getWidth()
+ - launcher.getOverviewPanel().getPaddingStart();
+ return new ScaleAndTranslation(1f, offscreenTranslationX, 0f);
+ }
+ return new ScaleAndTranslation(1.1f, 0f, 0f);
}
public void onStateEnabled(Launcher launcher) {
@@ -281,4 +292,16 @@
public abstract float getPageAlpha(int pageIndex);
}
+
+ public static class ScaleAndTranslation {
+ public float scale;
+ public float translationX;
+ public float translationY;
+
+ public ScaleAndTranslation(float scale, float translationX, float translationY) {
+ this.scale = scale;
+ this.translationX = translationX;
+ this.translationY = translationY;
+ }
+ }
}
diff --git a/src/com/android/launcher3/LauncherStateManager.java b/src/com/android/launcher3/LauncherStateManager.java
index f6b54f2..5b654d8 100644
--- a/src/com/android/launcher3/LauncherStateManager.java
+++ b/src/com/android/launcher3/LauncherStateManager.java
@@ -17,15 +17,21 @@
package com.android.launcher3;
import static android.view.View.VISIBLE;
+
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.AnimatorSetBuilder.ANIM_OVERVIEW_FADE;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_SCALE;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_TRANSLATE_X;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_FADE;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_SCALE;
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.INSTANT;
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.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER;
@@ -35,6 +41,8 @@
import android.os.Handler;
import android.os.Looper;
+import androidx.annotation.IntDef;
+
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.AnimatorSetBuilder;
@@ -46,8 +54,6 @@
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
-import androidx.annotation.IntDef;
-
/**
* TODO: figure out what kind of tests we can write for this
*
@@ -96,17 +102,21 @@
// We separate the state animations into "atomic" and "non-atomic" components. The atomic
// components may be run atomically - that is, all at once, instead of user-controlled. However,
// atomic components are not restricted to this purpose; they can be user-controlled alongside
- // non atomic components as well.
+ // non atomic components as well. Note that each gesture model has exactly one atomic component,
+ // ATOMIC_OVERVIEW_SCALE_COMPONENT *or* ATOMIC_OVERVIEW_PEEK_COMPONENT.
@IntDef(flag = true, value = {
NON_ATOMIC_COMPONENT,
- ATOMIC_COMPONENT
+ ATOMIC_OVERVIEW_SCALE_COMPONENT,
+ ATOMIC_OVERVIEW_PEEK_COMPONENT,
})
@Retention(RetentionPolicy.SOURCE)
public @interface AnimationComponents {}
public static final int NON_ATOMIC_COMPONENT = 1 << 0;
- public static final int ATOMIC_COMPONENT = 1 << 1;
+ public static final int ATOMIC_OVERVIEW_SCALE_COMPONENT = 1 << 1;
+ public static final int ATOMIC_OVERVIEW_PEEK_COMPONENT = 1 << 2;
- public static final int ANIM_ALL = NON_ATOMIC_COMPONENT | ATOMIC_COMPONENT;
+ public static final int ANIM_ALL = NON_ATOMIC_COMPONENT | ATOMIC_OVERVIEW_SCALE_COMPONENT
+ | ATOMIC_OVERVIEW_PEEK_COMPONENT;
private final AnimationConfig mConfig = new AnimationConfig();
private final Handler mUiHandler;
@@ -282,18 +292,20 @@
*/
public void prepareForAtomicAnimation(LauncherState fromState, LauncherState toState,
AnimatorSetBuilder builder) {
- if (fromState == NORMAL && toState.overviewUi) {
+ if (fromState == NORMAL && toState == OVERVIEW) {
builder.setInterpolator(ANIM_WORKSPACE_SCALE, OVERSHOOT_1_2);
builder.setInterpolator(ANIM_WORKSPACE_FADE, OVERSHOOT_1_2);
builder.setInterpolator(ANIM_OVERVIEW_SCALE, OVERSHOOT_1_2);
+ builder.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, OVERSHOOT_1_7);
builder.setInterpolator(ANIM_OVERVIEW_FADE, OVERSHOOT_1_2);
// Start from a higher overview scale, but only if we're invisible so we don't jump.
UiFactory.prepareToShowOverview(mLauncher);
- } else if (fromState.overviewUi && toState == NORMAL) {
+ } else if (fromState == OVERVIEW && toState == NORMAL) {
builder.setInterpolator(ANIM_WORKSPACE_SCALE, DEACCEL);
builder.setInterpolator(ANIM_WORKSPACE_FADE, ACCEL);
builder.setInterpolator(ANIM_OVERVIEW_SCALE, clampToProgress(ACCEL, 0, 0.9f));
+ builder.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, ACCEL);
builder.setInterpolator(ANIM_OVERVIEW_FADE, DEACCEL_1_7);
Workspace workspace = mLauncher.getWorkspace();
@@ -311,9 +323,26 @@
workspace.getHotseat().setScaleX(0.92f);
workspace.getHotseat().setScaleY(0.92f);
}
+ } else if (fromState == NORMAL && toState == OVERVIEW_PEEK) {
+ builder.setInterpolator(ANIM_OVERVIEW_FADE, INSTANT);
+ } else if (fromState == OVERVIEW_PEEK && toState == NORMAL) {
+ // Keep fully visible until the very end (when overview is offscreen) to make invisible.
+ builder.setInterpolator(ANIM_OVERVIEW_FADE, t -> t < 1 ? 0 : 1);
}
}
+ public AnimatorSet createAtomicAnimation(LauncherState fromState, LauncherState toState,
+ AnimatorSetBuilder builder, @AnimationComponents int atomicComponent, long duration) {
+ prepareForAtomicAnimation(fromState, toState, builder);
+ AnimationConfig config = new AnimationConfig();
+ config.animComponents = atomicComponent;
+ config.duration = duration;
+ for (StateHandler handler : mLauncher.getStateManager().getStateHandlers()) {
+ handler.setStateWithAnimation(toState, builder, config);
+ }
+ return builder.build();
+ }
+
/**
* Creates a {@link AnimatorPlaybackController} that can be used for a controlled
* state transition. The UI is force-set to fromState before creating the controller.
@@ -373,7 +402,6 @@
AnimatorSetBuilder builder, final Runnable onCompleteRunnable) {
for (StateHandler handler : getStateHandlers()) {
- builder.startTag(handler);
handler.setStateWithAnimation(state, builder, mConfig);
}
@@ -594,8 +622,12 @@
mCurrentAnimation.addListener(this);
}
- public boolean playAtomicComponent() {
- return (animComponents & ATOMIC_COMPONENT) != 0;
+ public boolean playAtomicOverviewScaleComponent() {
+ return (animComponents & ATOMIC_OVERVIEW_SCALE_COMPONENT) != 0;
+ }
+
+ public boolean playAtomicOverviewPeekComponent() {
+ return (animComponents & ATOMIC_OVERVIEW_PEEK_COMPONENT) != 0;
}
public boolean playNonAtomicComponent() {
diff --git a/src/com/android/launcher3/TestProtocol.java b/src/com/android/launcher3/TestProtocol.java
index 4eb3627..7d3715e 100644
--- a/src/com/android/launcher3/TestProtocol.java
+++ b/src/com/android/launcher3/TestProtocol.java
@@ -28,8 +28,31 @@
public static final int NORMAL_STATE_ORDINAL = 0;
public static final int SPRING_LOADED_STATE_ORDINAL = 1;
public static final int OVERVIEW_STATE_ORDINAL = 2;
- public static final int ALL_APPS_STATE_ORDINAL = 3;
- public static final int BACKGROUND_APP_STATE_ORDINAL = 4;
+ public static final int OVERVIEW_PEEK_STATE_ORDINAL = 3;
+ public static final int QUICK_SWITCH_STATE_ORDINAL = 4;
+ public static final int ALL_APPS_STATE_ORDINAL = 5;
+ public static final int BACKGROUND_APP_STATE_ORDINAL = 6;
+
+ public static String stateOrdinalToString(int ordinal) {
+ switch (ordinal) {
+ case NORMAL_STATE_ORDINAL:
+ return "Normal";
+ case SPRING_LOADED_STATE_ORDINAL:
+ return "SpringLoaded";
+ case OVERVIEW_STATE_ORDINAL:
+ return "Overview";
+ case OVERVIEW_PEEK_STATE_ORDINAL:
+ return "OverviewPeek";
+ case QUICK_SWITCH_STATE_ORDINAL:
+ return "QuickSwitch";
+ case ALL_APPS_STATE_ORDINAL:
+ return "AllApps";
+ case BACKGROUND_APP_STATE_ORDINAL:
+ return "Background";
+ default:
+ return null;
+ }
+ }
public static final String TEST_INFO_RESPONSE_FIELD = "response";
public static final String REQUEST_HOME_TO_OVERVIEW_SWIPE_HEIGHT =
@@ -40,4 +63,7 @@
"all-apps-to-overview-swipe-height";
public static final String REQUEST_HOME_TO_ALL_APPS_SWIPE_HEIGHT =
"home-to-all-apps-swipe-height";
+
+ public static boolean sDebugTracing = false;
+ public static final String NO_DRAG_TAG = "b/129434166";
}
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index dd755cb..fd4b508 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -308,10 +308,14 @@
Log.e(TAG, "mapToRange: range has 0 length");
return toMin;
}
- float progress = Math.abs(t - fromMin) / Math.abs(fromMax - fromMin);
+ float progress = getProgress(t, fromMin, fromMax);
return mapRange(interpolator.getInterpolation(progress), toMin, toMax);
}
+ public static float getProgress(float current, float min, float max) {
+ return Math.abs(current - min) / Math.abs(max - min);
+ }
+
public static float mapRange(float value, float min, float max) {
return min + (value * (max - min));
}
diff --git a/src/com/android/launcher3/WidgetPreviewLoader.java b/src/com/android/launcher3/WidgetPreviewLoader.java
index 050849c..6d1bc1a 100644
--- a/src/com/android/launcher3/WidgetPreviewLoader.java
+++ b/src/com/android/launcher3/WidgetPreviewLoader.java
@@ -24,6 +24,7 @@
import android.os.AsyncTask;
import android.os.CancellationSignal;
import android.os.Handler;
+import android.os.Process;
import android.os.UserHandle;
import android.util.Log;
import android.util.LongSparseArray;
@@ -73,7 +74,6 @@
private final Context mContext;
private final IconCache mIconCache;
private final UserManagerCompat mUserManager;
- private final AppWidgetManagerCompat mWidgetManager;
private final CacheDb mDb;
private final MainThreadExecutor mMainThreadExecutor = new MainThreadExecutor();
@@ -82,7 +82,6 @@
public WidgetPreviewLoader(Context context, IconCache iconCache) {
mContext = context;
mIconCache = iconCache;
- mWidgetManager = AppWidgetManagerCompat.getInstance(context);
mUserManager = UserManagerCompat.getInstance(context);
mDb = new CacheDb(context);
mWorkerHandler = new Handler(LauncherModel.getWorkerLooper());
@@ -107,6 +106,10 @@
return signal;
}
+ public void refresh() {
+ mDb.clear();
+
+ }
/**
* The DB holds the generated previews for various components. Previews can also have different
* sizes (landscape vs portrait).
@@ -474,8 +477,9 @@
RectF boxRect = drawBoxWithShadow(c, size, size);
LauncherIcons li = LauncherIcons.obtain(mContext);
- Bitmap icon = li.createScaledBitmapWithoutShadow(
- mutateOnMainThread(info.getFullResIcon(mIconCache)), 0);
+ Bitmap icon = li.createBadgedIconBitmap(
+ mutateOnMainThread(info.getFullResIcon(mIconCache)),
+ Process.myUserHandle(), 0).icon;
li.recycle();
Rect src = new Rect(0, 0, icon.getWidth(), icon.getHeight());
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 720a692..d24a5a6 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -298,12 +298,12 @@
if (grid.shouldFadeAdjacentWorkspaceScreens()) {
// In landscape mode the page spacing is set to the default.
- setPageSpacing(grid.defaultPageSpacingPx);
+ setPageSpacing(grid.edgeMarginPx);
} else {
// In portrait, we want the pages spaced such that there is no
// overhang of the previous / next page into the current page viewport.
// We assume symmetrical padding in portrait mode.
- setPageSpacing(Math.max(grid.defaultPageSpacingPx, padding.left + 1));
+ setPageSpacing(Math.max(grid.edgeMarginPx, padding.left + 1));
}
int paddingLeftRight = grid.cellLayoutPaddingLeftRightPx;
@@ -1446,6 +1446,10 @@
public DragView beginDragShared(View child, DragSource source, ItemInfo dragObject,
DragPreviewProvider previewProvider, DragOptions dragOptions) {
+ if (com.android.launcher3.TestProtocol.sDebugTracing) {
+ android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
+ "beginDragShared");
+ }
float iconScale = 1f;
if (child instanceof BubbleTextView) {
Drawable icon = ((BubbleTextView) child).getIcon();
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index 0507470..99a8801 100644
--- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -21,6 +21,7 @@
import static com.android.launcher3.LauncherState.HOTSEAT_ICONS;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_FADE;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_SCALE;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_TRANSLATE;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.anim.Interpolators.ZOOM_OUT;
import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER;
@@ -31,6 +32,7 @@
import android.view.animation.Interpolator;
import com.android.launcher3.LauncherState.PageAlphaProvider;
+import com.android.launcher3.LauncherState.ScaleAndTranslation;
import com.android.launcher3.LauncherStateManager.AnimationConfig;
import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.anim.PropertySetter;
@@ -71,9 +73,10 @@
*/
private void setWorkspaceProperty(LauncherState state, PropertySetter propertySetter,
AnimatorSetBuilder builder, AnimationConfig config) {
- float[] scaleAndTranslation = state.getWorkspaceScaleAndTranslation(mLauncher);
- float[] hotseatScaleAndTranslation = state.getHotseatScaleAndTranslation(mLauncher);
- mNewScale = scaleAndTranslation[0];
+ ScaleAndTranslation scaleAndTranslation = state.getWorkspaceScaleAndTranslation(mLauncher);
+ ScaleAndTranslation hotseatScaleAndTranslation = state.getHotseatScaleAndTranslation(
+ mLauncher);
+ mNewScale = scaleAndTranslation.scale;
PageAlphaProvider pageAlphaProvider = state.getWorkspacePageAlphaProvider(mLauncher);
final int childCount = mWorkspace.getChildCount();
for (int i = 0; i < childCount; i++) {
@@ -84,7 +87,7 @@
int elements = state.getVisibleElements(mLauncher);
Interpolator fadeInterpolator = builder.getInterpolator(ANIM_WORKSPACE_FADE,
pageAlphaProvider.interpolator);
- boolean playAtomicComponent = config.playAtomicComponent();
+ boolean playAtomicComponent = config.playAtomicOverviewScaleComponent();
Hotseat hotseat = mWorkspace.getHotseat();
if (playAtomicComponent) {
Interpolator scaleInterpolator = builder.getInterpolator(ANIM_WORKSPACE_SCALE, ZOOM_OUT);
@@ -98,7 +101,7 @@
dragLayer.mapCoordInSelfToDescendant(hotseat, workspacePivot);
hotseat.setPivotX(workspacePivot[0]);
hotseat.setPivotY(workspacePivot[1]);
- float hotseatScale = hotseatScaleAndTranslation[0];
+ float hotseatScale = hotseatScaleAndTranslation.scale;
propertySetter.setFloat(hotseat, SCALE_PROPERTY, hotseatScale, scaleInterpolator);
float hotseatIconsAlpha = (elements & HOTSEAT_ICONS) != 0 ? 1 : 0;
@@ -112,16 +115,18 @@
return;
}
- Interpolator translationInterpolator = !playAtomicComponent ? LINEAR : ZOOM_OUT;
+ Interpolator translationInterpolator = !playAtomicComponent
+ ? LINEAR
+ : builder.getInterpolator(ANIM_WORKSPACE_TRANSLATE, ZOOM_OUT);
propertySetter.setFloat(mWorkspace, View.TRANSLATION_X,
- scaleAndTranslation[1], translationInterpolator);
+ scaleAndTranslation.translationX, translationInterpolator);
propertySetter.setFloat(mWorkspace, View.TRANSLATION_Y,
- scaleAndTranslation[2], translationInterpolator);
+ scaleAndTranslation.translationY, translationInterpolator);
propertySetter.setFloat(hotseat, View.TRANSLATION_Y,
- hotseatScaleAndTranslation[2], translationInterpolator);
+ hotseatScaleAndTranslation.translationY, translationInterpolator);
propertySetter.setFloat(mWorkspace.getPageIndicator(), View.TRANSLATION_Y,
- hotseatScaleAndTranslation[2], translationInterpolator);
+ hotseatScaleAndTranslation.translationY, translationInterpolator);
// Set scrim
WorkspaceAndHotseatScrim scrim = mLauncher.getDragLayer().getScrim();
@@ -145,7 +150,7 @@
propertySetter.setInt(cl.getScrimBackground(),
DRAWABLE_ALPHA, drawableAlpha, ZOOM_OUT);
}
- if (config.playAtomicComponent()) {
+ if (config.playAtomicOverviewScaleComponent()) {
Interpolator fadeInterpolator = builder.getInterpolator(ANIM_WORKSPACE_FADE,
pageAlphaProvider.interpolator);
propertySetter.setFloat(cl.getShortcutsAndWidgets(), View.ALPHA,
diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
index 69b4bdb..3cfa0b1 100644
--- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
+++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
@@ -32,6 +32,7 @@
import com.android.launcher3.R;
import com.android.launcher3.allapps.AlphabeticalAppsList.AdapterItem;
import com.android.launcher3.compat.UserManagerCompat;
+import com.android.launcher3.model.AppLaunchTracker;
import com.android.launcher3.touch.ItemClickHandler;
import com.android.launcher3.touch.ItemLongClickListener;
import com.android.launcher3.util.PackageManagerHelper;
@@ -263,12 +264,8 @@
case VIEW_TYPE_SEARCH_MARKET:
View searchMarketView = mLayoutInflater.inflate(R.layout.all_apps_search_market,
parent, false);
- searchMarketView.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- mLauncher.startActivitySafely(v, mMarketSearchIntent, null);
- }
- });
+ searchMarketView.setOnClickListener(v -> mLauncher.startActivitySafely(
+ v, mMarketSearchIntent, null, AppLaunchTracker.CONTAINER_SEARCH));
return new ViewHolder(searchMarketView);
case VIEW_TYPE_ALL_APPS_DIVIDER:
return new ViewHolder(mLayoutInflater.inflate(
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index a4ecec7..4a1d432 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -205,7 +205,7 @@
mAppsView.getSearchUiManager().setContentVisibility(visibleElements, setter, allAppsFade);
setter.setInt(mScrimView, ScrimView.DRAG_HANDLE_ALPHA,
- (visibleElements & VERTICAL_SWIPE_INDICATOR) != 0 ? 255 : 0, LINEAR);
+ (visibleElements & VERTICAL_SWIPE_INDICATOR) != 0 ? 255 : 0, allAppsFade);
}
public AnimatorListenerAdapter getProgressAnimatorListener() {
diff --git a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
index 91be504..4515dde 100644
--- a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
+++ b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
@@ -28,6 +28,7 @@
import com.android.launcher3.ExtendedEditText;
import com.android.launcher3.Launcher;
import com.android.launcher3.Utilities;
+import com.android.launcher3.model.AppLaunchTracker;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.PackageManagerHelper;
@@ -111,7 +112,8 @@
return false;
}
return mLauncher.startActivitySafely(v,
- PackageManagerHelper.getMarketSearchIntent(mLauncher, query), null);
+ PackageManagerHelper.getMarketSearchIntent(mLauncher, query), null,
+ AppLaunchTracker.CONTAINER_SEARCH);
}
@Override
diff --git a/src/com/android/launcher3/anim/AnimatorSetBuilder.java b/src/com/android/launcher3/anim/AnimatorSetBuilder.java
index fdac5c8..5c498f8 100644
--- a/src/com/android/launcher3/anim/AnimatorSetBuilder.java
+++ b/src/com/android/launcher3/anim/AnimatorSetBuilder.java
@@ -30,20 +30,21 @@
public static final int ANIM_VERTICAL_PROGRESS = 0;
public static final int ANIM_WORKSPACE_SCALE = 1;
- public static final int ANIM_WORKSPACE_FADE = 2;
- public static final int ANIM_OVERVIEW_SCALE = 3;
- public static final int ANIM_OVERVIEW_FADE = 4;
- public static final int ANIM_ALL_APPS_FADE = 5;
+ public static final int ANIM_WORKSPACE_TRANSLATE = 2;
+ public static final int ANIM_WORKSPACE_FADE = 3;
+ public static final int ANIM_OVERVIEW_SCALE = 4;
+ public static final int ANIM_OVERVIEW_TRANSLATE_X = 5;
+ public static final int ANIM_OVERVIEW_TRANSLATE_Y = 6;
+ public static final int ANIM_OVERVIEW_FADE = 7;
+ public static final int ANIM_ALL_APPS_FADE = 8;
+
+ public static final int FLAG_DONT_ANIMATE_OVERVIEW = 1 << 0;
protected final ArrayList<Animator> mAnims = new ArrayList<>();
private final SparseArray<Interpolator> mInterpolators = new SparseArray<>();
private List<Runnable> mOnFinishRunnables = new ArrayList<>();
-
- /**
- * Associates a tag with all the animations added after this call.
- */
- public void startTag(Object obj) { }
+ private int mFlags = 0;
public void play(Animator anim) {
mAnims.add(anim);
@@ -77,4 +78,12 @@
public void setInterpolator(int animId, Interpolator interpolator) {
mInterpolators.put(animId, interpolator);
}
+
+ public void addFlag(int flag) {
+ mFlags |= flag;
+ }
+
+ public boolean hasFlag(int flag) {
+ return (mFlags & flag) != 0;
+ }
}
diff --git a/src/com/android/launcher3/anim/Interpolators.java b/src/com/android/launcher3/anim/Interpolators.java
index 675e26d..b169cb8 100644
--- a/src/com/android/launcher3/anim/Interpolators.java
+++ b/src/com/android/launcher3/anim/Interpolators.java
@@ -57,6 +57,8 @@
public static final Interpolator EXAGGERATED_EASE;
+ public static final Interpolator INSTANT = t -> 1;
+
private static final int MIN_SETTLE_DURATION = 200;
private static final float OVERSHOOT_FACTOR = 0.9f;
@@ -69,6 +71,7 @@
}
public static final Interpolator OVERSHOOT_1_2 = new OvershootInterpolator(1.2f);
+ public static final Interpolator OVERSHOOT_1_7 = new OvershootInterpolator(1.7f);
public static final Interpolator TOUCH_RESPONSE_INTERPOLATOR =
new PathInterpolator(0.3f, 0f, 0.1f, 1f);
diff --git a/src/com/android/launcher3/config/BaseFlags.java b/src/com/android/launcher3/config/BaseFlags.java
index 106d901..656151f 100644
--- a/src/com/android/launcher3/config/BaseFlags.java
+++ b/src/com/android/launcher3/config/BaseFlags.java
@@ -118,10 +118,6 @@
"ENABLE_HINTS_IN_OVERVIEW", false,
"Show chip hints and gleams on the overview screen");
- public static final TogglableFlag ENABLE_ASSISTANT_GESTURE = new ToggleableGlobalSettingsFlag(
- "ENABLE_ASSISTANT_GESTURE", false,
- "Enable swipe up from the bottom right corner to start assistant");
-
public static void initialize(Context context) {
// Avoid the disk read for user builds
if (Utilities.IS_DEBUG_DEVICE) {
diff --git a/src/com/android/launcher3/dragndrop/DragController.java b/src/com/android/launcher3/dragndrop/DragController.java
index 03dc66e..8b100d9 100644
--- a/src/com/android/launcher3/dragndrop/DragController.java
+++ b/src/com/android/launcher3/dragndrop/DragController.java
@@ -219,6 +219,9 @@
}
private void callOnDragStart() {
+ if (com.android.launcher3.TestProtocol.sDebugTracing) {
+ android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG, "callOnDragStart");
+ }
if (mOptions.preDragCondition != null) {
mOptions.preDragCondition.onPreDragEnd(mDragObject, true /* dragStarted*/);
}
@@ -472,6 +475,9 @@
}
private void handleMoveEvent(int x, int y) {
+ if (com.android.launcher3.TestProtocol.sDebugTracing) {
+ android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG, "handleMoveEvent1");
+ }
mDragObject.dragView.move(x, y);
// Drop on someone?
@@ -488,6 +494,10 @@
if (mIsInPreDrag && mOptions.preDragCondition != null
&& mOptions.preDragCondition.shouldStartDrag(mDistanceSinceScroll)) {
+ if (com.android.launcher3.TestProtocol.sDebugTracing) {
+ android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
+ "handleMoveEvent2");
+ }
callOnDragStart();
}
}
@@ -525,6 +535,10 @@
* Call this from a drag source view.
*/
public boolean onControllerTouchEvent(MotionEvent ev) {
+ if (com.android.launcher3.TestProtocol.sDebugTracing) {
+ android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
+ "onControllerTouchEvent1");
+ }
if (mDragDriver == null || mOptions == null || mOptions.isAccessibleDrag) {
return false;
}
@@ -545,6 +559,10 @@
break;
}
+ if (com.android.launcher3.TestProtocol.sDebugTracing) {
+ android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
+ "onControllerTouchEvent2");
+ }
return mDragDriver.onTouchEvent(ev);
}
diff --git a/src/com/android/launcher3/dragndrop/DragDriver.java b/src/com/android/launcher3/dragndrop/DragDriver.java
index 84fc94d..551f2d0 100644
--- a/src/com/android/launcher3/dragndrop/DragDriver.java
+++ b/src/com/android/launcher3/dragndrop/DragDriver.java
@@ -45,10 +45,18 @@
public void onDragViewAnimationEnd() { }
public boolean onTouchEvent(MotionEvent ev) {
+ if (com.android.launcher3.TestProtocol.sDebugTracing) {
+ android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
+ "onTouchEvent " + ev);
+ }
final int action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_MOVE:
+ if (com.android.launcher3.TestProtocol.sDebugTracing) {
+ android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
+ "onTouchEvent MOVE");
+ }
mEventListener.onDriverDragMove(ev.getX(), ev.getY());
break;
case MotionEvent.ACTION_UP:
diff --git a/src/com/android/launcher3/dragndrop/DragLayer.java b/src/com/android/launcher3/dragndrop/DragLayer.java
index 6950a1f..9f902ed 100644
--- a/src/com/android/launcher3/dragndrop/DragLayer.java
+++ b/src/com/android/launcher3/dragndrop/DragLayer.java
@@ -126,6 +126,10 @@
protected boolean findActiveController(MotionEvent ev) {
if (mActivity.getStateManager().getState().disableInteraction) {
// You Shall Not Pass!!!
+ if (com.android.launcher3.TestProtocol.sDebugTracing) {
+ android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
+ "mActiveController = null");
+ }
mActiveController = null;
return true;
}
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index 7a14b36..bcddd03 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -618,8 +618,7 @@
mFolderIcon.setBackgroundVisible(true);
mFolderIcon.mFolderName.setTextVisibility(true);
if (wasAnimated) {
- mFolderIcon.mBackground.fadeInBackgroundShadow();
- mFolderIcon.mBackground.animateBackgroundStroke();
+ mFolderIcon.animateBgShadowAndStroke();
mFolderIcon.onFolderClose(mContent.getCurrentPage());
if (mFolderIcon.hasDot()) {
mFolderIcon.animateDotScale(0f, 1f);
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index 71c9148..bcd5701 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -189,7 +189,17 @@
return icon;
}
+ public void animateBgShadowAndStroke() {
+ mBackground.fadeInBackgroundShadow();
+ mBackground.animateBackgroundStroke();
+ }
+
+ public BubbleTextView getFolderName() {
+ return mFolderName;
+ }
+
public void getPreviewBounds(Rect outBounds) {
+ mPreviewItemManager.recomputePreviewDrawingParams();
mBackground.getBounds(outBounds);
}
diff --git a/src/com/android/launcher3/logging/LoggerUtils.java b/src/com/android/launcher3/logging/LoggerUtils.java
index 4ef8626..d208077 100644
--- a/src/com/android/launcher3/logging/LoggerUtils.java
+++ b/src/com/android/launcher3/logging/LoggerUtils.java
@@ -15,7 +15,8 @@
*/
package com.android.launcher3.logging;
-import android.content.Context;
+import static com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType.NAVBAR;
+
import android.util.ArrayMap;
import android.util.SparseArray;
import android.view.View;
@@ -97,7 +98,8 @@
case Target.Type.CONTAINER:
str = getFieldName(t.containerType, ContainerType.class);
if (t.containerType == ContainerType.WORKSPACE ||
- t.containerType == ContainerType.HOTSEAT) {
+ t.containerType == ContainerType.HOTSEAT ||
+ t.containerType == NAVBAR) {
str += " id=" + t.pageIndex;
} else if (t.containerType == ContainerType.FOLDER) {
str += " grid(" + t.gridX + "," + t.gridY+ ")";
diff --git a/src/com/android/launcher3/logging/UserEventDispatcher.java b/src/com/android/launcher3/logging/UserEventDispatcher.java
index e115168..c8a4e2a 100644
--- a/src/com/android/launcher3/logging/UserEventDispatcher.java
+++ b/src/com/android/launcher3/logging/UserEventDispatcher.java
@@ -34,7 +34,8 @@
import android.os.SystemClock;
import android.util.Log;
import android.view.View;
-import android.view.ViewParent;
+
+import androidx.annotation.Nullable;
import com.android.launcher3.DropTarget;
import com.android.launcher3.ItemInfo;
@@ -54,15 +55,12 @@
import java.util.Locale;
import java.util.UUID;
-import androidx.annotation.Nullable;
-
/**
* Manages the creation of {@link LauncherEvent}.
* To debug this class, execute following command before side loading a new apk.
*
* $ adb shell setprop log.tag.UserEvent VERBOSE
*/
-@Deprecated
public class UserEventDispatcher implements ResourceBasedOverride {
private static final String TAG = "UserEvent";
@@ -360,6 +358,27 @@
dispatchUserEvent(event, null);
}
+ public void logActionBack(boolean completed, int downX, int downY, boolean isButton,
+ boolean gestureSwipeLeft, int containerType) {
+ int actionTouch = isButton ? Action.Touch.TAP : Action.Touch.SWIPE;
+ Action action = newCommandAction(actionTouch);
+ action.command = Action.Command.BACK;
+ action.dir = isButton
+ ? Action.Direction.NONE
+ : gestureSwipeLeft
+ ? Action.Direction.LEFT
+ : Action.Direction.RIGHT;
+ Target target = newControlTarget(isButton
+ ? LauncherLogProto.ControlType.BACK_BUTTON
+ : LauncherLogProto.ControlType.BACK_GESTURE);
+ target.spanX = downX;
+ target.spanY = downY;
+ target.cardinality = completed ? 1 : 0;
+ LauncherEvent event = newLauncherEvent(action, target, newContainerTarget(containerType));
+
+ dispatchUserEvent(event, null);
+ }
+
/**
* Currently logs following containers: workspace, allapps, widget tray.
* @param reason
diff --git a/src/com/android/launcher3/model/AppLaunchTracker.java b/src/com/android/launcher3/model/AppLaunchTracker.java
new file mode 100644
index 0000000..1613d47
--- /dev/null
+++ b/src/com/android/launcher3/model/AppLaunchTracker.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.model;
+
+import static com.android.launcher3.util.ResourceBasedOverride.Overrides.getObject;
+
+import android.content.ComponentName;
+import android.os.UserHandle;
+
+import com.android.launcher3.R;
+import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
+import com.android.launcher3.util.MainThreadInitializedObject;
+import com.android.launcher3.util.ResourceBasedOverride;
+
+import androidx.annotation.Nullable;
+
+/**
+ * Callback for receiving various app launch events
+ */
+public class AppLaunchTracker implements ResourceBasedOverride {
+
+ /**
+ * Derived from LauncherEvent proto.
+ * TODO: Use proper descriptive constants
+ */
+ public static final String CONTAINER_DEFAULT = Integer.toString(ContainerType.WORKSPACE);
+ public static final String CONTAINER_ALL_APPS = Integer.toString(ContainerType.ALLAPPS);
+ public static final String CONTAINER_PREDICTIONS = Integer.toString(ContainerType.PREDICTION);
+ public static final String CONTAINER_SEARCH = Integer.toString(ContainerType.SEARCHRESULT);
+
+
+ public static final MainThreadInitializedObject<AppLaunchTracker> INSTANCE =
+ new MainThreadInitializedObject<>(c ->
+ getObject(AppLaunchTracker.class, c, R.string.app_launch_tracker_class));
+
+ public void onStartShortcut(String packageName, String shortcutId, UserHandle user,
+ @Nullable String container) { }
+
+ public void onStartApp(ComponentName componentName, UserHandle user,
+ @Nullable String container) { }
+
+ public void onReturnedToHome() { }
+}
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index 10ecc4f..080a0cb 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -187,6 +187,10 @@
* @return the container if shown or null.
*/
public static PopupContainerWithArrow showForIcon(BubbleTextView icon) {
+ if (com.android.launcher3.TestProtocol.sDebugTracing) {
+ android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
+ "PopupContainerWithArrow.showForIcon");
+ }
Launcher launcher = Launcher.getLauncher(icon.getContext());
if (getOpen(launcher) != null) {
// There is already an items container open, so don't open this one.
diff --git a/src/com/android/launcher3/popup/SystemShortcut.java b/src/com/android/launcher3/popup/SystemShortcut.java
index fdc1b39..e7b8292 100644
--- a/src/com/android/launcher3/popup/SystemShortcut.java
+++ b/src/com/android/launcher3/popup/SystemShortcut.java
@@ -195,7 +195,7 @@
return view -> {
Intent intent = new PackageManagerHelper(view.getContext()).getMarketIntent(
itemInfo.getTargetComponent().getPackageName());
- activity.startActivitySafely(view, intent, itemInfo);
+ activity.startActivitySafely(view, intent, itemInfo, null);
AbstractFloatingView.closeAllOpenViews(activity);
};
}
diff --git a/src/com/android/launcher3/states/SpringLoadedState.java b/src/com/android/launcher3/states/SpringLoadedState.java
index fcace98..be3e6c9 100644
--- a/src/com/android/launcher3/states/SpringLoadedState.java
+++ b/src/com/android/launcher3/states/SpringLoadedState.java
@@ -41,7 +41,7 @@
}
@Override
- public float[] getWorkspaceScaleAndTranslation(Launcher launcher) {
+ public ScaleAndTranslation getWorkspaceScaleAndTranslation(Launcher launcher) {
DeviceProfile grid = launcher.getDeviceProfile();
Workspace ws = launcher.getWorkspace();
if (ws.getChildCount() == 0) {
@@ -50,7 +50,7 @@
if (grid.isVerticalBarLayout()) {
float scale = grid.workspaceSpringLoadShrinkFactor;
- return new float[] {scale, 0, 0};
+ return new ScaleAndTranslation(scale, 0, 0);
}
float scale = grid.workspaceSpringLoadShrinkFactor;
@@ -69,12 +69,12 @@
float myCenter = ws.getTop() + halfHeight;
float cellTopFromCenter = halfHeight - ws.getChildAt(0).getTop();
float actualCellTop = myCenter - cellTopFromCenter * scale;
- return new float[] { scale, 0, (desiredCellTop - actualCellTop) / scale};
+ return new ScaleAndTranslation(scale, 0, (desiredCellTop - actualCellTop) / scale);
}
@Override
- public float[] getHotseatScaleAndTranslation(Launcher launcher) {
- return new float[] {1, 0, 0};
+ public ScaleAndTranslation getHotseatScaleAndTranslation(Launcher launcher) {
+ return new ScaleAndTranslation(1, 0, 0);
}
@Override
diff --git a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
index c125c10..0274de3 100644
--- a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
+++ b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
@@ -20,7 +20,7 @@
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.LauncherStateManager.ANIM_ALL;
-import static com.android.launcher3.LauncherStateManager.ATOMIC_COMPONENT;
+import static com.android.launcher3.LauncherStateManager.ATOMIC_OVERVIEW_SCALE_COMPONENT;
import static com.android.launcher3.LauncherStateManager.NON_ATOMIC_COMPONENT;
import static com.android.launcher3.Utilities.SINGLE_FRAME_MS;
import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity;
@@ -38,9 +38,6 @@
import com.android.launcher3.LauncherAnimUtils;
import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherStateManager.AnimationComponents;
-import com.android.launcher3.LauncherStateManager.AnimationConfig;
-import com.android.launcher3.LauncherStateManager.StateHandler;
-import com.android.launcher3.TestProtocol;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
@@ -68,10 +65,11 @@
* Play an atomic recents animation when the progress from NORMAL to OVERVIEW reaches this.
*/
public static final float ATOMIC_OVERVIEW_ANIM_THRESHOLD = 0.5f;
- protected static final long ATOMIC_DURATION = 200;
+ protected final long ATOMIC_DURATION = getAtomicDuration();
protected final Launcher mLauncher;
protected final SwipeDetector mDetector;
+ protected final SwipeDetector.Direction mSwipeDirection;
private boolean mNoIntercept;
protected int mStartContainerType;
@@ -108,6 +106,11 @@
public AbstractStateChangeTouchController(Launcher l, SwipeDetector.Direction dir) {
mLauncher = l;
mDetector = new SwipeDetector(l, this, dir);
+ mSwipeDirection = dir;
+ }
+
+ protected long getAtomicDuration() {
+ return 200;
}
protected abstract boolean canInterceptTouch(MotionEvent ev);
@@ -214,14 +217,15 @@
}
if (mAtomicComponentsController != null) {
- animComponents &= ~ATOMIC_COMPONENT;
+ animComponents &= ~ATOMIC_OVERVIEW_SCALE_COMPONENT;
}
mProgressMultiplier = initCurrentAnimation(animComponents);
mCurrentAnimation.dispatchOnStart();
return true;
}
- private boolean goingBetweenNormalAndOverview(LauncherState fromState, LauncherState toState) {
+ protected boolean goingBetweenNormalAndOverview(LauncherState fromState,
+ LauncherState toState) {
return (fromState == NORMAL || fromState == OVERVIEW)
&& (toState == NORMAL || toState == OVERVIEW)
&& mPendingAnimation == null;
@@ -229,12 +233,17 @@
@Override
public void onDragStart(boolean start) {
+ if (com.android.launcher3.TestProtocol.sDebugTracing) {
+ android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
+ "AbstractStateChangeTouchController.onDragStart() called with: start = [" +
+ start + "]");
+ }
mStartState = mLauncher.getStateManager().getState();
if (mStartState == ALL_APPS) {
mStartContainerType = LauncherLogProto.ContainerType.ALLAPPS;
} else if (mStartState == NORMAL) {
mStartContainerType = getLogContainerTypeForNormalState();
- } else if (mStartState == OVERVIEW){
+ } else if (mStartState == OVERVIEW){
mStartContainerType = LauncherLogProto.ContainerType.TASKSWITCHER;
}
if (mCurrentAnimation == null) {
@@ -260,8 +269,14 @@
public boolean onDrag(float displacement) {
float deltaProgress = mProgressMultiplier * (displacement - mDisplacementShift);
float progress = deltaProgress + mStartProgress;
+ if (com.android.launcher3.TestProtocol.sDebugTracing) {
+ android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
+ "AbstractStateChangeTouchController.onDrag() called with: displacement = [" +
+ displacement + "], progress = [" + progress + "]");
+ }
updateProgress(progress);
- boolean isDragTowardPositive = (displacement - mDisplacementShift) < 0;
+ boolean isDragTowardPositive = mSwipeDirection.isPositive(
+ displacement - mDisplacementShift);
if (progress <= 0) {
if (reinitCurrentAnimation(false, isDragTowardPositive)) {
mDisplacementShift = displacement;
@@ -297,7 +312,7 @@
* When going between normal and overview states, see if we passed the overview threshold and
* play the appropriate atomic animation if so.
*/
- protected void maybeUpdateAtomicAnim(LauncherState fromState, LauncherState toState,
+ private void maybeUpdateAtomicAnim(LauncherState fromState, LauncherState toState,
float progress) {
if (!goingBetweenNormalAndOverview(fromState, toState)) {
return;
@@ -347,14 +362,8 @@
private AnimatorSet createAtomicAnimForState(LauncherState fromState, LauncherState targetState,
long duration) {
AnimatorSetBuilder builder = getAnimatorSetBuilderForStates(fromState, targetState);
- mLauncher.getStateManager().prepareForAtomicAnimation(fromState, targetState, builder);
- AnimationConfig config = new AnimationConfig();
- config.animComponents = ATOMIC_COMPONENT;
- config.duration = duration;
- for (StateHandler handler : mLauncher.getStateManager().getStateHandlers()) {
- handler.setStateWithAnimation(targetState, builder, config);
- }
- return builder.build();
+ return mLauncher.getStateManager().createAtomicAnimation(fromState, targetState, builder,
+ ATOMIC_OVERVIEW_SCALE_COMPONENT, duration);
}
protected AnimatorSetBuilder getAnimatorSetBuilderForStates(LauncherState fromState,
@@ -384,6 +393,12 @@
? MIN_PROGRESS_TO_ALL_APPS : SUCCESS_TRANSITION_PROGRESS;
targetState = (interpolatedProgress > successProgress) ? mToState : mFromState;
}
+ if (com.android.launcher3.TestProtocol.sDebugTracing) {
+ android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
+ "AbstractStateChangeTouchController.onDragEnd() called with: velocity = [" +
+ velocity + "], fling = [" + fling + "], target state: " +
+ targetState.getClass().getSimpleName());
+ }
final float endProgress;
final float startProgress;
@@ -434,11 +449,7 @@
mLauncher.getAppsView().addSpringFromFlingUpdateListener(anim, velocity);
}
anim.start();
- settleAtomicAnimation(endProgress, anim.getDuration());
- }
-
- protected void settleAtomicAnimation(float endProgress, long duration) {
- mAtomicAnimAutoPlayInfo = new AutoPlayAtomicAnimationInfo(endProgress, duration);
+ mAtomicAnimAutoPlayInfo = new AutoPlayAtomicAnimationInfo(endProgress, anim.getDuration());
maybeAutoPlayAtomicComponentsAnim();
}
diff --git a/src/com/android/launcher3/touch/ItemClickHandler.java b/src/com/android/launcher3/touch/ItemClickHandler.java
index 52fef9f..3c77860 100644
--- a/src/com/android/launcher3/touch/ItemClickHandler.java
+++ b/src/com/android/launcher3/touch/ItemClickHandler.java
@@ -22,6 +22,7 @@
import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_SUSPENDED;
import static com.android.launcher3.Launcher.REQUEST_BIND_PENDING_APPWIDGET;
import static com.android.launcher3.Launcher.REQUEST_RECONFIGURE_APPWIDGET;
+import static com.android.launcher3.model.AppLaunchTracker.CONTAINER_ALL_APPS;
import android.app.AlertDialog;
import android.content.Intent;
@@ -31,6 +32,8 @@
import android.view.View.OnClickListener;
import android.widget.Toast;
+import androidx.annotation.Nullable;
+
import com.android.launcher3.AppInfo;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.FolderInfo;
@@ -56,9 +59,21 @@
/**
* Instance used for click handling on items
*/
- public static final OnClickListener INSTANCE = ItemClickHandler::onClick;
+ public static final OnClickListener INSTANCE = getInstance(null);
- private static void onClick(View v) {
+ public static final OnClickListener getInstance(String sourceContainer) {
+ return v -> onClick(v, sourceContainer);
+ }
+
+ private static void onClick(View v, String sourceContainer) {
+ if (com.android.launcher3.TestProtocol.sDebugTracing) {
+ android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
+ "onClick() called with: v = [" + v.getClass().getSimpleName() +
+ "], sourceContainer = [" +
+ (sourceContainer != null ?
+ sourceContainer.getClass().getSimpleName() : "null")
+ + "]");
+ }
// Make sure that rogue clicks don't get through while allapps is launching, or after the
// view has detached (it's possible for this to happen if the view is removed mid touch).
if (v.getWindowToken() == null) {
@@ -72,13 +87,14 @@
Object tag = v.getTag();
if (tag instanceof ShortcutInfo) {
- onClickAppShortcut(v, (ShortcutInfo) tag, launcher);
+ onClickAppShortcut(v, (ShortcutInfo) tag, launcher, sourceContainer);
} else if (tag instanceof FolderInfo) {
if (v instanceof FolderIcon) {
onClickFolderIcon(v);
}
} else if (tag instanceof AppInfo) {
- startAppShortcutOrInfoActivity(v, (AppInfo) tag, launcher);
+ startAppShortcutOrInfoActivity(v, (AppInfo) tag, launcher,
+ sourceContainer == null ? CONTAINER_ALL_APPS: sourceContainer);
} else if (tag instanceof LauncherAppWidgetInfo) {
if (v instanceof PendingAppWidgetHostView) {
onClickPendingWidget((PendingAppWidgetHostView) v, launcher);
@@ -154,7 +170,7 @@
private static void startMarketIntentForPackage(View v, Launcher launcher, String packageName) {
ItemInfo item = (ItemInfo) v.getTag();
Intent intent = new PackageManagerHelper(launcher).getMarketIntent(packageName);
- launcher.startActivitySafely(v, intent, item);
+ launcher.startActivitySafely(v, intent, item, null);
}
/**
@@ -162,7 +178,8 @@
*
* @param v The view that was clicked. Must be a tagged with a {@link ShortcutInfo}.
*/
- public static void onClickAppShortcut(View v, ShortcutInfo shortcut, Launcher launcher) {
+ public static void onClickAppShortcut(View v, ShortcutInfo shortcut, Launcher launcher,
+ @Nullable String sourceContainer) {
if (shortcut.isDisabled()) {
final int disabledFlags = shortcut.runtimeStatusFlags & ShortcutInfo.FLAG_DISABLED_MASK;
if ((disabledFlags &
@@ -201,10 +218,11 @@
}
// Start activities
- startAppShortcutOrInfoActivity(v, shortcut, launcher);
+ startAppShortcutOrInfoActivity(v, shortcut, launcher, sourceContainer);
}
- private static void startAppShortcutOrInfoActivity(View v, ItemInfo item, Launcher launcher) {
+ private static void startAppShortcutOrInfoActivity(View v, ItemInfo item, Launcher launcher,
+ @Nullable String sourceContainer) {
Intent intent;
if (item instanceof PromiseAppInfo) {
PromiseAppInfo promiseAppInfo = (PromiseAppInfo) item;
@@ -227,6 +245,6 @@
intent.setPackage(null);
}
}
- launcher.startActivitySafely(v, intent, item);
+ launcher.startActivitySafely(v, intent, item, sourceContainer);
}
}
diff --git a/src/com/android/launcher3/touch/ItemLongClickListener.java b/src/com/android/launcher3/touch/ItemLongClickListener.java
index babbcdd..003b442 100644
--- a/src/com/android/launcher3/touch/ItemLongClickListener.java
+++ b/src/com/android/launcher3/touch/ItemLongClickListener.java
@@ -74,6 +74,10 @@
}
private static boolean onAllAppsItemLongClick(View v) {
+ if (com.android.launcher3.TestProtocol.sDebugTracing) {
+ android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
+ "onAllAppsItemLongClick");
+ }
Launcher launcher = Launcher.getLauncher(v.getContext());
if (!canStartDrag(launcher)) return false;
// When we have exited all apps or are in transition, disregard long clicks
diff --git a/src/com/android/launcher3/touch/SwipeDetector.java b/src/com/android/launcher3/touch/SwipeDetector.java
index a0a410e..d758a29 100644
--- a/src/com/android/launcher3/touch/SwipeDetector.java
+++ b/src/com/android/launcher3/touch/SwipeDetector.java
@@ -24,6 +24,8 @@
import android.view.VelocityTracker;
import android.view.ViewConfiguration;
+import com.android.launcher3.Utilities;
+
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
@@ -64,20 +66,25 @@
public static abstract class Direction {
- abstract float getDisplacement(MotionEvent ev, int pointerIndex, PointF refPoint);
+ abstract float getDisplacement(MotionEvent ev, int pointerIndex, PointF refPoint,
+ boolean isRtl);
/**
* Distance in pixels a touch can wander before we think the user is scrolling.
*/
abstract float getActiveTouchSlop(MotionEvent ev, int pointerIndex, PointF downPos);
- abstract float getVelocity(VelocityTracker tracker);
+ abstract float getVelocity(VelocityTracker tracker, boolean isRtl);
+
+ abstract boolean isPositive(float displacement);
+
+ abstract boolean isNegative(float displacement);
}
public static final Direction VERTICAL = new Direction() {
@Override
- float getDisplacement(MotionEvent ev, int pointerIndex, PointF refPoint) {
+ float getDisplacement(MotionEvent ev, int pointerIndex, PointF refPoint, boolean isRtl) {
return ev.getY(pointerIndex) - refPoint.y;
}
@@ -87,16 +94,32 @@
}
@Override
- float getVelocity(VelocityTracker tracker) {
+ float getVelocity(VelocityTracker tracker, boolean isRtl) {
return tracker.getYVelocity();
}
+
+ @Override
+ boolean isPositive(float displacement) {
+ // Up
+ return displacement < 0;
+ }
+
+ @Override
+ boolean isNegative(float displacement) {
+ // Down
+ return displacement > 0;
+ }
};
public static final Direction HORIZONTAL = new Direction() {
@Override
- float getDisplacement(MotionEvent ev, int pointerIndex, PointF refPoint) {
- return ev.getX(pointerIndex) - refPoint.x;
+ float getDisplacement(MotionEvent ev, int pointerIndex, PointF refPoint, boolean isRtl) {
+ float displacement = ev.getX(pointerIndex) - refPoint.x;
+ if (isRtl) {
+ displacement = -displacement;
+ }
+ return displacement;
}
@Override
@@ -105,8 +128,24 @@
}
@Override
- float getVelocity(VelocityTracker tracker) {
- return tracker.getXVelocity();
+ float getVelocity(VelocityTracker tracker, boolean isRtl) {
+ float velocity = tracker.getXVelocity();
+ if (isRtl) {
+ velocity = -velocity;
+ }
+ return velocity;
+ }
+
+ @Override
+ boolean isPositive(float displacement) {
+ // Right
+ return displacement > 0;
+ }
+
+ @Override
+ boolean isNegative(float displacement) {
+ // Left
+ return displacement < 0;
}
};
@@ -159,6 +198,7 @@
private final PointF mDownPos = new PointF();
private final PointF mLastPos = new PointF();
private final Direction mDir;
+ private final boolean mIsRtl;
private final float mTouchSlop;
private final float mMaxVelocity;
@@ -179,18 +219,23 @@
boolean onDrag(float displacement);
+ default boolean onDrag(float displacement, MotionEvent event) {
+ return onDrag(displacement);
+ }
+
void onDragEnd(float velocity, boolean fling);
}
public SwipeDetector(@NonNull Context context, @NonNull Listener l, @NonNull Direction dir) {
- this(ViewConfiguration.get(context), l, dir);
+ this(ViewConfiguration.get(context), l, dir, Utilities.isRtl(context.getResources()));
}
@VisibleForTesting
protected SwipeDetector(@NonNull ViewConfiguration config, @NonNull Listener l,
- @NonNull Direction dir) {
+ @NonNull Direction dir, boolean isRtl) {
mListener = l;
mDir = dir;
+ mIsRtl = isRtl;
mTouchSlop = config.getScaledTouchSlop();
mMaxVelocity = config.getScaledMaximumFlingVelocity();
}
@@ -212,8 +257,8 @@
}
// Check if the client is interested in scroll in current direction.
- if (((mScrollConditions & DIRECTION_NEGATIVE) > 0 && mDisplacement > 0) ||
- ((mScrollConditions & DIRECTION_POSITIVE) > 0 && mDisplacement < 0)) {
+ if (((mScrollConditions & DIRECTION_NEGATIVE) > 0 && mDir.isNegative(mDisplacement)) ||
+ ((mScrollConditions & DIRECTION_POSITIVE) > 0 && mDir.isPositive(mDisplacement))) {
return true;
}
return false;
@@ -259,14 +304,14 @@
if (pointerIndex == INVALID_POINTER_ID) {
break;
}
- mDisplacement = mDir.getDisplacement(ev, pointerIndex, mDownPos);
+ mDisplacement = mDir.getDisplacement(ev, pointerIndex, mDownPos, mIsRtl);
// handle state and listener calls.
if (mState != ScrollState.DRAGGING && shouldScrollStart(ev, pointerIndex)) {
setState(ScrollState.DRAGGING);
}
if (mState == ScrollState.DRAGGING) {
- reportDragging();
+ reportDragging(ev);
}
mLastPos.set(ev.getX(pointerIndex), ev.getY(pointerIndex));
break;
@@ -315,24 +360,24 @@
* @see #DIRECTION_BOTH
*/
public boolean wasInitialTouchPositive() {
- return mSubtractDisplacement < 0;
+ return mDir.isPositive(mSubtractDisplacement);
}
- private boolean reportDragging() {
+ private boolean reportDragging(MotionEvent event) {
if (mDisplacement != mLastDisplacement) {
if (DBG) {
Log.d(TAG, String.format("onDrag disp=%.1f", mDisplacement));
}
mLastDisplacement = mDisplacement;
- return mListener.onDrag(mDisplacement - mSubtractDisplacement);
+ return mListener.onDrag(mDisplacement - mSubtractDisplacement, event);
}
return true;
}
private void reportDragEnd() {
mVelocityTracker.computeCurrentVelocity(1000, mMaxVelocity);
- float velocity = mDir.getVelocity(mVelocityTracker) / 1000;
+ float velocity = mDir.getVelocity(mVelocityTracker, mIsRtl) / 1000;
if (DBG) {
Log.d(TAG, String.format("onScrollEnd disp=%.1f, velocity=%.1f",
mDisplacement, velocity));
diff --git a/src/com/android/launcher3/util/InstantAppResolver.java b/src/com/android/launcher3/util/InstantAppResolver.java
index 5dc7af8..031a40d 100644
--- a/src/com/android/launcher3/util/InstantAppResolver.java
+++ b/src/com/android/launcher3/util/InstantAppResolver.java
@@ -24,9 +24,6 @@
import com.android.launcher3.AppInfo;
import com.android.launcher3.R;
-import java.util.Collections;
-import java.util.List;
-
/**
* A wrapper class to access instant app related APIs.
*/
@@ -55,8 +52,4 @@
}
return false;
}
-
- public List<ApplicationInfo> getInstantApps() {
- return Collections.emptyList();
- }
}
diff --git a/src/com/android/launcher3/views/BaseDragLayer.java b/src/com/android/launcher3/views/BaseDragLayer.java
index 4545a1e..bd6bfd6 100644
--- a/src/com/android/launcher3/views/BaseDragLayer.java
+++ b/src/com/android/launcher3/views/BaseDragLayer.java
@@ -114,16 +114,28 @@
}
protected boolean findActiveController(MotionEvent ev) {
+ if (com.android.launcher3.TestProtocol.sDebugTracing) {
+ android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
+ "mActiveController = null");
+ }
mActiveController = null;
AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(mActivity);
if (topView != null && topView.onControllerInterceptTouchEvent(ev)) {
+ if (com.android.launcher3.TestProtocol.sDebugTracing) {
+ android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
+ "setting controller1: " + topView.getClass().getSimpleName());
+ }
mActiveController = topView;
return true;
}
for (TouchController controller : mControllers) {
if (controller.onControllerInterceptTouchEvent(ev)) {
+ if (com.android.launcher3.TestProtocol.sDebugTracing) {
+ android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
+ "setting controller1: " + controller.getClass().getSimpleName());
+ }
mActiveController = controller;
return true;
}
@@ -193,8 +205,17 @@
}
if (mActiveController != null) {
+ if (com.android.launcher3.TestProtocol.sDebugTracing) {
+ android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
+ "BaseDragLayer before onControllerTouchEvent " +
+ mActiveController.getClass().getSimpleName());
+ }
return mActiveController.onControllerTouchEvent(ev);
} else {
+ if (com.android.launcher3.TestProtocol.sDebugTracing) {
+ android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
+ "BaseDragLayer no controller");
+ }
// In case no child view handled the touch event, we may not get onIntercept anymore
return findActiveController(ev);
}
diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java
index 2a5418d..5889468 100644
--- a/src/com/android/launcher3/views/FloatingIconView.java
+++ b/src/com/android/launcher3/views/FloatingIconView.java
@@ -15,10 +15,13 @@
*/
package com.android.launcher3.views;
+import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.config.FeatureFlags.ADAPTIVE_ICON_WINDOW_ANIM;
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.graphics.Canvas;
@@ -45,8 +48,8 @@
import com.android.launcher3.LauncherModel;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
-import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.dragndrop.DragLayer;
+import com.android.launcher3.dragndrop.FolderAdaptiveIcon;
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.folder.FolderShape;
import com.android.launcher3.graphics.ShiftedBitmapDrawable;
@@ -57,18 +60,20 @@
import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
+import static com.android.launcher3.Utilities.mapToRange;
+
/**
* A view that is created to look like another view with the purpose of creating fluid animations.
*/
public class FloatingIconView extends View implements Animator.AnimatorListener, ClipPathView {
+ public static final float SHAPE_PROGRESS_DURATION = 0.15f;
+
private static final Rect sTmpRect = new Rect();
- private Runnable mStartRunnable;
private Runnable mEndRunnable;
- private int mOriginalHeight;
private final int mBlurSizeOutline;
private boolean mIsAdaptiveIcon = false;
@@ -79,30 +84,28 @@
private final Rect mStartRevealRect = new Rect();
private final Rect mEndRevealRect = new Rect();
private Path mClipPath;
- protected final Rect mOutline = new Rect();
- private final float mTaskCornerRadius;
+ private float mTaskCornerRadius;
private final Rect mFinalDrawableBounds = new Rect();
private final Rect mBgDrawableBounds = new Rect();
private float mBgDrawableStartScale = 1f;
+ private float mBgDrawableEndScale = 1f;
private FloatingIconView(Context context) {
super(context);
-
mBlurSizeOutline = context.getResources().getDimensionPixelSize(
R.dimen.blur_size_medium_outline);
-
- mTaskCornerRadius = 0; // TODO
}
/**
* Positions this view to match the size and location of {@param rect}.
- *
* @param alpha The alpha to set this view.
* @param progress A value from [0, 1] that represents the animation progress.
- * @param windowAlphaThreshold The value at which the window alpha is 0.
+ * @param shapeProgressStart The progress value at which to start the shape reveal.
+ * @param cornerRadius The corner radius of {@param rect}.
*/
- public void update(RectF rect, float alpha, float progress, float windowAlphaThreshold) {
+ public void update(RectF rect, float alpha, float progress, float shapeProgressStart,
+ float cornerRadius, boolean isOpening) {
setAlpha(alpha);
LayoutParams lp = (LayoutParams) getLayoutParams();
@@ -113,55 +116,50 @@
float scaleX = rect.width() / (float) lp.width;
float scaleY = rect.height() / (float) lp.height;
- float scale = mIsAdaptiveIcon ? Math.max(scaleX, scaleY) : Math.min(scaleX, scaleY);
+ float scale = mIsAdaptiveIcon && !isOpening ? Math.max(scaleX, scaleY)
+ : Math.min(scaleX, scaleY);
+ scale = Math.max(1f, scale);
+
setPivotX(0);
setPivotY(0);
setScaleX(scale);
setScaleY(scale);
- // Wait until the window is no longer visible before morphing the icon into its final shape.
- float shapeRevealProgress = Utilities.mapToRange(Math.max(windowAlphaThreshold, progress),
- windowAlphaThreshold, 1f, 0f, 1, Interpolators.LINEAR);
- if (mIsAdaptiveIcon && shapeRevealProgress > 0) {
+ // shapeRevealProgress = 1 when progress = shapeProgressStart + SHAPE_PROGRESS_DURATION
+ float toMax = isOpening ? 1 / SHAPE_PROGRESS_DURATION : 1f;
+ float shapeRevealProgress = Utilities.boundToRange(mapToRange(
+ Math.max(shapeProgressStart, progress), shapeProgressStart, 1f, 0, toMax,
+ LINEAR), 0, 1);
+
+ mTaskCornerRadius = cornerRadius;
+ if (mIsAdaptiveIcon && shapeRevealProgress >= 0) {
if (mRevealAnimator == null) {
- mEndRevealRect.set(mOutline);
- // We play the reveal animation in reverse so that we end with the icon shape.
mRevealAnimator = (ValueAnimator) FolderShape.getShape().createRevealAnimator(this,
- mStartRevealRect, mEndRevealRect, mTaskCornerRadius / scale, true);
- mRevealAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mRevealAnimator = null;
- }
- });
+ mStartRevealRect, mEndRevealRect, mTaskCornerRadius / scale, !isOpening);
mRevealAnimator.start();
// We pause here so we can set the current fraction ourselves.
mRevealAnimator.pause();
}
- float bgScale = shapeRevealProgress + mBgDrawableStartScale * (1 - shapeRevealProgress);
- setBackgroundDrawableBounds(bgScale);
-
mRevealAnimator.setCurrentFraction(shapeRevealProgress);
+
+ float bgScale = (mBgDrawableEndScale * shapeRevealProgress) + mBgDrawableStartScale
+ * (1 - shapeRevealProgress);
+ setBackgroundDrawableBounds(bgScale);
}
invalidate();
invalidateOutline();
}
@Override
- public void onAnimationStart(Animator animator) {
- if (mStartRunnable != null) {
- mStartRunnable.run();
- }
- }
-
- @Override
public void onAnimationEnd(Animator animator) {
- if (mRevealAnimator != null) {
- mRevealAnimator.end();
- }
if (mEndRunnable != null) {
mEndRunnable.run();
+ } else {
+ // End runnable also ends the reveal animator, so we manually handle it here.
+ if (mRevealAnimator != null) {
+ mRevealAnimator.end();
+ }
}
}
@@ -175,7 +173,6 @@
Utilities.getLocationBoundsForView(launcher, v, positionOut);
final LayoutParams lp = new LayoutParams(positionOut.width(), positionOut.height());
lp.ignoreInsets = true;
- mOriginalHeight = lp.height;
// Position the floating view exactly on top of the original
lp.leftMargin = positionOut.left;
@@ -188,11 +185,11 @@
}
@WorkerThread
- private void getIcon(Launcher launcher, View v, ItemInfo info, boolean useDrawableAsIs,
- float aspectRatio) {
+ private void getIcon(Launcher launcher, View v, ItemInfo info, boolean isOpening,
+ Runnable onIconLoadedRunnable) {
final LayoutParams lp = (LayoutParams) getLayoutParams();
Drawable drawable = null;
- boolean supportsAdaptiveIcons = ADAPTIVE_ICON_WINDOW_ANIM.get() && !useDrawableAsIs
+ boolean supportsAdaptiveIcons = ADAPTIVE_ICON_WINDOW_ANIM.get()
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.O;
if (!supportsAdaptiveIcons && v instanceof BubbleTextView) {
// Similar to DragView, we simply use the BubbleTextView icon here.
@@ -209,7 +206,7 @@
}
if (drawable == null) {
drawable = Utilities.getFullDrawable(launcher, info, lp.width, lp.height,
- useDrawableAsIs, new Object[1]);
+ false, new Object[1]);
}
Drawable finalDrawable = drawable == null ? null
@@ -221,6 +218,7 @@
new Handler(Looper.getMainLooper()).post(() -> {
if (isAdaptiveIcon) {
mIsAdaptiveIcon = true;
+ boolean isFolderIcon = finalDrawable instanceof FolderAdaptiveIcon;
AdaptiveIconDrawable adaptiveIcon = (AdaptiveIconDrawable) finalDrawable;
Drawable background = adaptiveIcon.getBackground();
@@ -234,35 +232,57 @@
}
mForeground = foreground;
- mFinalDrawableBounds.set(iconOffset, iconOffset, lp.width -
- iconOffset, mOriginalHeight - iconOffset);
if (mForeground instanceof ShiftedBitmapDrawable && v instanceof FolderIcon) {
ShiftedBitmapDrawable sbd = (ShiftedBitmapDrawable) mForeground;
((FolderIcon) v).getPreviewBounds(sTmpRect);
sbd.setShiftX(sbd.getShiftX() - sTmpRect.left);
sbd.setShiftY(sbd.getShiftY() - sTmpRect.top);
}
+
+ final int originalHeight = lp.height;
+ final int originalWidth = lp.width;
+
+ int blurMargin = mBlurSizeOutline / 2;
+ mFinalDrawableBounds.set(0, 0, originalWidth, originalHeight);
+ if (!isFolderIcon) {
+ mFinalDrawableBounds.inset(iconOffset - blurMargin, iconOffset - blurMargin);
+ }
mForeground.setBounds(mFinalDrawableBounds);
mBackground.setBounds(mFinalDrawableBounds);
- int blurMargin = mBlurSizeOutline / 2;
- mStartRevealRect.set(blurMargin, blurMargin , lp.width - blurMargin,
- mOriginalHeight - blurMargin);
+ mStartRevealRect.set(0, 0, originalWidth, originalHeight);
- if (aspectRatio > 0) {
- lp.height = (int) Math.max(lp.height, lp.width * aspectRatio);
- layout(lp.leftMargin, lp.topMargin, lp.leftMargin + lp.width, lp.topMargin
- + lp.height);
+ if (!isFolderIcon) {
+ mStartRevealRect.inset(mBlurSizeOutline, mBlurSizeOutline);
}
- mBgDrawableStartScale = (float) lp.height / mOriginalHeight;
- setBackgroundDrawableBounds(mBgDrawableStartScale);
- // Set up outline
- mOutline.set(0, 0, lp.width, lp.height);
+ float aspectRatio = launcher.getDeviceProfile().aspectRatio;
+ if (launcher.getDeviceProfile().isVerticalBarLayout()) {
+ lp.width = (int) Math.max(lp.width, lp.height * aspectRatio);
+ } else {
+ lp.height = (int) Math.max(lp.height, lp.width * aspectRatio);
+ }
+ layout(lp.leftMargin, lp.topMargin, lp.leftMargin + lp.width, lp.topMargin
+ + lp.height);
+
+ Rect rectOutline = new Rect();
+ float scale = Math.max((float) lp.height / originalHeight,
+ (float) lp.width / originalWidth);
+ if (isOpening) {
+ mBgDrawableStartScale = 1f;
+ mBgDrawableEndScale = scale;
+ rectOutline.set(0, 0, originalWidth, originalHeight);
+ } else {
+ mBgDrawableStartScale = scale;
+ mBgDrawableEndScale = 1f;
+ rectOutline.set(0, 0, lp.width, lp.height);
+ }
+ mEndRevealRect.set(0, 0, lp.width, lp.height);
+ setBackgroundDrawableBounds(mBgDrawableStartScale);
setOutlineProvider(new ViewOutlineProvider() {
@Override
public void getOutline(View view, Outline outline) {
- outline.setRoundRect(mOutline, mTaskCornerRadius);
+ outline.setRoundRect(rectOutline, mTaskCornerRadius);
}
});
setClipToOutline(true);
@@ -270,6 +290,7 @@
setBackground(finalDrawable);
}
+ onIconLoadedRunnable.run();
invalidate();
invalidateOutline();
});
@@ -337,6 +358,9 @@
}
@Override
+ public void onAnimationStart(Animator animator) {}
+
+ @Override
public void onAnimationCancel(Animator animator) {}
@Override
@@ -344,17 +368,16 @@
/**
* Creates a floating icon view for {@param originalView}.
- *
* @param originalView The view to copy
* @param hideOriginal If true, it will hide {@param originalView} while this view is visible.
- * @param useDrawableAsIs If true, we do not separate the foreground/background of adaptive
- * icons. TODO(b/122843905): We can remove this once app opening uses new animation.
- * @param aspectRatio If >= 0, we will use this aspect ratio for the initial adaptive icon size.
* @param positionOut Rect that will hold the size and position of v.
+ * @param isOpening True if this view replaces the icon for app open animation.
*/
public static FloatingIconView getFloatingIconView(Launcher launcher, View originalView,
- boolean hideOriginal, boolean useDrawableAsIs, float aspectRatio, Rect positionOut,
- FloatingIconView recycle) {
+ boolean hideOriginal, Rect positionOut, boolean isOpening, FloatingIconView recycle) {
+ if (recycle != null) {
+ recycle.recycle();
+ }
FloatingIconView view = recycle != null ? recycle : new FloatingIconView(launcher);
// Match the position of the original view.
@@ -363,9 +386,16 @@
// Get the drawable on the background thread
// Must be called after matchPositionOf so that we know what size to load.
if (originalView.getTag() instanceof ItemInfo) {
+ Runnable onIconLoaded = () -> {
+ // Delay swapping views until the icon is loaded to prevent a flash.
+ view.setVisibility(VISIBLE);
+ if (hideOriginal) {
+ originalView.setVisibility(INVISIBLE);
+ }
+ };
new Handler(LauncherModel.getWorkerLooper()).postAtFrontOfQueue(() -> {
- view.getIcon(launcher, originalView, (ItemInfo) originalView.getTag(),
- useDrawableAsIs, aspectRatio);
+ view.getIcon(launcher, originalView, (ItemInfo) originalView.getTag(), isOpening,
+ onIconLoaded);
});
}
@@ -374,18 +404,73 @@
view.setVisibility(INVISIBLE);
((ViewGroup) dragLayer.getParent()).getOverlay().add(view);
- view.mStartRunnable = () -> {
- view.setVisibility(VISIBLE);
- if (hideOriginal) {
- originalView.setVisibility(INVISIBLE);
- }
- };
- view.mEndRunnable = () -> {
- ((ViewGroup) dragLayer.getParent()).getOverlay().remove(view);
- if (hideOriginal) {
- originalView.setVisibility(VISIBLE);
- }
- };
+ if (hideOriginal) {
+ view.mEndRunnable = () -> {
+ AnimatorSet fade = new AnimatorSet();
+ fade.setDuration(200);
+ fade.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ originalView.setVisibility(VISIBLE);
+
+ if (originalView instanceof FolderIcon) {
+ FolderIcon folderIcon = (FolderIcon) originalView;
+ folderIcon.setBackgroundVisible(false);
+ folderIcon.getFolderName().setTextVisibility(false);
+ }
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ ((ViewGroup) dragLayer.getParent()).getOverlay().remove(view);
+
+ if (view.mRevealAnimator != null) {
+ view.mRevealAnimator.end();
+ }
+ }
+ });
+
+ if (originalView instanceof FolderIcon) {
+ FolderIcon folderIcon = (FolderIcon) originalView;
+ fade.play(folderIcon.getFolderName().createTextAlphaAnimator(true));
+ fade.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ folderIcon.setBackgroundVisible(true);
+ folderIcon.animateBgShadowAndStroke();
+ if (folderIcon.hasDot()) {
+ folderIcon.animateDotScale(0, 1f);
+ }
+ }
+ });
+ } else {
+ fade.play(ObjectAnimator.ofFloat(originalView, ALPHA, 0f, 1f));
+ }
+ fade.start();
+ // TODO: Do not run fade animation until we fix b/129421279.
+ fade.end();
+ };
+ }
return view;
}
+
+ private void recycle() {
+ setTranslationX(0);
+ setTranslationY(0);
+ setScaleX(1);
+ setScaleY(1);
+ setAlpha(1);
+ setBackground(null);
+ mEndRunnable = null;
+ mIsAdaptiveIcon = false;
+ mForeground = null;
+ mBackground = null;
+ mClipPath = null;
+ mFinalDrawableBounds.setEmpty();
+ mBgDrawableBounds.setEmpty();;
+ if (mRevealAnimator != null) {
+ mRevealAnimator.cancel();
+ }
+ mRevealAnimator = null;
+ }
}
diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java
index e259cfe..6a2f0ff 100644
--- a/src/com/android/launcher3/views/OptionsPopupView.java
+++ b/src/com/android/launcher3/views/OptionsPopupView.java
@@ -217,7 +217,7 @@
if (!TextUtils.isEmpty(pickerPackage)) {
intent.setPackage(pickerPackage);
}
- return launcher.startActivitySafely(v, intent, null);
+ return launcher.startActivitySafely(v, intent, null, null);
}
public static class OptionItem {
diff --git a/src/com/android/launcher3/widget/WidgetsRecyclerView.java b/src/com/android/launcher3/widget/WidgetsRecyclerView.java
index 641183a..c15557b 100644
--- a/src/com/android/launcher3/widget/WidgetsRecyclerView.java
+++ b/src/com/android/launcher3/widget/WidgetsRecyclerView.java
@@ -56,11 +56,6 @@
addOnItemTouchListener(this);
}
- public WidgetsRecyclerView(Context context, AttributeSet attrs, int defStyleAttr,
- int defStyleRes) {
- this(context, attrs, defStyleAttr);
- }
-
@Override
protected void onFinishInflate() {
super.onFinishInflate();
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/BackgroundAppState.java b/src_ui_overrides/com/android/launcher3/uioverrides/BackgroundAppState.java
deleted file mode 100644
index 9133b07..0000000
--- a/src_ui_overrides/com/android/launcher3/uioverrides/BackgroundAppState.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.uioverrides;
-
-/**
- * A dummy background app state
- */
-public class BackgroundAppState extends OverviewState {
-
- public BackgroundAppState(int id) {
- super(id);
- }
-}
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java b/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java
index 0d727fd..9939c25 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java
@@ -22,6 +22,7 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherStateManager.StateHandler;
+import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.util.TouchController;
import java.io.PrintWriter;
@@ -33,7 +34,9 @@
launcher.getDragController(), new AllAppsSwipeController(launcher)};
}
- public static void setOnTouchControllersChangedListener(Context context, Runnable listener) { }
+ public static Runnable enableLiveTouchControllerChanges(DragLayer dl) {
+ return null;
+ }
public static StateHandler[] getStateHandler(Launcher launcher) {
return new StateHandler[] {
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsState.java b/src_ui_overrides/com/android/launcher3/uioverrides/states/AllAppsState.java
similarity index 92%
rename from src_ui_overrides/com/android/launcher3/uioverrides/AllAppsState.java
rename to src_ui_overrides/com/android/launcher3/uioverrides/states/AllAppsState.java
index f7bb254..7006d77 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsState.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/states/AllAppsState.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.launcher3.uioverrides;
+package com.android.launcher3.uioverrides.states;
import static com.android.launcher3.LauncherAnimUtils.ALL_APPS_TRANSITION_MS;
import static com.android.launcher3.allapps.DiscoveryBounce.HOME_BOUNCE_SEEN;
@@ -66,9 +66,9 @@
}
@Override
- public float[] getWorkspaceScaleAndTranslation(Launcher launcher) {
- return new float[] { 1f, 0,
- -launcher.getAllAppsController().getShiftRange() * PARALLAX_COEFFICIENT};
+ public ScaleAndTranslation getWorkspaceScaleAndTranslation(Launcher launcher) {
+ return new ScaleAndTranslation(1f, 0,
+ -launcher.getAllAppsController().getShiftRange() * PARALLAX_COEFFICIENT);
}
@Override
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/OverviewState.java b/src_ui_overrides/com/android/launcher3/uioverrides/states/OverviewState.java
similarity index 74%
rename from src_ui_overrides/com/android/launcher3/uioverrides/OverviewState.java
rename to src_ui_overrides/com/android/launcher3/uioverrides/states/OverviewState.java
index 8def0d3..aeba788 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/OverviewState.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/states/OverviewState.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.launcher3.uioverrides;
+package com.android.launcher3.uioverrides.states;
import static com.android.launcher3.LauncherAnimUtils.OVERVIEW_TRANSITION_MS;
@@ -28,4 +28,16 @@
public OverviewState(int id) {
super(id, ContainerType.WORKSPACE, OVERVIEW_TRANSITION_MS, FLAG_DISABLE_RESTORE);
}
+
+ public static OverviewState newBackgroundState(int id) {
+ return new OverviewState(id);
+ }
+
+ public static OverviewState newPeekState(int id) {
+ return new OverviewState(id);
+ }
+
+ public static OverviewState newSwitchState(int id) {
+ return new OverviewState(id);
+ }
}
diff --git a/tests/Android.mk b/tests/Android.mk
index ca7395a..080c98b 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -30,7 +30,6 @@
LOCAL_STATIC_JAVA_LIBRARIES += libSharedSystemUI
LOCAL_SRC_FILES := $(call all-java-files-under, tapl) \
- ../quickstep/src/com/android/quickstep/SwipeUpSetting.java \
../src/com/android/launcher3/util/SecureSettingsObserver.java \
../src/com/android/launcher3/TestProtocol.java
endif
diff --git a/tests/src/com/android/launcher3/touch/SwipeDetectorTest.java b/tests/src/com/android/launcher3/touch/SwipeDetectorTest.java
index b600473..4ebf54c 100644
--- a/tests/src/com/android/launcher3/touch/SwipeDetectorTest.java
+++ b/tests/src/com/android/launcher3/touch/SwipeDetectorTest.java
@@ -15,9 +15,12 @@
*/
package com.android.launcher3.touch;
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.anyFloat;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
import android.util.Log;
import android.view.ViewConfiguration;
@@ -29,11 +32,9 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import static org.mockito.Matchers.anyBoolean;
-import static org.mockito.Matchers.anyFloat;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -63,7 +64,7 @@
doReturn(orgConfig.getScaledMaximumFlingVelocity()).when(mMockConfig)
.getScaledMaximumFlingVelocity();
- mDetector = new SwipeDetector(mMockConfig, mMockListener, SwipeDetector.VERTICAL);
+ mDetector = new SwipeDetector(mMockConfig, mMockListener, SwipeDetector.VERTICAL, false);
mDetector.setDetectableScrollConditions(SwipeDetector.DIRECTION_BOTH, false);
mTouchSlop = orgConfig.getScaledTouchSlop();
doReturn(mTouchSlop).when(mMockConfig).getScaledTouchSlop();
@@ -72,7 +73,19 @@
}
@Test
- public void testDragStart_vertical() {
+ public void testDragStart_verticalPositive() {
+ mDetector = new SwipeDetector(mMockConfig, mMockListener, SwipeDetector.VERTICAL, false);
+ mDetector.setDetectableScrollConditions(SwipeDetector.DIRECTION_POSITIVE, false);
+ mGenerator.put(0, 100, 100);
+ mGenerator.move(0, 100, 100 - mTouchSlop);
+ // TODO: actually calculate the following parameters and do exact value checks.
+ verify(mMockListener).onDragStart(anyBoolean());
+ }
+
+ @Test
+ public void testDragStart_verticalNegative() {
+ mDetector = new SwipeDetector(mMockConfig, mMockListener, SwipeDetector.VERTICAL, false);
+ mDetector.setDetectableScrollConditions(SwipeDetector.DIRECTION_NEGATIVE, false);
mGenerator.put(0, 100, 100);
mGenerator.move(0, 100, 100 + mTouchSlop);
// TODO: actually calculate the following parameters and do exact value checks.
@@ -88,9 +101,42 @@
}
@Test
- public void testDragStart_horizontal() {
- mDetector = new SwipeDetector(mMockConfig, mMockListener, SwipeDetector.HORIZONTAL);
- mDetector.setDetectableScrollConditions(SwipeDetector.DIRECTION_BOTH, false);
+ public void testDragStart_horizontalPositive() {
+ mDetector = new SwipeDetector(mMockConfig, mMockListener, SwipeDetector.HORIZONTAL, false);
+ mDetector.setDetectableScrollConditions(SwipeDetector.DIRECTION_POSITIVE, false);
+
+ mGenerator.put(0, 100, 100);
+ mGenerator.move(0, 100 + mTouchSlop, 100);
+ // TODO: actually calculate the following parameters and do exact value checks.
+ verify(mMockListener).onDragStart(anyBoolean());
+ }
+
+ @Test
+ public void testDragStart_horizontalNegative() {
+ mDetector = new SwipeDetector(mMockConfig, mMockListener, SwipeDetector.HORIZONTAL, false);
+ mDetector.setDetectableScrollConditions(SwipeDetector.DIRECTION_NEGATIVE, false);
+
+ mGenerator.put(0, 100, 100);
+ mGenerator.move(0, 100 - mTouchSlop, 100);
+ // TODO: actually calculate the following parameters and do exact value checks.
+ verify(mMockListener).onDragStart(anyBoolean());
+ }
+
+ @Test
+ public void testDragStart_horizontalRtlPositive() {
+ mDetector = new SwipeDetector(mMockConfig, mMockListener, SwipeDetector.HORIZONTAL, true);
+ mDetector.setDetectableScrollConditions(SwipeDetector.DIRECTION_POSITIVE, false);
+
+ mGenerator.put(0, 100, 100);
+ mGenerator.move(0, 100 - mTouchSlop, 100);
+ // TODO: actually calculate the following parameters and do exact value checks.
+ verify(mMockListener).onDragStart(anyBoolean());
+ }
+
+ @Test
+ public void testDragStart_horizontalRtlNegative() {
+ mDetector = new SwipeDetector(mMockConfig, mMockListener, SwipeDetector.HORIZONTAL, true);
+ mDetector.setDetectableScrollConditions(SwipeDetector.DIRECTION_NEGATIVE, false);
mGenerator.put(0, 100, 100);
mGenerator.move(0, 100 + mTouchSlop, 100);
diff --git a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
index 6f2f280..d29d29c 100644
--- a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
+++ b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
@@ -34,6 +34,7 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
+import com.android.launcher3.TestProtocol;
import com.android.launcher3.popup.ArrowPopup;
import com.android.launcher3.tapl.AllApps;
import com.android.launcher3.tapl.AppIcon;
@@ -206,8 +207,8 @@
// Test that ensureWorkspaceIsScrollable adds a page by dragging an icon there.
executeOnLauncher(launcher -> assertFalse("Initial workspace state is scrollable",
isWorkspaceScrollable(launcher)));
- assertNull("Messages app was found on empty workspace",
- workspace.tryGetWorkspaceAppIcon("Messages"));
+ assertNull("Play Store app was found on empty workspace",
+ workspace.tryGetWorkspaceAppIcon("Play Store"));
workspace.ensureWorkspaceIsScrollable();
@@ -217,8 +218,8 @@
executeOnLauncher(
launcher -> assertTrue("ensureScrollable didn't make workspace scrollable",
isWorkspaceScrollable(launcher)));
- assertNotNull("ensureScrollable didn't add Messages app",
- workspace.tryGetWorkspaceAppIcon("Messages"));
+ assertNotNull("ensureScrollable didn't add Play Store app",
+ workspace.tryGetWorkspaceAppIcon("Play Store"));
// Test flinging workspace.
workspace.flingBackward();
@@ -234,10 +235,10 @@
assertTrue("Launcher internal state is not Home", isInState(LauncherState.NORMAL));
// Test starting a workspace app.
- final AppIcon app = workspace.tryGetWorkspaceAppIcon("Messages");
- assertNotNull("No Messages app in workspace", app);
+ final AppIcon app = workspace.tryGetWorkspaceAppIcon("Play Store");
+ assertNotNull("No Play Store app in workspace", app);
assertNotNull("AppIcon.launch returned null",
- app.launch(resolveSystemApp(Intent.CATEGORY_APP_MESSAGING)));
+ app.launch(resolveSystemApp(Intent.CATEGORY_APP_MARKET)));
executeOnLauncher(launcher -> assertTrue(
"Launcher activity is the top activity; expecting another activity to be the top "
+ "one",
@@ -327,18 +328,23 @@
@Test
@PortraitLandscape
public void testDragAppIcon() throws Throwable {
- LauncherActivityInfo settingsApp = getSettingsApp();
+ try {
+ TestProtocol.sDebugTracing = true;
+ LauncherActivityInfo settingsApp = getSettingsApp();
- final String appName = settingsApp.getLabel().toString();
- // 1. Open all apps and wait for load complete.
- // 2. Drag icon to homescreen.
- // 3. Verify that the icon works on homescreen.
- mLauncher.getWorkspace().
- switchToAllApps().
- getAppIcon(appName).
- dragToWorkspace().
- getWorkspaceAppIcon(appName).
- launch(settingsApp.getComponentName().getPackageName());
+ final String appName = settingsApp.getLabel().toString();
+ // 1. Open all apps and wait for load complete.
+ // 2. Drag icon to homescreen.
+ // 3. Verify that the icon works on homescreen.
+ mLauncher.getWorkspace().
+ switchToAllApps().
+ getAppIcon(appName).
+ dragToWorkspace().
+ getWorkspaceAppIcon(appName).
+ launch(settingsApp.getComponentName().getPackageName());
+ } finally {
+ TestProtocol.sDebugTracing = false;
+ }
}
@Test
diff --git a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
index fbb4f51..68b16d6 100644
--- a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
@@ -145,7 +145,7 @@
assertFalse(mDevice.findObject(new UiSelector().description(info.label)).exists());
}
- @Test
+ @Test @Ignore
public void testPendingWidget_autoRestored() {
// A non-restored widget with no config screen gets restored automatically.
LauncherAppWidgetProviderInfo info = TestViewHelpers.findWidgetProvider(this, false);
diff --git a/tests/tapl/com/android/launcher3/tapl/AllApps.java b/tests/tapl/com/android/launcher3/tapl/AllApps.java
index 122151e..98fb07f 100644
--- a/tests/tapl/com/android/launcher3/tapl/AllApps.java
+++ b/tests/tapl/com/android/launcher3/tapl/AllApps.java
@@ -29,7 +29,7 @@
public class AllApps extends LauncherInstrumentation.VisibleContainer {
private static final int MAX_SCROLL_ATTEMPTS = 40;
private static final int MIN_INTERACT_SIZE = 100;
- private static final int FLING_SPEED = 3000;
+ private static final int FLING_SPEED = LauncherInstrumentation.needSlowGestures() ? 1000 : 3000;
private final int mHeight;
@@ -60,47 +60,61 @@
*/
@NonNull
public AppIcon getAppIcon(String appName) {
- final UiObject2 allAppsContainer = verifyActiveContainer();
- final BySelector appIconSelector = AppIcon.getAppIconSelector(appName, mLauncher);
- if (!hasClickableIcon(allAppsContainer, appIconSelector)) {
- scrollBackToBeginning();
- int attempts = 0;
- while (!hasClickableIcon(allAppsContainer, appIconSelector) &&
- allAppsContainer.scroll(Direction.DOWN, 0.8f)) {
- LauncherInstrumentation.assertTrue(
- "Exceeded max scroll attempts: " + MAX_SCROLL_ATTEMPTS,
- ++attempts <= MAX_SCROLL_ATTEMPTS);
+ try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+ "want to get app icon on all apps")) {
+ final UiObject2 allAppsContainer = verifyActiveContainer();
+ final UiObject2 navBar = mLauncher.waitForSystemUiObject("navigation_bar_frame");
+ allAppsContainer.setGestureMargins(0, 0, 0, navBar.getVisibleBounds().height() + 1);
+ final BySelector appIconSelector = AppIcon.getAppIconSelector(appName, mLauncher);
+ if (!hasClickableIcon(allAppsContainer, appIconSelector)) {
+ scrollBackToBeginning();
+ int attempts = 0;
+ try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("scrolled")) {
+ while (!hasClickableIcon(allAppsContainer, appIconSelector) &&
+ allAppsContainer.scroll(Direction.DOWN, 0.8f)) {
+ mLauncher.assertTrue(
+ "Exceeded max scroll attempts: " + MAX_SCROLL_ATTEMPTS,
+ ++attempts <= MAX_SCROLL_ATTEMPTS);
+ verifyActiveContainer();
+ }
+ }
verifyActiveContainer();
}
- }
- verifyActiveContainer();
- final UiObject2 appIcon = mLauncher.getObjectInContainer(allAppsContainer, appIconSelector);
- ensureIconVisible(appIcon, allAppsContainer);
- return new AppIcon(mLauncher, appIcon);
+ final UiObject2 appIcon = mLauncher.getObjectInContainer(allAppsContainer,
+ appIconSelector);
+ ensureIconVisible(appIcon, allAppsContainer);
+ return new AppIcon(mLauncher, appIcon);
+ }
}
private void scrollBackToBeginning() {
- final UiObject2 allAppsContainer = verifyActiveContainer();
- final UiObject2 searchBox =
- mLauncher.waitForObjectInContainer(allAppsContainer, "search_container_all_apps");
+ try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+ "want to scroll back in all apps")) {
+ final UiObject2 allAppsContainer = verifyActiveContainer();
+ final UiObject2 searchBox =
+ mLauncher.waitForObjectInContainer(allAppsContainer,
+ "search_container_all_apps");
- int attempts = 0;
- allAppsContainer.setGestureMargins(0, searchBox.getVisibleBounds().bottom + 1, 0, 5);
+ int attempts = 0;
+ allAppsContainer.setGestureMargins(0, searchBox.getVisibleBounds().bottom + 1, 0, 5);
- for (int scroll = getScroll(allAppsContainer);
- scroll != 0;
- scroll = getScroll(allAppsContainer)) {
- LauncherInstrumentation.assertTrue("Negative scroll position", scroll > 0);
+ for (int scroll = getScroll(allAppsContainer);
+ scroll != 0;
+ scroll = getScroll(allAppsContainer)) {
+ mLauncher.assertTrue("Negative scroll position", scroll > 0);
- LauncherInstrumentation.assertTrue(
- "Exceeded max scroll attempts: " + MAX_SCROLL_ATTEMPTS,
- ++attempts <= MAX_SCROLL_ATTEMPTS);
+ mLauncher.assertTrue(
+ "Exceeded max scroll attempts: " + MAX_SCROLL_ATTEMPTS,
+ ++attempts <= MAX_SCROLL_ATTEMPTS);
- allAppsContainer.scroll(Direction.UP, 1);
+ allAppsContainer.scroll(Direction.UP, 1);
+ }
+
+ try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("scrolled up")) {
+ verifyActiveContainer();
+ }
}
-
- verifyActiveContainer();
}
private int getScroll(UiObject2 allAppsContainer) {
@@ -115,8 +129,11 @@
// to reveal the app icon to have the MIN_INTERACT_SIZE
final float pct = Math.max(((float) (MIN_INTERACT_SIZE - appHeight)) / mHeight, 0.2f);
allAppsContainer.scroll(Direction.DOWN, pct);
- mLauncher.waitForIdle();
- verifyActiveContainer();
+ try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+ "scrolled an icon in all apps to make it visible - and then")) {
+ mLauncher.waitForIdle();
+ verifyActiveContainer();
+ }
}
}
@@ -124,21 +141,29 @@
* Flings forward (down) and waits the fling's end.
*/
public void flingForward() {
- final UiObject2 allAppsContainer = verifyActiveContainer();
- // Start the gesture in the center to avoid starting at elements near the top.
- allAppsContainer.setGestureMargins(0, 0, 0, mHeight / 2);
- allAppsContainer.fling(Direction.DOWN, (int) (FLING_SPEED * mLauncher.getDisplayDensity()));
- verifyActiveContainer();
+ try (LauncherInstrumentation.Closable c =
+ mLauncher.addContextLayer("want to fling forward in all apps")) {
+ final UiObject2 allAppsContainer = verifyActiveContainer();
+ // Start the gesture in the center to avoid starting at elements near the top.
+ allAppsContainer.setGestureMargins(0, 0, 0, mHeight / 2);
+ allAppsContainer.fling(Direction.DOWN,
+ (int) (FLING_SPEED * mLauncher.getDisplayDensity()));
+ verifyActiveContainer();
+ }
}
/**
* Flings backward (up) and waits the fling's end.
*/
public void flingBackward() {
- final UiObject2 allAppsContainer = verifyActiveContainer();
- // Start the gesture in the center, for symmetry with forward.
- allAppsContainer.setGestureMargins(0, mHeight / 2, 0, 0);
- allAppsContainer.fling(Direction.UP, (int) (FLING_SPEED * mLauncher.getDisplayDensity()));
- verifyActiveContainer();
+ try (LauncherInstrumentation.Closable c =
+ mLauncher.addContextLayer("want to fling backward in all apps")) {
+ final UiObject2 allAppsContainer = verifyActiveContainer();
+ // Start the gesture in the center, for symmetry with forward.
+ allAppsContainer.setGestureMargins(0, mHeight / 2, 0, 0);
+ allAppsContainer.fling(Direction.UP,
+ (int) (FLING_SPEED * mLauncher.getDisplayDensity()));
+ verifyActiveContainer();
+ }
}
}
diff --git a/tests/tapl/com/android/launcher3/tapl/AllAppsFromOverview.java b/tests/tapl/com/android/launcher3/tapl/AllAppsFromOverview.java
index dcc51b5..c3b671b 100644
--- a/tests/tapl/com/android/launcher3/tapl/AllAppsFromOverview.java
+++ b/tests/tapl/com/android/launcher3/tapl/AllAppsFromOverview.java
@@ -42,20 +42,24 @@
*/
@NonNull
public Overview switchBackToOverview() {
- final UiObject2 allAppsContainer = verifyActiveContainer();
- // Swipe from the search box to the bottom.
- final UiObject2 qsb = mLauncher.waitForObjectInContainer(
- allAppsContainer, "search_container_all_apps");
- final Point start = qsb.getVisibleCenter();
- final int swipeHeight = mLauncher.getTestInfo(
- TestProtocol.REQUEST_ALL_APPS_TO_OVERVIEW_SWIPE_HEIGHT).
- getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
+ try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+ "want to switch back from all apps to overview")) {
+ final UiObject2 allAppsContainer = verifyActiveContainer();
+ // Swipe from the search box to the bottom.
+ final UiObject2 qsb = mLauncher.waitForObjectInContainer(
+ allAppsContainer, "search_container_all_apps");
+ final Point start = qsb.getVisibleCenter();
+ final int swipeHeight = mLauncher.getTestInfo(
+ TestProtocol.REQUEST_ALL_APPS_TO_OVERVIEW_SWIPE_HEIGHT).
+ getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
- final int endY = start.y + swipeHeight + mLauncher.getTouchSlop();
- LauncherInstrumentation.log("AllAppsFromOverview.switchBackToOverview before swipe");
- mLauncher.swipe(start.x, start.y, start.x, endY, OVERVIEW_STATE_ORDINAL);
+ final int endY = start.y + swipeHeight + mLauncher.getTouchSlop();
+ LauncherInstrumentation.log("AllAppsFromOverview.switchBackToOverview before swipe");
+ mLauncher.swipe(start.x, start.y, start.x, endY, OVERVIEW_STATE_ORDINAL);
- return new Overview(mLauncher);
+ try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("swiped down")) {
+ return new Overview(mLauncher);
+ }
+ }
}
-
}
diff --git a/tests/tapl/com/android/launcher3/tapl/Background.java b/tests/tapl/com/android/launcher3/tapl/Background.java
index ef509ed..358d5e9 100644
--- a/tests/tapl/com/android/launcher3/tapl/Background.java
+++ b/tests/tapl/com/android/launcher3/tapl/Background.java
@@ -20,8 +20,6 @@
import static com.android.launcher3.tapl.LauncherInstrumentation.WAIT_TIME_MS;
import static com.android.launcher3.tapl.TestHelpers.getOverviewPackageName;
-import static org.junit.Assert.assertTrue;
-
import android.graphics.Point;
import android.os.SystemClock;
import android.view.MotionEvent;
@@ -57,11 +55,14 @@
*/
@NonNull
public BaseOverview switchToOverview() {
- verifyActiveContainer();
- goToOverviewUnchecked(BACKGROUND_APP_STATE_ORDINAL);
- assertTrue("Overview not visible", mLauncher.getDevice().wait(
- Until.hasObject(By.pkg(getOverviewPackageName())), WAIT_TIME_MS));
- return new BaseOverview(mLauncher);
+ try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+ "want to switch from background to overview")) {
+ verifyActiveContainer();
+ goToOverviewUnchecked(BACKGROUND_APP_STATE_ORDINAL);
+ mLauncher.assertTrue("Overview not visible", mLauncher.getDevice().wait(
+ Until.hasObject(By.pkg(getOverviewPackageName())), WAIT_TIME_MS));
+ return new BaseOverview(mLauncher);
+ }
}
protected void goToOverviewUnchecked(int expectedState) {
diff --git a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
index 234c3bf..4205188 100644
--- a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
+++ b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
@@ -44,42 +44,54 @@
* Flings forward (left) and waits the fling's end.
*/
public void flingForward() {
- LauncherInstrumentation.log("Overview.flingForward before fling");
- final UiObject2 overview = verifyActiveContainer();
- final int margin = (int) (50 * mLauncher.getDisplayDensity()) + 1;
- overview.setGestureMargins(margin, 0, 0, 0);
- overview.fling(Direction.LEFT, (int) (FLING_SPEED * mLauncher.getDisplayDensity()));
- mLauncher.waitForIdle();
- verifyActiveContainer();
+ try (LauncherInstrumentation.Closable c =
+ mLauncher.addContextLayer("want to fling forward in overview")) {
+ LauncherInstrumentation.log("Overview.flingForward before fling");
+ final UiObject2 overview = verifyActiveContainer();
+ final int margin = (int) (50 * mLauncher.getDisplayDensity()) + 1;
+ overview.setGestureMargins(margin, 0, 0, 0);
+ overview.fling(Direction.LEFT, (int) (FLING_SPEED * mLauncher.getDisplayDensity()));
+ mLauncher.waitForIdle();
+ verifyActiveContainer();
+ }
}
/**
* Dismissed all tasks by scrolling to Clear-all button and pressing it.
*/
public Workspace dismissAllTasks() {
- final BySelector clearAllSelector = mLauncher.getLauncherObjectSelector("clear_all");
- for (int i = 0;
- i < FLINGS_FOR_DISMISS_LIMIT
- && !verifyActiveContainer().hasObject(clearAllSelector);
- ++i) {
- flingForward();
- }
+ try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+ "dismissing all tasks")) {
+ final BySelector clearAllSelector = mLauncher.getLauncherObjectSelector("clear_all");
+ for (int i = 0;
+ i < FLINGS_FOR_DISMISS_LIMIT
+ && !verifyActiveContainer().hasObject(clearAllSelector);
+ ++i) {
+ flingForward();
+ }
- mLauncher.getObjectInContainer(verifyActiveContainer(), clearAllSelector).click();
- return new Workspace(mLauncher);
+ mLauncher.getObjectInContainer(verifyActiveContainer(), clearAllSelector).click();
+ try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
+ "dismissed all tasks")) {
+ return new Workspace(mLauncher);
+ }
+ }
}
/**
* Flings backward (right) and waits the fling's end.
*/
public void flingBackward() {
- LauncherInstrumentation.log("Overview.flingBackward before fling");
- final UiObject2 overview = verifyActiveContainer();
- final int margin = (int) (50 * mLauncher.getDisplayDensity()) + 1;
- overview.setGestureMargins(0, 0, margin, 0);
- overview.fling(Direction.RIGHT, (int) (FLING_SPEED * mLauncher.getDisplayDensity()));
- mLauncher.waitForIdle();
- verifyActiveContainer();
+ try (LauncherInstrumentation.Closable c =
+ mLauncher.addContextLayer("want to fling backward in overview")) {
+ LauncherInstrumentation.log("Overview.flingBackward before fling");
+ final UiObject2 overview = verifyActiveContainer();
+ final int margin = (int) (50 * mLauncher.getDisplayDensity()) + 1;
+ overview.setGestureMargins(0, 0, margin, 0);
+ overview.fling(Direction.RIGHT, (int) (FLING_SPEED * mLauncher.getDisplayDensity()));
+ mLauncher.waitForIdle();
+ verifyActiveContainer();
+ }
}
/**
@@ -89,18 +101,21 @@
*/
@NonNull
public OverviewTask getCurrentTask() {
- verifyActiveContainer();
- final List<UiObject2> taskViews = mLauncher.getDevice().findObjects(
- mLauncher.getLauncherObjectSelector("snapshot"));
- LauncherInstrumentation.assertNotEquals("Unable to find a task", 0, taskViews.size());
+ try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+ "want to get current task")) {
+ verifyActiveContainer();
+ final List<UiObject2> taskViews = mLauncher.getDevice().findObjects(
+ mLauncher.getLauncherObjectSelector("snapshot"));
+ mLauncher.assertNotEquals("Unable to find a task", 0, taskViews.size());
- // taskViews contains up to 3 task views: the 'main' (having the widest visible
- // part) one in the center, and parts of its right and left siblings. Find the
- // main task view by its width.
- final UiObject2 widestTask = Collections.max(taskViews,
- (t1, t2) -> Integer.compare(t1.getVisibleBounds().width(),
- t2.getVisibleBounds().width()));
+ // taskViews contains up to 3 task views: the 'main' (having the widest visible
+ // part) one in the center, and parts of its right and left siblings. Find the
+ // main task view by its width.
+ final UiObject2 widestTask = Collections.max(taskViews,
+ (t1, t2) -> Integer.compare(t1.getVisibleBounds().width(),
+ t2.getVisibleBounds().width()));
- return new OverviewTask(mLauncher, widestTask, this);
+ return new OverviewTask(mLauncher, widestTask, this);
+ }
}
}
\ No newline at end of file
diff --git a/tests/tapl/com/android/launcher3/tapl/Home.java b/tests/tapl/com/android/launcher3/tapl/Home.java
index f8bd85a..20c116c 100644
--- a/tests/tapl/com/android/launcher3/tapl/Home.java
+++ b/tests/tapl/com/android/launcher3/tapl/Home.java
@@ -48,8 +48,14 @@
@NonNull
@Override
public Overview switchToOverview() {
- verifyActiveContainer();
- goToOverviewUnchecked(OVERVIEW_STATE_ORDINAL);
- return new Overview(mLauncher);
+ try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+ "want to switch from home to overview")) {
+ verifyActiveContainer();
+ goToOverviewUnchecked(OVERVIEW_STATE_ORDINAL);
+ try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
+ "performed the switch action")) {
+ return new Overview(mLauncher);
+ }
+ }
}
}
\ No newline at end of file
diff --git a/tests/tapl/com/android/launcher3/tapl/Launchable.java b/tests/tapl/com/android/launcher3/tapl/Launchable.java
index 481281a..7a2b7af 100644
--- a/tests/tapl/com/android/launcher3/tapl/Launchable.java
+++ b/tests/tapl/com/android/launcher3/tapl/Launchable.java
@@ -59,10 +59,10 @@
private Background launch(String errorMessage, BySelector selector) {
LauncherInstrumentation.log("Launchable.launch before click " +
mObject.getVisibleCenter());
- LauncherInstrumentation.assertTrue(
+ mLauncher.assertTrue(
"Launching an app didn't open a new window: " + mObject.getText(),
mObject.clickAndWait(Until.newWindow(), LauncherInstrumentation.WAIT_TIME_MS));
- LauncherInstrumentation.assertTrue(
+ mLauncher.assertTrue(
"App didn't start: " + errorMessage,
mLauncher.getDevice().wait(Until.hasObject(selector),
LauncherInstrumentation.WAIT_TIME_MS));
@@ -79,6 +79,9 @@
this,
new Point(device.getDisplayWidth() / 2, device.getDisplayHeight() / 2),
DRAG_SPEED);
- return new Workspace(mLauncher);
+ try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+ "dragged launchable to workspace")) {
+ return new Workspace(mLauncher);
+ }
}
}
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 7e8c544..a4b4171 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -16,26 +16,26 @@
package com.android.launcher3.tapl;
-import static com.android.launcher3.TestProtocol.BACKGROUND_APP_STATE_ORDINAL;
-
import android.app.ActivityManager;
import android.app.Instrumentation;
import android.app.UiAutomation;
import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.content.res.Resources;
import android.graphics.Point;
import android.net.Uri;
+import android.os.Build;
import android.os.Bundle;
import android.os.Parcelable;
import android.os.SystemClock;
+import android.text.TextUtils;
import android.util.Log;
import android.view.InputDevice;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.ViewConfiguration;
import android.view.accessibility.AccessibilityEvent;
-
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.test.uiautomator.By;
@@ -44,16 +44,15 @@
import androidx.test.uiautomator.UiDevice;
import androidx.test.uiautomator.UiObject2;
import androidx.test.uiautomator.Until;
-
import com.android.launcher3.TestProtocol;
import com.android.systemui.shared.system.QuickStepContract;
-
-import org.junit.Assert;
-
import java.io.IOException;
import java.lang.ref.WeakReference;
+import java.util.Deque;
+import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.TimeoutException;
+import org.junit.Assert;
/**
* The main tapl object. The only object that can be explicitly constructed by the using code. It
@@ -62,6 +61,8 @@
public final class LauncherInstrumentation {
private static final String TAG = "Tapl";
+ private static final String NAV_BAR_INTERACTION_MODE_RES_NAME =
+ "config_navBarInteractionMode";
private static final int ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME = 20;
// Types for launcher containers that the user is interacting with. "Background" is a
@@ -89,11 +90,16 @@
* @return UI object for the container.
*/
final UiObject2 verifyActiveContainer() {
- assertTrue("Attempt to use a stale container", this == sActiveContainer.get());
+ mLauncher.assertTrue("Attempt to use a stale container",
+ this == sActiveContainer.get());
return mLauncher.verifyContainerType(getContainerType());
}
}
+ interface Closable extends AutoCloseable {
+ void close();
+ }
+
private static final String WORKSPACE_RES_ID = "workspace";
private static final String APPS_RES_ID = "apps_view";
private static final String OVERVIEW_RES_ID = "overview_panel";
@@ -107,6 +113,7 @@
private final Instrumentation mInstrumentation;
private int mExpectedRotation = Surface.ROTATION_0;
private final Uri mTestProviderUri;
+ private final Deque<String> mDiagnosticContext = new LinkedList<>();
/**
* Constructs the root of TAPL hierarchy. You get all other objects from it.
@@ -157,50 +164,72 @@
}
public NavigationModel getNavigationModel() {
- return isSwipeUpEnabled() ? NavigationModel.TWO_BUTTON : NavigationModel.THREE_BUTTON;
- }
-
- private boolean isSwipeUpEnabled() {
final Context baseContext = mInstrumentation.getTargetContext();
try {
// Workaround, use constructed context because both the instrumentation context and the
// app context are not constructed with resources that take overlays into account
- Context ctx = baseContext.createPackageContext(getLauncherPackageName(), 0);
- return !QuickStepContract.isLegacyMode(ctx);
+ final Context ctx = baseContext.createPackageContext("android", 0);
+ if (isGesturalMode(ctx)) {
+ return NavigationModel.ZERO_BUTTON;
+ } else if (isSwipeUpMode(ctx)) {
+ return NavigationModel.TWO_BUTTON;
+ } else if (isLegacyMode(ctx)) {
+ return NavigationModel.THREE_BUTTON;
+ } else {
+ fail("Can't detect navigation mode");
+ }
} catch (PackageManager.NameNotFoundException e) {
- return false;
+ fail(e.toString());
}
+ return NavigationModel.THREE_BUTTON;
+ }
+
+ static boolean needSlowGestures() {
+ return Build.MODEL.contains("Cuttlefish");
}
static void log(String message) {
Log.d(TAG, message);
}
- private static void fail(String message) {
- Assert.fail("http://go/tapl : " + message);
+ Closable addContextLayer(String piece) {
+ mDiagnosticContext.addLast(piece);
+ return () -> mDiagnosticContext.removeLast();
}
- static void assertTrue(String message, boolean condition) {
+ private void fail(String message) {
+ final String ctxt = mDiagnosticContext.isEmpty() ? "" : String.join(", ",
+ mDiagnosticContext) + "; ";
+ Assert.fail("http://go/tapl : " + ctxt + message);
+ }
+
+ void assertTrue(String message, boolean condition) {
if (!condition) {
fail(message);
}
}
- static void assertNotNull(String message, Object object) {
+ void assertNotNull(String message, Object object) {
assertTrue(message, object != null);
}
- static private void failEquals(String message, Object actual) {
+ private void failEquals(String message, Object actual) {
fail(message + ". " + "Actual: " + actual);
}
- static private void assertEquals(String message, int expected, int actual) {
+ private void assertEquals(String message, int expected, int actual) {
if (expected != actual) {
fail(message + " expected: " + expected + " but was: " + actual);
}
}
- static void assertNotEquals(String message, int unexpected, int actual) {
+ private void assertEquals(String message, String expected, String actual) {
+ if (!TextUtils.equals(expected, actual)) {
+ fail(message + " expected: '" + expected + "' but was: '" + actual + "'");
+ }
+ }
+
+ void assertNotEquals(String message, int unexpected, int actual) {
if (unexpected == actual) {
failEquals(message, actual);
}
@@ -213,54 +242,61 @@
private UiObject2 verifyContainerType(ContainerType containerType) {
assertEquals("Unexpected display rotation",
mExpectedRotation, mDevice.getDisplayRotation());
- assertTrue("Presence of recents button doesn't match isSwipeUpEnabled()",
- isSwipeUpEnabled() ==
- (mDevice.findObject(By.res(SYSTEMUI_PACKAGE, "recent_apps")) == null));
+ final NavigationModel navigationModel = getNavigationModel();
+ assertTrue("Presence of recents button doesn't match the interaction mode",
+ (navigationModel == NavigationModel.THREE_BUTTON) ==
+ mDevice.hasObject(By.res(SYSTEMUI_PACKAGE, "recent_apps")));
+ assertTrue("Presence of home button doesn't match the interaction mode",
+ (navigationModel != NavigationModel.ZERO_BUTTON) ==
+ mDevice.hasObject(By.res(SYSTEMUI_PACKAGE, "home")));
log("verifyContainerType: " + containerType);
- switch (containerType) {
- case WORKSPACE: {
- waitForLauncherObject(APPS_RES_ID);
- waitUntilGone(OVERVIEW_RES_ID);
- waitUntilGone(WIDGETS_RES_ID);
- return waitForLauncherObject(WORKSPACE_RES_ID);
- }
- case WIDGETS: {
- waitUntilGone(WORKSPACE_RES_ID);
- waitUntilGone(APPS_RES_ID);
- waitUntilGone(OVERVIEW_RES_ID);
- return waitForLauncherObject(WIDGETS_RES_ID);
- }
- case ALL_APPS: {
- waitUntilGone(WORKSPACE_RES_ID);
- waitUntilGone(OVERVIEW_RES_ID);
- waitUntilGone(WIDGETS_RES_ID);
- return waitForLauncherObject(APPS_RES_ID);
- }
- case OVERVIEW: {
- if (mDevice.isNaturalOrientation()) {
+ try (Closable c = addContextLayer(
+ "but the current state is not " + containerType.name())) {
+ switch (containerType) {
+ case WORKSPACE: {
waitForLauncherObject(APPS_RES_ID);
- } else {
- waitUntilGone(APPS_RES_ID);
+ waitUntilGone(OVERVIEW_RES_ID);
+ waitUntilGone(WIDGETS_RES_ID);
+ return waitForLauncherObject(WORKSPACE_RES_ID);
}
- // Fall through
- }
- case BASE_OVERVIEW: {
- waitUntilGone(WORKSPACE_RES_ID);
- waitUntilGone(WIDGETS_RES_ID);
+ case WIDGETS: {
+ waitUntilGone(WORKSPACE_RES_ID);
+ waitUntilGone(APPS_RES_ID);
+ waitUntilGone(OVERVIEW_RES_ID);
+ return waitForLauncherObject(WIDGETS_RES_ID);
+ }
+ case ALL_APPS: {
+ waitUntilGone(WORKSPACE_RES_ID);
+ waitUntilGone(OVERVIEW_RES_ID);
+ waitUntilGone(WIDGETS_RES_ID);
+ return waitForLauncherObject(APPS_RES_ID);
+ }
+ case OVERVIEW: {
+ if (mDevice.isNaturalOrientation()) {
+ waitForLauncherObject(APPS_RES_ID);
+ } else {
+ waitUntilGone(APPS_RES_ID);
+ }
+ // Fall through
+ }
+ case BASE_OVERVIEW: {
+ waitUntilGone(WORKSPACE_RES_ID);
+ waitUntilGone(WIDGETS_RES_ID);
- return waitForLauncherObject(OVERVIEW_RES_ID);
+ return waitForLauncherObject(OVERVIEW_RES_ID);
+ }
+ case BACKGROUND: {
+ waitUntilGone(WORKSPACE_RES_ID);
+ waitUntilGone(APPS_RES_ID);
+ waitUntilGone(OVERVIEW_RES_ID);
+ waitUntilGone(WIDGETS_RES_ID);
+ return null;
+ }
+ default:
+ fail("Invalid state: " + containerType);
+ return null;
}
- case BACKGROUND: {
- waitUntilGone(WORKSPACE_RES_ID);
- waitUntilGone(APPS_RES_ID);
- waitUntilGone(OVERVIEW_RES_ID);
- waitUntilGone(WIDGETS_RES_ID);
- return null;
- }
- default:
- fail("Invalid state: " + containerType);
- return null;
}
}
@@ -298,30 +334,27 @@
// 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;
if (getNavigationModel() == NavigationModel.ZERO_BUTTON) {
if (hasLauncherObject(WORKSPACE_RES_ID)) {
- log("0-button pressHome: already in workspace");
+ log(action = "0-button: already in workspace");
} else if (hasLauncherObject(OVERVIEW_RES_ID)) {
- log("0-button pressHome: overview");
+ log(action = "0-button: from overview");
mDevice.pressHome();
} else if (hasLauncherObject(WIDGETS_RES_ID)) {
- log("0-button pressHome: widgets");
+ log(action = "0-button: from widgets");
mDevice.pressHome();
} else if (hasLauncherObject(APPS_RES_ID)) {
- log("0-button pressHome: all apps");
+ log(action = "0-button: from all apps");
mDevice.pressHome();
} else {
- log("0-button pressHome: another app");
+ log(action = "0-button: from another app");
assertTrue("Launcher is visible, don't know how to go home",
!mDevice.hasObject(By.pkg(getLauncherPackageName())));
- final UiObject2 navBar = waitForSystemUiObject("navigation_bar_frame");
-
- swipe(
- navBar.getVisibleBounds().centerX(), navBar.getVisibleBounds().centerY(),
- navBar.getVisibleBounds().centerX(), 0,
- BACKGROUND_APP_STATE_ORDINAL, ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME);
+ mDevice.pressHome();
}
} else {
+ log(action = "clicking home button");
executeAndWaitForEvent(
() -> {
log("LauncherInstrumentation.pressHome before clicking");
@@ -341,7 +374,10 @@
"Pressing Home didn't produce any events");
mDevice.waitForIdle();
}
- return getWorkspace();
+ try (LauncherInstrumentation.Closable c = addContextLayer(
+ "performed action to switch to Home - " + action)) {
+ return getWorkspace();
+ }
}
/**
@@ -352,7 +388,9 @@
*/
@NonNull
public Workspace getWorkspace() {
- return new Workspace(this);
+ try (LauncherInstrumentation.Closable c = addContextLayer("want to get workspace object")) {
+ return new Workspace(this);
+ }
}
/**
@@ -374,7 +412,9 @@
*/
@NonNull
public Widgets getAllWidgets() {
- return new Widgets(this);
+ try (LauncherInstrumentation.Closable c = addContextLayer("want to get widgets")) {
+ return new Widgets(this);
+ }
}
/**
@@ -385,7 +425,9 @@
*/
@NonNull
public Overview getOverview() {
- return new Overview(this);
+ try (LauncherInstrumentation.Closable c = addContextLayer("want to get overview")) {
+ return new Overview(this);
+ }
}
/**
@@ -409,7 +451,9 @@
*/
@NonNull
public AllApps getAllApps() {
- return new AllApps(this);
+ try (LauncherInstrumentation.Closable c = addContextLayer("want to get all apps object")) {
+ return new AllApps(this);
+ }
}
/**
@@ -422,7 +466,9 @@
*/
@NonNull
public AllAppsFromOverview getAllAppsFromOverview() {
- return new AllAppsFromOverview(this);
+ try (LauncherInstrumentation.Closable c = addContextLayer("want to get all apps object")) {
+ return new AllAppsFromOverview(this);
+ }
}
void waitUntilGone(String resId) {
@@ -497,8 +543,9 @@
event -> TestProtocol.SWITCHED_TO_STATE_MESSAGE.equals(event.getClassName()),
"Swipe failed to receive an event for the swipe end: " + startX + ", " + startY
+ ", " + endX + ", " + endY);
- assertEquals("Swipe switched launcher to a wrong state",
- expectedState, parcel.getInt(TestProtocol.STATE_FIELD));
+ assertEquals("Swipe switched launcher to a wrong state;",
+ TestProtocol.stateOrdinalToString(expectedState),
+ TestProtocol.stateOrdinalToString(parcel.getInt(TestProtocol.STATE_FIELD)));
}
void waitForIdle() {
@@ -553,6 +600,33 @@
}
}
+ public static boolean isGesturalMode(Context context) {
+ return QuickStepContract.isGesturalMode(
+ getSystemIntegerRes(context, NAV_BAR_INTERACTION_MODE_RES_NAME));
+ }
+
+ public static boolean isSwipeUpMode(Context context) {
+ return QuickStepContract.isSwipeUpMode(
+ getSystemIntegerRes(context, NAV_BAR_INTERACTION_MODE_RES_NAME));
+ }
+
+ public static boolean isLegacyMode(Context context) {
+ return QuickStepContract.isLegacyMode(
+ getSystemIntegerRes(context, NAV_BAR_INTERACTION_MODE_RES_NAME));
+ }
+
+ private static int getSystemIntegerRes(Context context, String resName) {
+ Resources res = context.getResources();
+ int resId = res.getIdentifier(resName, "integer", "android");
+
+ if (resId != 0) {
+ return res.getInteger(resId);
+ } else {
+ Log.e(TAG, "Failed to get system resource ID. Incompatible framework version?");
+ return -1;
+ }
+ }
+
static void sleep(int duration) {
try {
Thread.sleep(duration);
diff --git a/tests/tapl/com/android/launcher3/tapl/Overview.java b/tests/tapl/com/android/launcher3/tapl/Overview.java
index 5c8d5eb..b88da3a 100644
--- a/tests/tapl/com/android/launcher3/tapl/Overview.java
+++ b/tests/tapl/com/android/launcher3/tapl/Overview.java
@@ -18,13 +18,11 @@
import static com.android.launcher3.TestProtocol.ALL_APPS_STATE_ORDINAL;
-import android.graphics.Point;
-
-import com.android.launcher3.tapl.LauncherInstrumentation.ContainerType;
-
import androidx.annotation.NonNull;
import androidx.test.uiautomator.UiObject2;
+import com.android.launcher3.tapl.LauncherInstrumentation.ContainerType;
+
/**
* Overview pane.
*/
@@ -47,14 +45,20 @@
*/
@NonNull
public AllAppsFromOverview switchToAllApps() {
- verifyActiveContainer();
+ try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+ "want to switch from overview to all apps")) {
+ verifyActiveContainer();
- // Swipe from navbar to the top.
- final UiObject2 navBar = mLauncher.waitForSystemUiObject("navigation_bar_frame");
- final Point start = navBar.getVisibleCenter();
- LauncherInstrumentation.log("Overview.switchToAllApps before swipe");
- mLauncher.swipe(start.x, start.y, start.x, 0, ALL_APPS_STATE_ORDINAL);
+ // Swipe from navbar to the top.
+ final UiObject2 navBar = mLauncher.waitForSystemUiObject("navigation_bar_frame");
+ LauncherInstrumentation.log("Overview.switchToAllApps before swipe");
+ final int x = navBar.getVisibleCenter().x;
+ mLauncher.swipe(x, navBar.getVisibleBounds().top - 1, x, 0, ALL_APPS_STATE_ORDINAL);
- return new AllAppsFromOverview(mLauncher);
+ try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
+ "swiped all way up from overview")) {
+ return new AllAppsFromOverview(mLauncher);
+ }
+ }
}
}
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
index 7ccd49b..b966851 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
@@ -44,10 +44,13 @@
* Swipes the task up.
*/
public void dismiss() {
- verifyActiveContainer();
- // Dismiss the task via flinging it up.
- mTask.fling(Direction.DOWN, (int) (FLING_SPEED * mLauncher.getDisplayDensity()));
- mLauncher.waitForIdle();
+ try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+ "want to dismiss a task")) {
+ verifyActiveContainer();
+ // Dismiss the task via flinging it up.
+ mTask.fling(Direction.DOWN, (int) (FLING_SPEED * mLauncher.getDisplayDensity()));
+ mLauncher.waitForIdle();
+ }
}
/**
@@ -55,7 +58,7 @@
*/
public Background open() {
verifyActiveContainer();
- LauncherInstrumentation.assertTrue("Launching task didn't open a new window: " +
+ mLauncher.assertTrue("Launching task didn't open a new window: " +
mTask.getParent().getContentDescription(),
mTask.clickAndWait(Until.newWindow(), LauncherInstrumentation.WAIT_TIME_MS));
return new Background(mLauncher);
diff --git a/tests/tapl/com/android/launcher3/tapl/Widgets.java b/tests/tapl/com/android/launcher3/tapl/Widgets.java
index 89affd1..2de53c3 100644
--- a/tests/tapl/com/android/launcher3/tapl/Widgets.java
+++ b/tests/tapl/com/android/launcher3/tapl/Widgets.java
@@ -34,21 +34,37 @@
* Flings forward (down) and waits the fling's end.
*/
public void flingForward() {
- final UiObject2 widgetsContainer = verifyActiveContainer();
- widgetsContainer.setGestureMargin(100);
- widgetsContainer.fling(Direction.DOWN, (int) (FLING_SPEED * mLauncher.getDisplayDensity()));
- verifyActiveContainer();
+ try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+ "want to fling forward in widgets")) {
+ LauncherInstrumentation.log("Widgets.flingForward enter");
+ final UiObject2 widgetsContainer = verifyActiveContainer();
+ widgetsContainer.setGestureMargin(100);
+ widgetsContainer.fling(Direction.DOWN,
+ (int) (FLING_SPEED * mLauncher.getDisplayDensity()));
+ try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("flung forward")) {
+ verifyActiveContainer();
+ }
+ LauncherInstrumentation.log("Widgets.flingForward exit");
+ }
}
/**
* Flings backward (up) and waits the fling's end.
*/
public void flingBackward() {
- final UiObject2 widgetsContainer = verifyActiveContainer();
- widgetsContainer.setGestureMargin(100);
- widgetsContainer.fling(Direction.UP, (int) (FLING_SPEED * mLauncher.getDisplayDensity()));
- mLauncher.waitForIdle();
- verifyActiveContainer();
+ try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+ "want to fling backwards in widgets")) {
+ LauncherInstrumentation.log("Widgets.flingBackward enter");
+ final UiObject2 widgetsContainer = verifyActiveContainer();
+ widgetsContainer.setGestureMargin(100);
+ widgetsContainer.fling(Direction.UP,
+ (int) (FLING_SPEED * mLauncher.getDisplayDensity()));
+ mLauncher.waitForIdle();
+ try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("flung back")) {
+ verifyActiveContainer();
+ }
+ LauncherInstrumentation.log("Widgets.flingBackward exit");
+ }
}
@Override
diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java
index 7d97acd..91443d0 100644
--- a/tests/tapl/com/android/launcher3/tapl/Workspace.java
+++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java
@@ -36,7 +36,7 @@
public final class Workspace extends Home {
private static final float FLING_SPEED = 3500.0F;
private final UiObject2 mHotseat;
- private final int ICON_DRAG_SPEED = 2000;
+ private final int ICON_DRAG_SPEED = LauncherInstrumentation.needSlowGestures() ? 100 : 570;
Workspace(LauncherInstrumentation launcher) {
super(launcher);
@@ -50,21 +50,27 @@
*/
@NonNull
public AllApps switchToAllApps() {
- verifyActiveContainer();
- final UiObject2 hotseat = mHotseat;
- final Point start = hotseat.getVisibleCenter();
- final int swipeHeight = mLauncher.getTestInfo(
- TestProtocol.REQUEST_HOME_TO_ALL_APPS_SWIPE_HEIGHT).
- getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
- mLauncher.swipe(
- start.x,
- start.y,
- start.x,
- start.y - swipeHeight - mLauncher.getTouchSlop(),
- ALL_APPS_STATE_ORDINAL
- );
+ try (LauncherInstrumentation.Closable c =
+ mLauncher.addContextLayer("want to switch from workspace to all apps")) {
+ verifyActiveContainer();
+ final UiObject2 hotseat = mHotseat;
+ final Point start = hotseat.getVisibleCenter();
+ final int swipeHeight = mLauncher.getTestInfo(
+ TestProtocol.REQUEST_HOME_TO_ALL_APPS_SWIPE_HEIGHT).
+ getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
+ mLauncher.swipe(
+ start.x,
+ start.y,
+ start.x,
+ start.y - swipeHeight - mLauncher.getTouchSlop(),
+ ALL_APPS_STATE_ORDINAL
+ );
- return new AllApps(mLauncher);
+ try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
+ "swiped to all apps")) {
+ return new AllApps(mLauncher);
+ }
+ }
}
/**
@@ -75,9 +81,13 @@
*/
@Nullable
public AppIcon tryGetWorkspaceAppIcon(String appName) {
- final UiObject2 workspace = verifyActiveContainer();
- final UiObject2 icon = workspace.findObject(AppIcon.getAppIconSelector(appName, mLauncher));
- return icon != null ? new AppIcon(mLauncher, icon) : null;
+ try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+ "want to get a workspace icon")) {
+ final UiObject2 workspace = verifyActiveContainer();
+ final UiObject2 icon = workspace.findObject(
+ AppIcon.getAppIconSelector(appName, mLauncher));
+ return icon != null ? new AppIcon(mLauncher, icon) : null;
+ }
}
@@ -104,10 +114,10 @@
if (!isWorkspaceScrollable(workspace)) {
dragIconToWorkspace(
mLauncher,
- getHotseatAppIcon("Messages"),
+ getHotseatAppIcon("Play Store"),
new Point(mLauncher.getDevice().getDisplayWidth(),
workspace.getVisibleBounds().centerY()),
- ICON_DRAG_SPEED);
+ (int) (ICON_DRAG_SPEED * mLauncher.getDisplayDensity()));
verifyActiveContainer();
}
assertTrue("Home screen workspace didn't become scrollable",
@@ -126,7 +136,9 @@
static void dragIconToWorkspace(LauncherInstrumentation launcher, Launchable launchable,
Point dest, int icon_drag_speed) {
+ LauncherInstrumentation.log("dragIconToWorkspace: begin");
launchable.getObject().drag(dest, icon_drag_speed);
+ LauncherInstrumentation.log("dragIconToWorkspace: end");
launcher.waitUntilGone("drop_target_bar");
}
@@ -165,7 +177,9 @@
public Widgets openAllWidgets() {
verifyActiveContainer();
mLauncher.getDevice().pressKeyCode(KeyEvent.KEYCODE_W, KeyEvent.META_CTRL_ON);
- return new Widgets(mLauncher);
+ try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer("pressed Ctrl+W")) {
+ return new Widgets(mLauncher);
+ }
}
@Override