Merge "App icon transitions with app window in overview" into ub-launcher3-master
diff --git a/go/quickstep/res/layout/task_item_view.xml b/go/quickstep/res/layout/task_item_view.xml
new file mode 100644
index 0000000..90940c4
--- /dev/null
+++ b/go/quickstep/res/layout/task_item_view.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<com.android.quickstep.views.TaskItemView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+ <ImageView
+ android:id="@+id/task_icon_and_thumbnail"
+ android:layout_width="@dimen/task_thumbnail_icon_size"
+ android:layout_height="@dimen/task_thumbnail_icon_size"
+ android:layout_gravity="center_vertical"
+ android:layout_marginHorizontal="8dp"/>
+ <TextView
+ android:id="@+id/task_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_marginHorizontal="8dp"
+ android:singleLine="true"
+ android:textColor="@android:color/white"
+ android:textSize="24sp"/>
+</com.android.quickstep.views.TaskItemView>
diff --git a/go/quickstep/src/com/android/quickstep/TaskAdapter.java b/go/quickstep/src/com/android/quickstep/TaskAdapter.java
index 57cd60a..d3fd240 100644
--- a/go/quickstep/src/com/android/quickstep/TaskAdapter.java
+++ b/go/quickstep/src/com/android/quickstep/TaskAdapter.java
@@ -15,16 +15,17 @@
*/
package com.android.quickstep;
+import android.view.LayoutInflater;
import android.view.ViewGroup;
-import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView.Adapter;
+import com.android.launcher3.R;
+import com.android.quickstep.views.TaskItemView;
import com.android.systemui.shared.recents.model.Task;
import java.util.ArrayList;
-
/**
* Recycler view adapter that dynamically inflates and binds {@link TaskHolder} instances with the
* appropriate {@link Task} from the recents task list.
@@ -42,8 +43,9 @@
@Override
public TaskHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// TODO: Swap in an actual task view here (view w/ icon, label, etc.)
- TextView stubView = new TextView(parent.getContext());
- return new TaskHolder(stubView);
+ TaskItemView itemView = (TaskItemView) LayoutInflater.from(parent.getContext())
+ .inflate(R.layout.task_item_view, parent, false);
+ return new TaskHolder(itemView);
}
@Override
diff --git a/go/quickstep/src/com/android/quickstep/TaskHolder.java b/go/quickstep/src/com/android/quickstep/TaskHolder.java
index 1ea6d76..47398c8 100644
--- a/go/quickstep/src/com/android/quickstep/TaskHolder.java
+++ b/go/quickstep/src/com/android/quickstep/TaskHolder.java
@@ -15,10 +15,9 @@
*/
package com.android.quickstep;
-import android.widget.TextView;
-
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
+import com.android.quickstep.views.TaskItemView;
import com.android.systemui.shared.recents.model.Task;
/**
@@ -27,22 +26,21 @@
*/
final class TaskHolder extends ViewHolder {
- // TODO: Implement the actual task view to be held.
- // For now, we just use a simple text view.
- private final TextView mStubView;
+ private final TaskItemView mTaskItemView;
- public TaskHolder(TextView stubView) {
- super(stubView);
- mStubView = stubView;
+ public TaskHolder(TaskItemView itemView) {
+ super(itemView);
+ mTaskItemView = itemView;
}
/**
* 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.
*
- * @param task the task to bind to the view this
+ * @param task the task to bind to the view
*/
public void bindTask(Task task) {
- mStubView.setText("Stub task view: " + task.titleDescription);
+ mTaskItemView.setLabel(task.titleDescription);
+ mTaskItemView.setIcon(task.icon);
}
}
diff --git a/go/quickstep/src/com/android/quickstep/TaskListLoader.java b/go/quickstep/src/com/android/quickstep/TaskListLoader.java
index 9f359b4..c798cef 100644
--- a/go/quickstep/src/com/android/quickstep/TaskListLoader.java
+++ b/go/quickstep/src/com/android/quickstep/TaskListLoader.java
@@ -85,34 +85,40 @@
}
/**
- * Loads task content for a list of tasks, including the label and the icon. Uses the list of
- * tasks since the last load as a cache for loaded content.
+ * 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 onLoadedCallback runnable to run after all tasks have loaded their content
+ * @param onFullyLoadedCallback runnable to run after all tasks have loaded their content
*/
private void loadTaskContents(ArrayList<Task> tasksToLoad,
- @Nullable Runnable onLoadedCallback) {
- AtomicInteger loadRequestsCount = new AtomicInteger(0);
+ @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.
- loadRequestsCount.getAndIncrement();
- mRecentsModel.getIconCache().updateIconInBackground(task, loadedTask -> {
- if (loadRequestsCount.decrementAndGet() == 0 && onLoadedCallback != null) {
- onLoadedCallback.run();
- }
- });
+ mRecentsModel.getIconCache().updateIconInBackground(task,
+ loadedTask -> itemLoadedRunnable.run());
}
- }
- if (loadRequestsCount.get() == 0 && onLoadedCallback != null) {
- onLoadedCallback.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 2858deb..89a8454 100644
--- a/go/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/go/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -52,6 +52,7 @@
ISystemUiProxy iSystemUiProxy = ISystemUiProxy.Stub
.asInterface(bundle.getBinder(KEY_EXTRA_SYSUI_PROXY));
mRecentsModel.setSystemUiProxy(iSystemUiProxy);
+ mRecentsModel.onInitializeSystemUI(bundle);
}
@Override
@@ -77,6 +78,11 @@
mOverviewCommandHelper.onTip(actionType, viewType);
}
+ @Override
+ public void onAssistantAvailable(boolean available) {
+ // TODO handle assistant
+ }
+
/** Deprecated methods **/
public void onQuickStep(MotionEvent motionEvent) { }
diff --git a/go/quickstep/src/com/android/quickstep/views/TaskItemView.java b/go/quickstep/src/com/android/quickstep/views/TaskItemView.java
new file mode 100644
index 0000000..ce3947d
--- /dev/null
+++ b/go/quickstep/src/com/android/quickstep/views/TaskItemView.java
@@ -0,0 +1,64 @@
+/*
+ * 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.views;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.launcher3.R;
+
+/**
+ * View representing an individual task item with the icon + thumbnail adjacent to the task label.
+ */
+public final class TaskItemView extends LinearLayout {
+
+ private TextView mLabelView;
+ private ImageView mIconView;
+
+ public TaskItemView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mLabelView = findViewById(R.id.task_label);
+ mIconView = findViewById(R.id.task_icon_and_thumbnail);
+ }
+
+ /**
+ * Set the label for the task item.
+ *
+ * @param label task label
+ */
+ public void setLabel(String label) {
+ mLabelView.setText(label);
+ }
+
+ /**
+ * Set the icon for the task item.
+ *
+ * @param icon task icon
+ */
+ public void setIcon(Drawable icon) {
+ mIconView.setImageDrawable(icon);
+ // TODO: Add in combination drawable for icon + thumbnail
+ }
+}
diff --git a/quickstep/AndroidManifest.xml b/quickstep/AndroidManifest.xml
index 62d0500..0992849 100644
--- a/quickstep/AndroidManifest.xml
+++ b/quickstep/AndroidManifest.xml
@@ -39,7 +39,7 @@
<service
android:name="com.android.quickstep.TouchInteractionService"
android:permission="android.permission.STATUS_BAR_SERVICE"
- android:directBootAware="true" >
+ android:directBootAware="false" >
<intent-filter>
<action android:name="android.intent.action.QUICKSTEP_SERVICE" />
</intent-filter>
diff --git a/quickstep/libs/sysui_shared.jar b/quickstep/libs/sysui_shared.jar
index 2b76924..4b64ad4 100644
--- a/quickstep/libs/sysui_shared.jar
+++ b/quickstep/libs/sysui_shared.jar
Binary files differ
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/BackgroundAppState.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/BackgroundAppState.java
index 963f1fa..fdb80da 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/BackgroundAppState.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/BackgroundAppState.java
@@ -20,6 +20,7 @@
import android.os.RemoteException;
import com.android.launcher3.Launcher;
import com.android.launcher3.allapps.AllAppsTransitionController;
+import com.android.launcher3.config.FeatureFlags;
import com.android.quickstep.RecentsModel;
import com.android.quickstep.util.LayoutUtils;
import com.android.quickstep.views.RecentsView;
@@ -72,4 +73,13 @@
float scale = (float) appWidth / sTempRect.width();
return new float[] { scale, 0f };
}
+
+ @Override
+ public int getVisibleElements(Launcher launcher) {
+ if (FeatureFlags.SWIPE_HOME.get()) {
+ return super.getVisibleElements(launcher);
+ }
+ // Hide shelf content (e.g. QSB) because we fade it in when swiping up.
+ return ALL_APPS_HEADER_EXTRA;
+ }
}
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 9650a53..eee0344 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java
@@ -23,28 +23,36 @@
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.allapps.AllAppsTransitionController.SPRING_DAMPING_RATIO;
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 android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
-import android.content.ComponentName;
import android.content.Context;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
+import android.os.UserHandle;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Interpolator;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.UiThread;
+
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.allapps.AllAppsTransitionController;
import com.android.launcher3.allapps.DiscoveryBounce;
import com.android.launcher3.anim.AnimatorPlaybackController;
+import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.anim.SpringObjectAnimator;
import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.config.FeatureFlags;
@@ -61,10 +69,6 @@
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.
*/
@@ -102,9 +106,10 @@
final RecentsView recentsView = activity.getOverviewPanel();
final TaskView runningTaskView = recentsView.getRunningTaskView();
final View workspaceView;
- if (runningTaskView != null) {
- ComponentName component = runningTaskView.getTask().key.sourceComponent;
- workspaceView = activity.getWorkspace().getFirstMatchForAppClose(component);
+ if (runningTaskView != null && runningTaskView.getTask().key.getComponent() != null) {
+ workspaceView = activity.getWorkspace().getFirstMatchForAppClose(
+ runningTaskView.getTask().key.getComponent().getPackageName(),
+ UserHandle.of(runningTaskView.getTask().key.userId));
} else {
workspaceView = null;
}
@@ -211,7 +216,7 @@
: mShelfState == ShelfAnimState.PEEK
? shelfPeekingProgress
: shelfOverviewProgress;
- mShelfAnim = createShelfAnim(activity, toProgress);
+ mShelfAnim = createShelfProgressAnim(activity, toProgress);
mShelfAnim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
@@ -229,10 +234,10 @@
LauncherState fromState, long transitionLength,
Consumer<AnimatorPlaybackController> callback) {
LauncherState endState = OVERVIEW;
+ DeviceProfile dp = activity.getDeviceProfile();
+ long accuracy = 2 * Math.max(dp.widthPx, dp.heightPx);
if (wasVisible && fromState != BACKGROUND_APP) {
// If a translucent app was launched fom launcher, animate launcher states.
- DeviceProfile dp = activity.getDeviceProfile();
- long accuracy = 2 * Math.max(dp.widthPx, dp.heightPx);
callback.accept(activity.getStateManager()
.createAnimationToNewWorkspace(fromState, endState, accuracy));
return;
@@ -245,10 +250,11 @@
if (!activity.getDeviceProfile().isVerticalBarLayout()
&& !FeatureFlags.SWIPE_HOME.get()) {
// Don't animate the shelf when SWIPE_HOME is true, because we update it atomically.
- Animator shiftAnim = createShelfAnim(activity,
+ Animator shiftAnim = createShelfProgressAnim(activity,
fromState.getVerticalProgress(activity),
endState.getVerticalProgress(activity));
anim.play(shiftAnim);
+ anim.play(createShelfAlphaAnim(activity, endState, accuracy));
}
playScaleDownAnim(anim, activity, endState);
@@ -265,7 +271,7 @@
callback.accept(controller);
}
- private Animator createShelfAnim(Launcher activity, float ... progressValues) {
+ private Animator createShelfProgressAnim(Launcher activity, float ... progressValues) {
Animator shiftAnim = new SpringObjectAnimator<>(activity.getAllAppsController(),
"allAppsSpringFromACH", activity.getAllAppsController().getShiftRange(),
SPRING_DAMPING_RATIO, SPRING_STIFFNESS, progressValues);
@@ -274,6 +280,19 @@
}
/**
+ * Very quickly fade the alpha of shelf content.
+ */
+ private Animator createShelfAlphaAnim(Launcher activity, LauncherState toState, long accuracy) {
+ AllAppsTransitionController allAppsController = activity.getAllAppsController();
+ AnimatorSetBuilder animBuilder = new AnimatorSetBuilder();
+ animBuilder.setInterpolator(AnimatorSetBuilder.ANIM_ALL_APPS_FADE, DEACCEL_3);
+ LauncherStateManager.AnimationConfig config = new LauncherStateManager.AnimationConfig();
+ config.duration = accuracy;
+ allAppsController.setAlphas(toState.getVisibleElements(activity), config, animBuilder);
+ return animBuilder.build();
+ }
+
+ /**
* Scale down recents from the center task being full screen to being in overview.
*/
private void playScaleDownAnim(AnimatorSet anim, Launcher 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 e3afb92..4e010d2 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/OtherActivityInputConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/OtherActivityInputConsumer.java
@@ -230,7 +230,6 @@
mTouchSlop) {
mPassedTouchSlop = true;
- TOUCH_INTERACTION_LOG.addLog("startQuickstep");
if (mIsDeferredDownTarget) {
// Deferred gesture, start the animation and gesture tracking once
// we pass the actual touch slop
@@ -272,6 +271,7 @@
}
private void notifyGestureStarted() {
+ TOUCH_INTERACTION_LOG.addLog("startQuickstep");
if (mInteractionHandler == null) {
return;
}
@@ -310,6 +310,7 @@
if (listenerSet != null) {
listenerSet.addListener(handler);
mSwipeSharedState.applyActiveRecentsAnimationState(handler);
+ notifyGestureStarted();
} else {
RecentsAnimationListenerSet newListenerSet =
mSwipeSharedState.newRecentsAnimationListenerSet();
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 a3c3ff9..6d608ee 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
@@ -89,6 +89,7 @@
.asInterface(bundle.getBinder(KEY_EXTRA_SYSUI_PROXY));
runWhenUserUnlocked(() -> {
mRecentsModel.setSystemUiProxy(mISystemUiProxy);
+ mRecentsModel.onInitializeSystemUI(bundle);
mOverviewInteractionState.setSystemUiProxy(mISystemUiProxy);
});
@@ -121,6 +122,11 @@
mOverviewCommandHelper.onTip(actionType, viewType);
}
+ @Override
+ public void onAssistantAvailable(boolean available) {
+ mAssistantAvailable = available;
+ }
+
/** Deprecated methods **/
public void onQuickStep(MotionEvent motionEvent) { }
@@ -174,6 +180,7 @@
private TaskOverlayFactory mTaskOverlayFactory;
private InputConsumerController mInputConsumer;
private SwipeSharedState mSwipeSharedState;
+ private boolean mAssistantAvailable;
private boolean mIsUserUnlocked;
private List<Runnable> mOnUserUnlockedCallbacks;
@@ -308,7 +315,7 @@
if (runningTaskInfo == null && !mSwipeSharedState.goingToLauncher) {
return InputConsumer.NO_OP;
- } else if (mOverviewInteractionState.isSwipeUpGestureEnabled()
+ } else if (mAssistantAvailable && mOverviewInteractionState.isSwipeUpGestureEnabled()
&& FeatureFlags.ENABLE_ASSISTANT_GESTURE.get()
&& AssistantTouchConsumer.withinTouchRegion(this, event.getX())) {
return new AssistantTouchConsumer(this, mRecentsModel.getSystemUiProxy());
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/DigitalWellBeingToast.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/DigitalWellBeingToast.java
index 0aa1beb..19e9cb4 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/DigitalWellBeingToast.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/DigitalWellBeingToast.java
@@ -23,6 +23,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.pm.LauncherApps;
+import android.content.pm.LauncherApps.AppUsageLimit;
import android.content.res.Resources;
import android.icu.text.MeasureFormat;
import android.icu.text.MeasureFormat.FormatWidth;
@@ -44,13 +45,13 @@
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.systemui.shared.recents.model.Task;
-import java.lang.reflect.Method;
import java.time.Duration;
import java.util.Locale;
public final class DigitalWellBeingToast extends LinearLayout {
static final Intent OPEN_APP_USAGE_SETTINGS_TEMPLATE = new Intent(ACTION_APP_USAGE_SETTINGS);
static final int MINUTE_MS = 60000;
+ private final LauncherApps mLauncherApps;
public interface InitializeCallback {
void call(float saturation, String contentDescription);
@@ -67,6 +68,7 @@
setLayoutDirection(Utilities.isRtl(getResources()) ?
View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR);
setOnClickListener((view) -> openAppUsageSettings());
+ mLauncherApps = context.getSystemService(LauncherApps.class);
}
@Override
@@ -87,47 +89,29 @@
}
Utilities.THREAD_POOL_EXECUTOR.execute(() -> {
- long appUsageLimitTimeMs = -1;
- long appRemainingTimeMs = -1;
+ final AppUsageLimit usageLimit = mLauncherApps.getAppUsageLimit(
+ task.getTopComponent().getPackageName(),
+ UserHandle.of(task.key.userId));
- try {
- final Method getAppUsageLimit = LauncherApps.class.getMethod(
- "getAppUsageLimit",
- String.class,
- UserHandle.class);
- final Object usageLimit = getAppUsageLimit.invoke(
- getContext().getSystemService(LauncherApps.class),
- task.getTopComponent().getPackageName(),
- UserHandle.of(task.key.userId));
-
- if (usageLimit != null) {
- final Class appUsageLimitClass = usageLimit.getClass();
- appUsageLimitTimeMs = (long) appUsageLimitClass.getMethod("getTotalUsageLimit").
- invoke(usageLimit);
- appRemainingTimeMs = (long) appUsageLimitClass.getMethod("getUsageRemaining").
- invoke(usageLimit);
- }
- } catch (Exception e) {
- // Do nothing
- }
-
- final long appUsageLimitTimeMsFinal = appUsageLimitTimeMs;
- final long appRemainingTimeMsFinal = appRemainingTimeMs;
+ final long appUsageLimitTimeMs =
+ usageLimit != null ? usageLimit.getTotalUsageLimit() : -1;
+ final long appRemainingTimeMs =
+ usageLimit != null ? usageLimit.getUsageRemaining() : -1;
post(() -> {
- if (appUsageLimitTimeMsFinal < 0) {
+ if (appUsageLimitTimeMs < 0) {
setVisibility(GONE);
} else {
setVisibility(VISIBLE);
- mText.setText(getText(appRemainingTimeMsFinal));
- mImage.setImageResource(appRemainingTimeMsFinal > 0 ?
+ mText.setText(getText(appRemainingTimeMs));
+ mImage.setImageResource(appRemainingTimeMs > 0 ?
R.drawable.hourglass_top : R.drawable.hourglass_bottom);
}
callback.call(
- appUsageLimitTimeMsFinal >= 0 && appRemainingTimeMsFinal <= 0 ? 0 : 1,
+ appUsageLimitTimeMs >= 0 && appRemainingTimeMs <= 0 ? 0 : 1,
getContentDescriptionForTask(
- task, appUsageLimitTimeMsFinal, appRemainingTimeMsFinal));
+ task, appUsageLimitTimeMs, appRemainingTimeMs));
});
});
}
diff --git a/quickstep/src/com/android/quickstep/RecentsModel.java b/quickstep/src/com/android/quickstep/RecentsModel.java
index 81a22a1..56bc8570 100644
--- a/quickstep/src/com/android/quickstep/RecentsModel.java
+++ b/quickstep/src/com/android/quickstep/RecentsModel.java
@@ -16,12 +16,15 @@
package com.android.quickstep;
import static com.android.quickstep.TaskUtils.checkCurrentOrManagedUserId;
+import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SUPPORTS_WINDOW_CORNERS;
+import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_WINDOW_CORNER_RADIUS;
import android.annotation.TargetApi;
import android.app.ActivityManager;
import android.content.ComponentCallbacks2;
import android.content.Context;
import android.os.Build;
+import android.os.Bundle;
import android.os.HandlerThread;
import android.os.Process;
import android.os.RemoteException;
@@ -59,8 +62,8 @@
private final TaskIconCache mIconCache;
private final TaskThumbnailCache mThumbnailCache;
- private float mWindowCornerRadius = -1;
- private Boolean mSupportsRoundedCornersOnWindows;
+ private float mWindowCornerRadius = 0;
+ private boolean mSupportsRoundedCornersOnWindows;
private RecentsModel(Context context) {
mContext = context;
@@ -73,6 +76,12 @@
ActivityManagerWrapper.getInstance().registerTaskStackListener(this);
}
+ public void onInitializeSystemUI(Bundle params) {
+ mWindowCornerRadius = params.getFloat(KEY_EXTRA_WINDOW_CORNER_RADIUS, 0);
+ mSupportsRoundedCornersOnWindows =
+ params.getBoolean(KEY_EXTRA_SUPPORTS_WINDOW_CORNERS, false);
+ }
+
public TaskIconCache getIconCache() {
return mIconCache;
}
@@ -182,42 +191,10 @@
}
public float getWindowCornerRadius() {
- // The window corner radius is expressed in pixels and won't change if the
- // display density changes. It's safe to cache the value.
- if (mWindowCornerRadius == -1) {
- if (mSystemUiProxy != null) {
- try {
- mWindowCornerRadius = mSystemUiProxy.getWindowCornerRadius();
- } catch (RemoteException e) {
- Log.w(TAG, "Connection to ISystemUIProxy was lost, ignoring window corner "
- + "radius");
- return 0;
- }
- } else {
- Log.w(TAG, "ISystemUIProxy is null, ignoring window corner radius");
- return 0;
- }
- }
return mWindowCornerRadius;
}
public boolean supportsRoundedCornersOnWindows() {
- if (mSupportsRoundedCornersOnWindows == null) {
- if (mSystemUiProxy != null) {
- try {
- mSupportsRoundedCornersOnWindows =
- mSystemUiProxy.supportsRoundedCornersOnWindows();
- } catch (RemoteException e) {
- Log.w(TAG, "Connection to ISystemUIProxy was lost, ignoring window corner "
- + "radius");
- return false;
- }
- } else {
- Log.w(TAG, "ISystemUIProxy is null, ignoring window corner radius");
- return false;
- }
- }
-
return mSupportsRoundedCornersOnWindows;
}
diff --git a/quickstep/tests/src/com/android/quickstep/QuickStepOnOffRule.java b/quickstep/tests/src/com/android/quickstep/QuickStepOnOffRule.java
index c5975a9..f89842a 100644
--- a/quickstep/tests/src/com/android/quickstep/QuickStepOnOffRule.java
+++ b/quickstep/tests/src/com/android/quickstep/QuickStepOnOffRule.java
@@ -24,6 +24,7 @@
import static org.junit.Assert.assertTrue;
import android.provider.Settings;
+import android.util.Log;
import androidx.test.InstrumentationRegistry;
@@ -46,6 +47,8 @@
*/
public class QuickStepOnOffRule implements TestRule {
+ static final String TAG = "QuickStepOnOffRule";
+
public enum Mode {
ON, OFF, BOTH
}
@@ -73,32 +76,32 @@
return new Statement() {
@Override
public void evaluate() throws Throwable {
- try {
- if (SwipeUpSetting.isSwipeUpSettingAvailable()) {
+ if (SwipeUpSetting.isSwipeUpSettingAvailable()) {
+ try {
if (mode == ON || mode == BOTH) {
evaluateWithQuickstepOn();
}
if (mode == OFF || mode == BOTH) {
evaluateWithQuickstepOff();
}
- } else {
- // Execute without changing the setting, if the requested mode is
- // compatible.
- final boolean swipeUpEnabledDefaultValue =
- SwipeUpSetting.isSwipeUpEnabledDefaultValue();
- if (mode == BOTH ||
- mode == ON && swipeUpEnabledDefaultValue ||
- mode == OFF && !swipeUpEnabledDefaultValue) {
- evaluateWithoutChangingSetting(base);
- }
+ } finally {
+ setSwipeUpSetting(null);
}
- } finally {
- setSwipeUpSetting(null);
-
+ } else {
+ // Execute without changing the setting, if the requested mode is
+ // compatible.
+ final boolean swipeUpEnabledDefaultValue =
+ SwipeUpSetting.isSwipeUpEnabledDefaultValue();
+ if (mode == BOTH ||
+ mode == ON && swipeUpEnabledDefaultValue ||
+ mode == OFF && !swipeUpEnabledDefaultValue) {
+ evaluateWithoutChangingSetting(base);
+ }
}
}
public void setSwipeUpSetting(String value) {
+ Log.d(TAG, "setSwipeUpSetting: " + value);
assertTrue("Couldn't change Quickstep mode",
Settings.Secure.putString(
InstrumentationRegistry.getInstrumentation().getTargetContext().
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 3b054c2..7919d29 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -133,6 +133,7 @@
private final Rect mInsets = new Rect();
public final Rect workspacePadding = new Rect();
private final Rect mHotseatPadding = new Rect();
+ // When true, nav bar is on the left side of the screen.
private boolean mIsSeascape;
// Notification dots
@@ -587,28 +588,40 @@
/**
* Gets an item's location on the home screen. This is useful if the home screen
* is animating, otherwise use {@link View#getLocationOnScreen(int[])}.
- *
- * TODO(b/123900446): Handle landscape mode
* @param pageDiff The page difference relative to the current page.
*/
public void getItemLocation(int cellX, int cellY, int spanX, int spanY, int container,
int pageDiff, Rect outBounds) {
outBounds.setEmpty();
- outBounds.left = mInsets.left
- + workspacePadding.left + cellLayoutPaddingLeftRightPx + (cellX * getCellSize().x);
- outBounds.top = mInsets.top;
if (container == CONTAINER_HOTSEAT) {
- outBounds.top += workspacePadding.top
- + (inv.numRows * getCellSize().y)
- + verticalDragHandleSizePx
- - verticalDragHandleOverlapWorkspace;
- outBounds.bottom = outBounds.top + hotseatBarSizePx - hotseatBarBottomPaddingPx;
+ final int actualHotseatCellHeight;
+ if (isVerticalBarLayout()) {
+ actualHotseatCellHeight = availableHeightPx / inv.numRows;
+ if (mIsSeascape) {
+ outBounds.left = mHotseatPadding.left;
+ } else {
+ outBounds.left = availableWidthPx - hotseatBarSizePx + mHotseatPadding.left;
+ }
+ outBounds.right = outBounds.left + iconSizePx;
+ outBounds.top = mHotseatPadding.top
+ + actualHotseatCellHeight * (inv.numRows - cellX - 1);
+ outBounds.bottom = outBounds.top + actualHotseatCellHeight;
+ } else {
+ actualHotseatCellHeight = hotseatBarSizePx - hotseatBarBottomPaddingPx
+ - hotseatBarTopPaddingPx;
+ outBounds.left = mInsets.left + workspacePadding.left + cellLayoutPaddingLeftRightPx
+ + (cellX * getCellSize().x);
+ outBounds.right = outBounds.left + getCellSize().x;
+ outBounds.top = mInsets.top + availableHeightPx - hotseatBarSizePx;
+ outBounds.bottom = outBounds.top + actualHotseatCellHeight;
+ }
} else {
- outBounds.top += workspacePadding.top + (cellY * getCellSize().y);
+ outBounds.left = mInsets.left + workspacePadding.left + cellLayoutPaddingLeftRightPx
+ + (cellX * getCellSize().x) + (pageDiff * availableWidthPx);
+ outBounds.right = outBounds.left + (getCellSize().x * spanX);
+ outBounds.top = mInsets.top + workspacePadding.top + (cellY * getCellSize().y);
outBounds.bottom = outBounds.top + (getCellSize().y * spanY);
- outBounds.left += (pageDiff) * availableWidthPx;
}
- outBounds.right = outBounds.left + (getCellSize().x * spanX);
}
public float getAspectRatioWithInsets() {
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index d820448..61cd2f1 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -488,11 +488,15 @@
@Override
public void invalidateParent(ItemInfo info) {
- FolderIconPreviewVerifier verifier = new FolderIconPreviewVerifier(getDeviceProfile().inv);
- if (verifier.isItemInPreview(info.rank) && (info.container >= 0)) {
+ if (info.container >= 0) {
View folderIcon = getWorkspace().getHomescreenIconByItemId(info.container);
- if (folderIcon != null) {
- folderIcon.invalidate();
+ if (folderIcon instanceof FolderIcon && folderIcon.getTag() instanceof FolderInfo) {
+ FolderIconPreviewVerifier verifier =
+ new FolderIconPreviewVerifier(getDeviceProfile().inv);
+ verifier.setFolderInfo((FolderInfo) folderIcon.getTag());
+ if (verifier.isItemInPreview(info.rank)) {
+ folderIcon.invalidate();
+ }
}
}
}
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index fb33694..ce73229 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -20,6 +20,7 @@
import static com.android.launcher3.provider.LauncherDbUtils.tableExists;
import android.annotation.TargetApi;
+import android.app.backup.BackupManager;
import android.appwidget.AppWidgetHost;
import android.appwidget.AppWidgetManager;
import android.content.ComponentName;
@@ -150,7 +151,7 @@
mOpenHelper = new DatabaseHelper(getContext(), mListenerHandler);
if (RestoreDbTask.isPending(getContext())) {
- if (!RestoreDbTask.performRestore(mOpenHelper)) {
+ if (!RestoreDbTask.performRestore(mOpenHelper, new BackupManager(getContext()))) {
mOpenHelper.createEmptyDB(mOpenHelper.getWritableDatabase());
}
// Set is pending to false irrespective of the result, so that it doesn't get
@@ -542,6 +543,7 @@
* The class is subclassed in tests to create an in-memory db.
*/
public static class DatabaseHelper extends NoLocaleSQLiteHelper implements LayoutParserCallback {
+ private final BackupManager mBackupManager;
private final Handler mWidgetHostResetHandler;
private final Context mContext;
private int mMaxItemId = -1;
@@ -571,6 +573,7 @@
super(context, tableName, SCHEMA_VERSION);
mContext = context;
mWidgetHostResetHandler = widgetHostResetHandler;
+ mBackupManager = new BackupManager(mContext);
}
protected void initIds() {
@@ -620,9 +623,12 @@
Utilities.getPrefs(mContext).edit().putBoolean(EMPTY_DATABASE_CREATED, true).commit();
}
+ public long getSerialNumberForUser(UserHandle user) {
+ return UserManagerCompat.getInstance(mContext).getSerialNumberForUser(user);
+ }
+
public long getDefaultUserSerial() {
- return UserManagerCompat.getInstance(mContext).getSerialNumberForUser(
- Process.myUserHandle());
+ return getSerialNumberForUser(Process.myUserHandle());
}
private void addFavoritesTable(SQLiteDatabase db, boolean optional) {
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 7eee8af..09eb6d9 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -19,9 +19,13 @@
import static com.android.launcher3.LauncherAnimUtils.OVERVIEW_TRANSITION_MS;
import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_TRANSITION_MS;
+import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
+import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
+import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.SPRING_LOADED;
+import static com.android.launcher3.config.FeatureFlags.ADAPTIVE_ICON_WINDOW_ANIM;
import static com.android.launcher3.dragndrop.DragLayer.ALPHA_INDEX_OVERLAY;
import android.animation.Animator;
@@ -34,7 +38,6 @@
import android.app.WallpaperManager;
import android.appwidget.AppWidgetHostView;
import android.appwidget.AppWidgetProviderInfo;
-import android.content.ComponentName;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
@@ -47,6 +50,7 @@
import android.os.Message;
import android.os.Parcelable;
import android.os.UserHandle;
+import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.util.SparseArray;
@@ -99,8 +103,6 @@
import java.util.ArrayList;
import java.util.HashSet;
-import java.util.Objects;
-import java.util.Set;
import java.util.function.Predicate;
/**
@@ -1612,7 +1614,7 @@
boolean aboveShortcut = (dropOverView.getTag() instanceof ShortcutInfo);
boolean willBecomeShortcut =
- (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
+ (info.itemType == ITEM_TYPE_APPLICATION ||
info.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT ||
info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT);
@@ -2520,7 +2522,7 @@
View view;
switch (info.itemType) {
- case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
+ case ITEM_TYPE_APPLICATION:
case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT:
if (info.container == NO_ID && info instanceof AppInfo) {
@@ -2896,51 +2898,29 @@
}
/**
- * Returns a list of all the CellLayouts on the Homescreen, starting with
- * {@param startPage}, then going outward alternating between pages prior to the startPage,
- * and then the pages after the startPage.
- * ie. if there are 5 pages [0, 1, 2, 3, 4] and startPage is 1, we return [1, 0, 2, 3, 4].
- */
- private CellLayout[] getWorkspaceCellLayouts(int startPage) {
- int screenCount = getChildCount();
- final CellLayout[] layouts = new CellLayout[screenCount];
- int screen = 0;
-
- layouts[screen] = (CellLayout) getChildAt(startPage);
- screen++;
-
- for (int i = 1; screen < screenCount; ++i) {
- CellLayout prevPage = (CellLayout) getChildAt(startPage - i);
- CellLayout nextPage = (CellLayout) getChildAt(startPage + i);
-
- if (prevPage != null) {
- layouts[screen] = prevPage;
- screen++;
- }
- if (nextPage != null) {
- layouts[screen] = nextPage;
- screen++;
- }
- }
- return layouts;
- }
-
- /**
* Similar to {@link #getFirstMatch} but optimized to finding a suitable view for the app close
* animation.
*
- * @param component The component of the task being dismissed.
+ * @param packageName The package name of the app to match.
+ * @param user The user of the app to match.
*/
- public View getFirstMatchForAppClose(ComponentName component) {
+ public View getFirstMatchForAppClose(String packageName, UserHandle user) {
final int curPage = getCurrentPage();
final CellLayout currentPage = (CellLayout) getPageAt(curPage);
- final Workspace.ItemOperator isItemComponent = (info, view) ->
- info != null && Objects.equals(info.getTargetComponent(), component);
- final Workspace.ItemOperator isItemInFolder = (info, view) -> {
+ final Workspace.ItemOperator packageAndUser = (ItemInfo info, View view) -> info != null
+ && info.getTargetComponent() != null
+ && TextUtils.equals(info.getTargetComponent().getPackageName(), packageName)
+ && info.user.equals(user);
+ final Workspace.ItemOperator packageAndUserAndApp = (ItemInfo info, View view) ->
+ packageAndUser.evaluate(info, view) && info.itemType == ITEM_TYPE_APPLICATION;
+ final Workspace.ItemOperator packageAndUserAndShortcut = (ItemInfo info, View view) ->
+ packageAndUser.evaluate(info, view) && (info.itemType == ITEM_TYPE_SHORTCUT
+ || info.itemType == ITEM_TYPE_DEEP_SHORTCUT);
+ final Workspace.ItemOperator packageAndUserInFolder = (info, view) -> {
if (info instanceof FolderInfo) {
FolderInfo folderInfo = (FolderInfo) info;
for (ShortcutInfo shortcutInfo : folderInfo.contents) {
- if (Objects.equals(shortcutInfo.getTargetComponent(), component)) {
+ if (packageAndUser.evaluate(shortcutInfo, view)) {
return true;
}
}
@@ -2948,33 +2928,16 @@
return false;
};
- CellLayout[] hotseatAndCurrentPage = new CellLayout[] { getHotseat(), currentPage };
- // First we look if the app itself is in the hotseat or on the current workspace page.
- View icon = getFirstMatch(hotseatAndCurrentPage, isItemComponent);
- if (icon != null) {
- return icon;
+ // Order: App icons, shortcuts, app/shortcut in folder. Items in hotseat get returned first.
+ if (ADAPTIVE_ICON_WINDOW_ANIM.get()) {
+ return getFirstMatch(new CellLayout[] { getHotseat(), currentPage },
+ packageAndUserAndApp, packageAndUserAndShortcut, packageAndUserInFolder);
+ } else {
+ // Do not use Folder as a criteria, since it'll cause a crash when trying to draw
+ // FolderAdaptiveIcon as the background.
+ return getFirstMatch(new CellLayout[] { getHotseat(), currentPage },
+ packageAndUserAndApp, packageAndUserAndShortcut);
}
- // Then we look if the app is in a folder on the hotseat or current workspace page.
- icon = getFirstMatch(hotseatAndCurrentPage, isItemInFolder);
- if (icon != null) {
- return icon;
- }
- // Continue searching for the app or for a folder with the app on other pages of the
- // workspace. We skip the current page, since we already searched above.
- CellLayout[] allPages = getWorkspaceCellLayouts(curPage);
- CellLayout[] page = new CellLayout[1];
- for (int i = 1; i < allPages.length; ++i) {
- page[0] = allPages[i];
- icon = getFirstMatch(page, isItemComponent);
- if (icon != null) {
- return icon;
- }
- icon = getFirstMatch(page, isItemInFolder);
- if (icon != null) {
- return icon;
- }
- }
- return null;
}
public View getHomescreenIconByItemId(final int id) {
@@ -3002,21 +2965,38 @@
return value[0];
}
- private View getFirstMatch(CellLayout[] cellLayouts, final ItemOperator operator) {
- final View[] value = new View[1];
+ /**
+ * @param cellLayouts List of CellLayouts to scan, in order of preference.
+ * @param operators List of operators, in order starting from best matching operator.
+ * @return
+ */
+ private View getFirstMatch(CellLayout[] cellLayouts, final ItemOperator... operators) {
+ // This array is filled with the first match for each operator.
+ final View[] matches = new View[operators.length];
+ // For efficiency, the outer loop should be CellLayout.
for (CellLayout cellLayout : cellLayouts) {
mapOverCellLayout(MAP_NO_RECURSE, cellLayout, (info, v) -> {
- if (operator.evaluate(info, v)) {
- value[0] = v;
- return true;
+ for (int i = 0; i < operators.length; ++i) {
+ if (matches[i] == null && operators[i].evaluate(info, v)) {
+ matches[i] = v;
+ if (i == 0) {
+ // We can return since this is the best match possible.
+ return true;
+ }
+ }
}
return false;
});
- if (value[0] != null) {
+ if (matches[0] != null) {
break;
}
}
- return value[0];
+ for (View match : matches) {
+ if (match != null) {
+ return match;
+ }
+ }
+ return null;
}
void clearDropTargets() {
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 93bf69d..a4ecec7 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -188,9 +188,12 @@
private void setAlphas(LauncherState toState, AnimationConfig config,
AnimatorSetBuilder builder) {
+ setAlphas(toState.getVisibleElements(mLauncher), config, builder);
+ }
+
+ public void setAlphas(int visibleElements, AnimationConfig config, AnimatorSetBuilder builder) {
PropertySetter setter = config == null ? NO_ANIM_PROPERTY_SETTER
: config.getPropertySetter(builder);
- int visibleElements = toState.getVisibleElements(mLauncher);
boolean hasHeaderExtra = (visibleElements & ALL_APPS_HEADER_EXTRA) != 0;
boolean hasContent = (visibleElements & ALL_APPS_CONTENT) != 0;
diff --git a/src/com/android/launcher3/config/BaseFlags.java b/src/com/android/launcher3/config/BaseFlags.java
index b350767..cb239b3 100644
--- a/src/com/android/launcher3/config/BaseFlags.java
+++ b/src/com/android/launcher3/config/BaseFlags.java
@@ -21,6 +21,9 @@
import android.content.ContentResolver;
import android.content.Context;
import android.content.SharedPreferences;
+import android.database.ContentObserver;
+import android.os.Handler;
+import android.os.Looper;
import android.provider.Settings;
import androidx.annotation.GuardedBy;
@@ -102,7 +105,7 @@
false, "Enable springs for quickstep animations");
public static final TogglableFlag ADAPTIVE_ICON_WINDOW_ANIM = new TogglableFlag(
- "ADAPTIVE_ICON_WINDOW_ANIM", false,
+ "ADAPTIVE_ICON_WINDOW_ANIM", true,
"Use adaptive icons for window animations.");
public static final TogglableFlag ENABLE_QUICKSTEP_LIVE_TILE = new TogglableFlag(
@@ -256,6 +259,16 @@
@Override
public void initialize(Context context) {
contentResolver = context.getContentResolver();
+ contentResolver.registerContentObserver(Settings.Global.getUriFor(getKey()), true,
+ new ContentObserver(new Handler(Looper.getMainLooper())) {
+ @Override
+ public void onChange(boolean selfChange) {
+ superInitialize(context);
+ }});
+ superInitialize(context);
+ }
+
+ private void superInitialize(Context context) {
super.initialize(context);
}
@@ -274,10 +287,5 @@
}
return Settings.Global.getInt(contentResolver, getKey(), defaultValue ? 1 : 0) == 1;
}
-
- @Override
- public boolean get() {
- return getFromStorage(null, getDefaultValue());
- }
}
}
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index 67495ea..71c9148 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -200,6 +200,7 @@
private void setFolder(Folder folder) {
mFolder = folder;
mPreviewVerifier = new FolderIconPreviewVerifier(mLauncher.getDeviceProfile().inv);
+ mPreviewVerifier.setFolderInfo(mFolder.getInfo());
updatePreviewItems(false);
}
diff --git a/src/com/android/launcher3/folder/FolderIconPreviewVerifier.java b/src/com/android/launcher3/folder/FolderIconPreviewVerifier.java
index 5a27cd4..4c84e35 100644
--- a/src/com/android/launcher3/folder/FolderIconPreviewVerifier.java
+++ b/src/com/android/launcher3/folder/FolderIconPreviewVerifier.java
@@ -16,6 +16,8 @@
package com.android.launcher3.folder;
+import android.util.Log;
+
import com.android.launcher3.FolderInfo;
import com.android.launcher3.InvariantDeviceProfile;
@@ -26,14 +28,20 @@
*/
public class FolderIconPreviewVerifier {
+ private static final String TAG = "FolderPreviewVerifier";
+
private final int mMaxGridCountX;
private final int mMaxGridCountY;
private final int mMaxItemsPerPage;
- private final int[] mGridSize = new int[2];
+ private final int[] mGridSize = new int[] { 1, 1 };
+ private int mNumItemsInFolder;
private int mGridCountX;
private boolean mDisplayingUpperLeftQuadrant = false;
+ /**
+ * Note: must call {@link #setFolderInfo(FolderInfo)} manually for verifier to work.
+ */
public FolderIconPreviewVerifier(InvariantDeviceProfile profile) {
mMaxGridCountX = profile.numFolderColumns;
mMaxGridCountY = profile.numFolderRows;
@@ -42,11 +50,14 @@
public void setFolderInfo(FolderInfo info) {
int numItemsInFolder = info.contents.size();
- FolderPagedView.calculateGridSize(numItemsInFolder, 0, 0, mMaxGridCountX,
- mMaxGridCountY, mMaxItemsPerPage, mGridSize);
- mGridCountX = mGridSize[0];
+ if (numItemsInFolder != mNumItemsInFolder) {
+ FolderPagedView.calculateGridSize(numItemsInFolder, 0, 0, mMaxGridCountX,
+ mMaxGridCountY, mMaxItemsPerPage, mGridSize);
+ mGridCountX = mGridSize[0];
- mDisplayingUpperLeftQuadrant = numItemsInFolder > MAX_NUM_ITEMS_IN_PREVIEW;
+ mDisplayingUpperLeftQuadrant = numItemsInFolder > MAX_NUM_ITEMS_IN_PREVIEW;
+ mNumItemsInFolder = numItemsInFolder;
+ }
}
/**
@@ -62,6 +73,10 @@
* @return True iff the icon is in the 2x2 upper left quadrant of the Folder.
*/
public boolean isItemInPreview(int page, int rank) {
+ if (mGridSize[0] == 1) {
+ Log.w(TAG, "setFolderInfo not called before checking if item is in preview.");
+ }
+
// First page items are laid out such that the first 4 items are always in the upper
// left quadrant. For all other pages, we need to check the row and col.
if (page > 0 || mDisplayingUpperLeftQuadrant) {
diff --git a/src/com/android/launcher3/folder/FolderPagedView.java b/src/com/android/launcher3/folder/FolderPagedView.java
index 06eaf38..d4ce6dd 100644
--- a/src/com/android/launcher3/folder/FolderPagedView.java
+++ b/src/com/android/launcher3/folder/FolderPagedView.java
@@ -321,6 +321,7 @@
FolderIconPreviewVerifier verifier = new FolderIconPreviewVerifier(
Launcher.getLauncher(getContext()).getDeviceProfile().inv);
+ verifier.setFolderInfo(mFolder.getInfo());
rank = 0;
for (int i = 0; i < itemCount; i++) {
View v = list.size() > i ? list.get(i) : null;
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index 7275576..2b20b08 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -340,8 +340,6 @@
Intent intent;
String targetPkg;
- FolderIconPreviewVerifier verifier =
- new FolderIconPreviewVerifier(mApp.getInvariantDeviceProfile());
while (!mStopped && c.moveToNext()) {
try {
if (c.user == null) {
@@ -366,13 +364,13 @@
ComponentName cn = intent.getComponent();
targetPkg = cn == null ? intent.getPackage() : cn.getPackageName();
- if (!Process.myUserHandle().equals(c.user)) {
+ if (allUsers.indexOfValue(c.user) < 0) {
if (c.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) {
- c.markDeleted("Legacy shortcuts are only allowed for default user");
+ c.markDeleted("Legacy shortcuts are only allowed for current users");
continue;
} else if (c.restoreFlag != 0) {
// Don't restore items for other profiles.
- c.markDeleted("Restore from managed profile not supported");
+ c.markDeleted("Restore from other profiles not supported");
continue;
}
}
@@ -461,8 +459,7 @@
c.markRestored();
}
- boolean useLowResIcon = !c.isOnWorkspaceOrHotseat() &&
- !verifier.isItemInPreview(c.getInt(rankIndex));
+ boolean useLowResIcon = !c.isOnWorkspaceOrHotseat();
if (c.restoreFlag != 0) {
// Already verified above that user is same as default user
@@ -745,24 +742,25 @@
}
}
+ // Sort the folder items, update ranks, and make sure all preview items are high res.
FolderIconPreviewVerifier verifier =
new FolderIconPreviewVerifier(mApp.getInvariantDeviceProfile());
- // Sort the folder items and make sure all items in the preview are high resolution.
for (FolderInfo folder : mBgDataModel.folders) {
Collections.sort(folder.contents, Folder.ITEM_POS_COMPARATOR);
verifier.setFolderInfo(folder);
+ int size = folder.contents.size();
- int numItemsInPreview = 0;
- for (ShortcutInfo info : folder.contents) {
+ // Update ranks here to ensure there are no gaps caused by removed folder items.
+ // Ranks are the source of truth for folder items, so cellX and cellY can be ignored
+ // for now. Database will be updated once user manually modifies folder.
+ for (int rank = 0; rank < size; ++rank) {
+ ShortcutInfo info = folder.contents.get(rank);
+ info.rank = rank;
+
if (info.usingLowResIcon()
&& info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
&& verifier.isItemInPreview(info.rank)) {
mIconCache.getTitleAndIcon(info, false);
- numItemsInPreview++;
- }
-
- if (numItemsInPreview >= MAX_NUM_ITEMS_IN_PREVIEW) {
- break;
}
}
}
diff --git a/src/com/android/launcher3/provider/RestoreDbTask.java b/src/com/android/launcher3/provider/RestoreDbTask.java
index bcca4d8..040b5e5 100644
--- a/src/com/android/launcher3/provider/RestoreDbTask.java
+++ b/src/com/android/launcher3/provider/RestoreDbTask.java
@@ -18,10 +18,15 @@
import static com.android.launcher3.provider.LauncherDbUtils.dropTable;
+import android.app.backup.BackupManager;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
+import android.os.Build;
+import android.os.UserHandle;
+import android.util.LongSparseArray;
+import android.util.SparseLongArray;
import com.android.launcher3.LauncherAppWidgetInfo;
import com.android.launcher3.LauncherProvider.DatabaseHelper;
@@ -48,10 +53,10 @@
private static final String INFO_COLUMN_NAME = "name";
private static final String INFO_COLUMN_DEFAULT_VALUE = "dflt_value";
- public static boolean performRestore(DatabaseHelper helper) {
+ public static boolean performRestore(DatabaseHelper helper, BackupManager backupManager) {
SQLiteDatabase db = helper.getWritableDatabase();
try (SQLiteTransaction t = new SQLiteTransaction(db)) {
- new RestoreDbTask().sanitizeDB(helper, db);
+ new RestoreDbTask().sanitizeDB(helper, db, backupManager);
t.commit();
return true;
} catch (Exception e) {
@@ -62,20 +67,44 @@
/**
* Makes the following changes in the provider DB.
- * 1. Removes all entries belonging to a managed profile as managed profiles
- * cannot be restored.
+ * 1. Removes all entries belonging to any profiles that were not restored.
* 2. Marks all entries as restored. The flags are updated during first load or as
* the restored apps get installed.
- * 3. If the user serial for primary profile is different than that of the previous device,
- * update the entries to the new profile id.
+ * 3. If the user serial for any restored profile is different than that of the previous
+ * device, update the entries to the new profile id.
*/
- private void sanitizeDB(DatabaseHelper helper, SQLiteDatabase db) throws Exception {
+ private void sanitizeDB(DatabaseHelper helper, SQLiteDatabase db, BackupManager backupManager)
+ throws Exception {
+ // Primary user ids
+ long myProfileId = helper.getDefaultUserSerial();
long oldProfileId = getDefaultProfileId(db);
- // Delete all entries which do not belong to the main user
- int itemsDeleted = db.delete(
- Favorites.TABLE_NAME, "profileId != ?", new String[]{Long.toString(oldProfileId)});
+ LongSparseArray<Long> oldManagedProfileIds = getManagedProfileIds(db, oldProfileId);
+ LongSparseArray<Long> profileMapping = new LongSparseArray<>(oldManagedProfileIds.size()
+ + 1);
+
+ // Build mapping of restored profile ids to their new profile ids.
+ profileMapping.put(oldProfileId, myProfileId);
+ for (int i = oldManagedProfileIds.size() - 1; i >= 0; --i) {
+ long oldManagedProfileId = oldManagedProfileIds.keyAt(i);
+ UserHandle user = getUserForAncestralSerialNumber(backupManager, oldManagedProfileId);
+ if (user != null) {
+ long newManagedProfileId = helper.getSerialNumberForUser(user);
+ profileMapping.put(oldManagedProfileId, newManagedProfileId);
+ }
+ }
+
+ // Delete all entries which do not belong to any restored profile(s).
+ int numProfiles = profileMapping.size();
+ String[] profileIds = new String[numProfiles];
+ profileIds[0] = Long.toString(oldProfileId);
+ StringBuilder whereClause = new StringBuilder("profileId != ?");
+ for (int i = profileMapping.size() - 1; i >= 1; --i) {
+ whereClause.append(" AND profileId != ?");
+ profileIds[i] = Long.toString(profileMapping.keyAt(i));
+ }
+ int itemsDeleted = db.delete(Favorites.TABLE_NAME, whereClause.toString(), profileIds);
if (itemsDeleted > 0) {
- FileLog.d(TAG, itemsDeleted + " items belonging to a managed profile, were deleted");
+ FileLog.d(TAG, itemsDeleted + " items from unrestored user(s) were deleted");
}
// Mark all items as restored.
@@ -85,7 +114,7 @@
| (keepAllIcons ? ShortcutInfo.FLAG_RESTORE_STARTED : 0));
db.update(Favorites.TABLE_NAME, values, null, null);
- // Mark widgets with appropriate restore flag
+ // Mark widgets with appropriate restore flag.
values.put(Favorites.RESTORED, LauncherAppWidgetInfo.FLAG_ID_NOT_VALID |
LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY |
LauncherAppWidgetInfo.FLAG_UI_NOT_READY |
@@ -93,21 +122,46 @@
db.update(Favorites.TABLE_NAME, values, "itemType = ?",
new String[]{Integer.toString(Favorites.ITEM_TYPE_APPWIDGET)});
- long myProfileId = helper.getDefaultUserSerial();
+ // Migrate ids. To avoid any overlap, we initially move conflicting ids to a temp location.
+ // Using Long.MIN_VALUE since profile ids can not be negative, so there will be no overlap.
+ final long tempLocationOffset = Long.MIN_VALUE;
+ SparseLongArray tempMigratedIds = new SparseLongArray(profileMapping.size());
+ int numTempMigrations = 0;
+ for (int i = profileMapping.size() - 1; i >= 0; --i) {
+ long oldId = profileMapping.keyAt(i);
+ long newId = profileMapping.valueAt(i);
+
+ if (oldId != newId) {
+ if (profileMapping.indexOfKey(newId) >= 0) {
+ tempMigratedIds.put(numTempMigrations, newId);
+ numTempMigrations++;
+ newId = tempLocationOffset + newId;
+ }
+ migrateProfileId(db, oldId, newId);
+ }
+ }
+
+ // Migrate ids from their temporary id to their actual final id.
+ for (int i = tempMigratedIds.size() - 1; i >= 0; --i) {
+ long newId = tempMigratedIds.valueAt(i);
+ migrateProfileId(db, tempLocationOffset + newId, newId);
+ }
+
if (myProfileId != oldProfileId) {
- FileLog.d(TAG, "Changing primary user id from " + oldProfileId + " to " + myProfileId);
- migrateProfileId(db, myProfileId);
+ changeDefaultColumn(db, myProfileId);
}
}
/**
- * Updates profile id of all entries and changes the default value for the column.
+ * Updates profile id of all entries from {@param oldProfileId} to {@param newProfileId}.
*/
- protected void migrateProfileId(SQLiteDatabase db, long newProfileId) {
+ protected void migrateProfileId(SQLiteDatabase db, long oldProfileId, long newProfileId) {
+ FileLog.d(TAG, "Changing profile user id from " + oldProfileId + " to " + newProfileId);
// Update existing entries.
ContentValues values = new ContentValues();
values.put(Favorites.PROFILE_ID, newProfileId);
- db.update(Favorites.TABLE_NAME, values, null, null);
+ db.update(Favorites.TABLE_NAME, values, "profileId = ?",
+ new String[]{Long.toString(oldProfileId)});
// Change default value of the column.
db.execSQL("ALTER TABLE favorites RENAME TO favorites_old;");
@@ -116,6 +170,43 @@
dropTable(db, "favorites_old");
}
+
+ /**
+ * Changes the default value for the column.
+ */
+ protected void changeDefaultColumn(SQLiteDatabase db, long newProfileId) {
+ db.execSQL("ALTER TABLE favorites RENAME TO favorites_old;");
+ Favorites.addTableToDb(db, newProfileId, false);
+ db.execSQL("INSERT INTO favorites SELECT * FROM favorites_old;");
+ dropTable(db, "favorites_old");
+ }
+
+ /**
+ * Returns a list of the managed profile id(s) used in the favorites table of the provided db.
+ */
+ private LongSparseArray<Long> getManagedProfileIds(SQLiteDatabase db, long defaultProfileId) {
+ LongSparseArray<Long> ids = new LongSparseArray<>();
+ try (Cursor c = db.rawQuery("SELECT profileId from favorites WHERE profileId != ? "
+ + "GROUP BY profileId", new String[] {Long.toString(defaultProfileId)})){
+ while (c.moveToNext()) {
+ ids.put(c.getLong(c.getColumnIndex(Favorites.PROFILE_ID)), null);
+ }
+ }
+ return ids;
+ }
+
+ /**
+ * Returns a UserHandle of a restored managed profile with the given serial number, or null
+ * if none found.
+ */
+ private UserHandle getUserForAncestralSerialNumber(BackupManager backupManager,
+ long ancestralSerialNumber) {
+ if (Build.VERSION.SDK_INT < 29) {
+ return null;
+ }
+ return backupManager.getUserForAncestralSerialNumber(ancestralSerialNumber);
+ }
+
/**
* Returns the profile id used in the favorites table of the provided db.
*/
diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java
index 23ddd98..ec0462b 100644
--- a/src/com/android/launcher3/views/FloatingIconView.java
+++ b/src/com/android/launcher3/views/FloatingIconView.java
@@ -35,6 +35,7 @@
import android.view.ViewGroup;
import android.view.ViewOutlineProvider;
+import com.android.launcher3.BubbleTextView;
import com.android.launcher3.InsettableFrameLayout.LayoutParams;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.Launcher;
@@ -81,7 +82,7 @@
private final Rect mFinalDrawableBounds = new Rect();
private final Rect mBgDrawableBounds = new Rect();
- private final float mBgDrawableStartScale = 5f; // Magic number that can be tuned later.
+ private float mBgDrawableStartScale = 1f;
private FloatingIconView(Context context) {
super(context);
@@ -188,12 +189,19 @@
private void getIcon(Launcher launcher, View v, ItemInfo info, boolean useDrawableAsIs,
float aspectRatio) {
final LayoutParams lp = (LayoutParams) getLayoutParams();
- mDrawable = Utilities.getFullDrawable(launcher, info, lp.width, lp.height, useDrawableAsIs,
- new Object[1]);
- if (ADAPTIVE_ICON_WINDOW_ANIM.get() && !useDrawableAsIs
- && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
- && mDrawable instanceof AdaptiveIconDrawable) {
+ boolean supportsAdaptiveIcons = ADAPTIVE_ICON_WINDOW_ANIM.get() && !useDrawableAsIs
+ && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O;
+ if (!supportsAdaptiveIcons && v instanceof BubbleTextView) {
+ // Similar to DragView, we simply use the BubbleTextView icon here.
+ mDrawable = ((BubbleTextView) v).getIcon();
+ }
+ if (mDrawable == null) {
+ mDrawable = Utilities.getFullDrawable(launcher, info, lp.width, lp.height,
+ useDrawableAsIs, new Object[1]);
+ }
+
+ if (supportsAdaptiveIcons && mDrawable instanceof AdaptiveIconDrawable) {
mIsAdaptiveIcon = true;
AdaptiveIconDrawable adaptiveIcon = (AdaptiveIconDrawable) mDrawable;
@@ -227,8 +235,9 @@
lp.height = (int) Math.max(lp.height, lp.width * aspectRatio);
layout(lp.leftMargin, lp.topMargin, lp.leftMargin + lp.width, lp.topMargin
+ lp.height);
- setBackgroundDrawableBounds(mBgDrawableStartScale);
}
+ mBgDrawableStartScale = (float) lp.height / mOriginalHeight;
+ setBackgroundDrawableBounds(mBgDrawableStartScale);
// Set up outline
mOutline.set(0, 0, lp.width, lp.height);
@@ -252,6 +261,9 @@
private void setBackgroundDrawableBounds(float scale) {
mBgDrawableBounds.set(mFinalDrawableBounds);
Utilities.scaleRectAboutCenter(mBgDrawableBounds, scale);
+ // Since the drawable is at the top of the view, we need to offset to keep it centered.
+ mBgDrawableBounds.offsetTo(mBgDrawableBounds.left,
+ (int) (mFinalDrawableBounds.top * scale));
mBackground.setBounds(mBgDrawableBounds);
}
diff --git a/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java b/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java
index babb731..6fa8d62 100644
--- a/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java
+++ b/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java
@@ -41,18 +41,34 @@
// Verify item add
assertEquals(5, getCount(db, "select * from favorites where profileId = 42"));
- new RestoreDbTask().migrateProfileId(db, 33);
+ new RestoreDbTask().migrateProfileId(db, 42, 33);
// verify data migrated
assertEquals(0, getCount(db, "select * from favorites where profileId = 42"));
assertEquals(5, getCount(db, "select * from favorites where profileId = 33"));
+ }
+
+ @Test
+ public void testChangeDefaultColumn() throws Exception {
+ SQLiteDatabase db = new MyDatabaseHelper(42).getWritableDatabase();
+ // Add some dummy data
+ for (int i = 0; i < 5; i++) {
+ ContentValues values = new ContentValues();
+ values.put(Favorites._ID, i);
+ values.put(Favorites.TITLE, "item " + i);
+ db.insert(Favorites.TABLE_NAME, null, values);
+ }
+ // Verify default column is 42
+ assertEquals(5, getCount(db, "select * from favorites where profileId = 42"));
+
+ new RestoreDbTask().changeDefaultColumn(db, 33);
// Verify default value changed
ContentValues values = new ContentValues();
values.put(Favorites._ID, 100);
values.put(Favorites.TITLE, "item 100");
db.insert(Favorites.TABLE_NAME, null, values);
- assertEquals(6, getCount(db, "select * from favorites where profileId = 33"));
+ assertEquals(1, getCount(db, "select * from favorites where profileId = 33"));
}
private int getCount(SQLiteDatabase db, String sql) {
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 02f5502..dd768fd 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -98,6 +98,10 @@
}
if (TestHelpers.isInLauncherProcess()) Utilities.enableRunningInTestHarnessForTests();
mLauncher = new LauncherInstrumentation(instrumentation);
+ try {
+ mDevice.executeShellCommand("settings delete secure assistant");
+ } catch (IOException e) {
+ }
}
@Rule
diff --git a/tests/tapl/com/android/launcher3/tapl/AllApps.java b/tests/tapl/com/android/launcher3/tapl/AllApps.java
index 82ea8be..1353a23 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 = 12000;
+ private static final int FLING_SPEED = 3000;
private final int mHeight;
@@ -120,7 +120,7 @@
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, FLING_SPEED);
+ allAppsContainer.fling(Direction.DOWN, (int) (FLING_SPEED * mLauncher.getDisplayDensity()));
verifyActiveContainer();
}
@@ -131,7 +131,7 @@
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, FLING_SPEED);
+ allAppsContainer.fling(Direction.UP, (int) (FLING_SPEED * mLauncher.getDisplayDensity()));
verifyActiveContainer();
}
}
diff --git a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
index 0ff3070..6e92dad 100644
--- a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
+++ b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
@@ -28,7 +28,7 @@
* Common overview pane for both Launcher and fallback recents
*/
public class BaseOverview extends LauncherInstrumentation.VisibleContainer {
- private static final int DEFAULT_FLING_SPEED = 15000;
+ private static final int FLING_SPEED = 1500;
private static final int FLINGS_FOR_DISMISS_LIMIT = 5;
BaseOverview(LauncherInstrumentation launcher) {
@@ -46,7 +46,7 @@
public void flingForward() {
final UiObject2 overview = verifyActiveContainer();
LauncherInstrumentation.log("Overview.flingForward before fling");
- overview.fling(Direction.LEFT, DEFAULT_FLING_SPEED);
+ overview.fling(Direction.LEFT, (int) (FLING_SPEED * mLauncher.getDisplayDensity()));
mLauncher.waitForIdle();
verifyActiveContainer();
}
@@ -73,7 +73,7 @@
public void flingBackward() {
final UiObject2 overview = verifyActiveContainer();
LauncherInstrumentation.log("Overview.flingBackward before fling");
- overview.fling(Direction.RIGHT, DEFAULT_FLING_SPEED);
+ overview.fling(Direction.RIGHT, (int) (FLING_SPEED * mLauncher.getDisplayDensity()));
mLauncher.waitForIdle();
verifyActiveContainer();
}
diff --git a/tests/tapl/com/android/launcher3/tapl/Widgets.java b/tests/tapl/com/android/launcher3/tapl/Widgets.java
index 77555a3..89affd1 100644
--- a/tests/tapl/com/android/launcher3/tapl/Widgets.java
+++ b/tests/tapl/com/android/launcher3/tapl/Widgets.java
@@ -23,7 +23,7 @@
* All widgets container.
*/
public final class Widgets extends LauncherInstrumentation.VisibleContainer {
- private static final int FLING_SPEED = 6000;
+ private static final int FLING_SPEED = 1500;
Widgets(LauncherInstrumentation launcher) {
super(launcher);
@@ -36,7 +36,7 @@
public void flingForward() {
final UiObject2 widgetsContainer = verifyActiveContainer();
widgetsContainer.setGestureMargin(100);
- widgetsContainer.fling(Direction.DOWN, FLING_SPEED);
+ widgetsContainer.fling(Direction.DOWN, (int) (FLING_SPEED * mLauncher.getDisplayDensity()));
verifyActiveContainer();
}
@@ -46,7 +46,7 @@
public void flingBackward() {
final UiObject2 widgetsContainer = verifyActiveContainer();
widgetsContainer.setGestureMargin(100);
- widgetsContainer.fling(Direction.UP, FLING_SPEED);
+ widgetsContainer.fling(Direction.UP, (int) (FLING_SPEED * mLauncher.getDisplayDensity()));
mLauncher.waitForIdle();
verifyActiveContainer();
}