Merge "Prevent the work mode switch thumb from being dragged." into ub-launcher3-master
diff --git a/Android.mk b/Android.mk
index 3945746..ca53fa7 100644
--- a/Android.mk
+++ b/Android.mk
@@ -37,9 +37,8 @@
LOCAL_MODULE_TAGS := optional
LOCAL_STATIC_ANDROID_LIBRARIES := \
- android-support-v4 \
- android-support-v7-recyclerview \
- android-support-dynamic-animation
+ androidx.recyclerview_recyclerview \
+ androidx.dynamicanimation_dynamicanimation
LOCAL_SRC_FILES := \
$(call all-proto-files-under, protos) \
@@ -193,7 +192,8 @@
$(LOCAL_PATH)/quickstep/res \
$(LOCAL_PATH)/go/res
-LOCAL_PROGUARD_ENABLED := disabled
+LOCAL_PROGUARD_FLAG_FILES := proguard.flags
+LOCAL_PROGUARD_ENABLED := full
LOCAL_SDK_VERSION := system_current
LOCAL_MIN_SDK_VERSION := 26
diff --git a/build.gradle b/build.gradle
index 4ae6600..dcb5b81 100644
--- a/build.gradle
+++ b/build.gradle
@@ -4,12 +4,12 @@
google()
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.2.0-alpha12'
- classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.3'
+ classpath 'com.android.tools.build:gradle:3.2.0-beta05'
+ classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.6'
}
}
-final String SUPPORT_LIBS_VERSION = '28.0.0-SNAPSHOT'
+final String SUPPORT_LIBS_VERSION = '1.0.0-alpha1'
apply plugin: 'com.android.application'
apply plugin: 'com.google.protobuf'
@@ -57,6 +57,8 @@
dimension "default"
applicationId 'com.android.launcher3'
testApplicationId 'com.android.launcher3.tests'
+
+ minSdkVersion 28
}
}
@@ -84,7 +86,7 @@
androidTest {
res.srcDirs = ['tests/res']
- java.srcDirs = ['tests/src']
+ java.srcDirs = ['tests/src', 'tests/tapl']
manifest.srcFile "tests/AndroidManifest-common.xml"
}
@@ -118,9 +120,8 @@
}
dependencies {
- implementation "com.android.support:support-v4:${SUPPORT_LIBS_VERSION}"
- implementation "com.android.support:support-dynamic-animation:${SUPPORT_LIBS_VERSION}"
- implementation "com.android.support:recyclerview-v7:${SUPPORT_LIBS_VERSION}"
+ implementation "androidx.dynamicanimation:dynamicanimation:${SUPPORT_LIBS_VERSION}"
+ implementation "androidx.recyclerview:recyclerview:${SUPPORT_LIBS_VERSION}"
implementation 'com.google.protobuf.nano:protobuf-javanano:3.0.0-alpha-7'
quickstepImplementation fileTree(dir: "quickstep/libs", include: 'sysui_shared.jar')
@@ -132,7 +133,7 @@
androidTestImplementation 'com.android.support.test:runner:1.0.0'
androidTestImplementation 'com.android.support.test:rules:1.0.0'
androidTestImplementation 'com.android.support.test.uiautomator:uiautomator-v18:2.1.2'
- androidTestImplementation "com.android.support:support-annotations:${SUPPORT_LIBS_VERSION}"
+ androidTestImplementation "androidx.annotation:annotation:${SUPPORT_LIBS_VERSION}"
}
protobuf {
diff --git a/proguard.flags b/proguard.flags
index ddae07e..a312b91 100644
--- a/proguard.flags
+++ b/proguard.flags
@@ -95,7 +95,7 @@
# next row when focus is on the last item of last row when using a RecyclerView
# Keep optimized and shrunk proguard to prevent issues like this when using
# support jar.
--keep class android.support.v7.widget.RecyclerView { *; }
+-keep class androidx.recyclerview.widget.RecyclerView { *; }
# Preference fragments
-keep class ** extends android.preference.PreferenceFragment {
diff --git a/quickstep/libs/sysui_shared.jar b/quickstep/libs/sysui_shared.jar
index 27de1e9..9d91d7e 100644
--- a/quickstep/libs/sysui_shared.jar
+++ b/quickstep/libs/sysui_shared.jar
Binary files differ
diff --git a/quickstep/res/layout/task_menu.xml b/quickstep/res/layout/task_menu.xml
index bf55ece..098b34f 100644
--- a/quickstep/res/layout/task_menu.xml
+++ b/quickstep/res/layout/task_menu.xml
@@ -24,11 +24,19 @@
android:orientation="vertical"
android:visibility="invisible">
+ <com.android.quickstep.views.IconView
+ android:id="@+id/task_icon"
+ android:layout_width="@dimen/task_thumbnail_icon_size"
+ android:layout_height="@dimen/task_thumbnail_icon_size"
+ android:layout_gravity="top|center_horizontal"
+ android:layout_marginBottom="@dimen/deep_shortcut_drawable_padding"
+ android:focusable="false"
+ android:importantForAccessibility="no" />
+
<TextView
- android:id="@+id/task_icon_and_name"
+ android:id="@+id/task_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:drawablePadding="@dimen/deep_shortcut_drawable_padding"
android:gravity="center_horizontal"
android:layout_marginBottom="16dp"
android:textSize="12sp"/>
diff --git a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
index e346310..78f6ffa 100644
--- a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
+++ b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
@@ -17,7 +17,8 @@
import static com.android.launcher3.Utilities.SINGLE_FRAME_MS;
import static com.android.launcher3.Utilities.postAsyncCallback;
-import static com.android.systemui.shared.recents.utilities.Utilities.postAtFrontOfQueueAsynchronously;
+import static com.android.systemui.shared.recents.utilities.Utilities
+ .postAtFrontOfQueueAsynchronously;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -25,12 +26,13 @@
import android.annotation.TargetApi;
import android.os.Build;
import android.os.Handler;
-import android.support.annotation.BinderThread;
-import android.support.annotation.UiThread;
import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
+import androidx.annotation.BinderThread;
+import androidx.annotation.UiThread;
+
@TargetApi(Build.VERSION_CODES.P)
public abstract class LauncherAnimationRunner implements RemoteAnimationRunnerCompat {
diff --git a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
index 14633af..37d0b12 100644
--- a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
+++ b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
@@ -537,6 +537,9 @@
@Override
public void onAnimationEnd(Animator animation) {
// Reset launcher to normal state
+ if (isBubbleTextView) {
+ ((BubbleTextView) v).setStayPressed(false);
+ }
v.setVisibility(View.VISIBLE);
((ViewGroup) mDragLayer.getParent()).removeView(mFloatingView);
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/BackButtonAlphaHandler.java b/quickstep/src/com/android/launcher3/uioverrides/BackButtonAlphaHandler.java
index 722f51b..693ae60 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/BackButtonAlphaHandler.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/BackButtonAlphaHandler.java
@@ -35,7 +35,7 @@
public BackButtonAlphaHandler(Launcher launcher) {
mLauncher = launcher;
- mOverviewInteractionState = OverviewInteractionState.getInstance(mLauncher);
+ mOverviewInteractionState = OverviewInteractionState.INSTANCE.get(mLauncher);
}
@Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/LandscapeEdgeSwipeController.java b/quickstep/src/com/android/launcher3/uioverrides/LandscapeEdgeSwipeController.java
index 6d10619..fd4bf9b 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/LandscapeEdgeSwipeController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/LandscapeEdgeSwipeController.java
@@ -73,7 +73,7 @@
protected void onSwipeInteractionCompleted(LauncherState targetState, int logAction) {
super.onSwipeInteractionCompleted(targetState, logAction);
if (mStartState == NORMAL && targetState == OVERVIEW) {
- RecentsModel.getInstance(mLauncher).onOverviewShown(true, TAG);
+ RecentsModel.INSTANCE.get(mLauncher).onOverviewShown(true, TAG);
}
}
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
index 7f956f8..25b5f57 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
@@ -31,6 +31,7 @@
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.quickstep.RecentsModel;
import com.android.quickstep.views.RecentsView;
+import com.android.quickstep.views.TaskView;
/**
* Definition for overview state
@@ -77,7 +78,7 @@
public void onStateDisabled(Launcher launcher) {
RecentsView rv = launcher.getOverviewPanel();
rv.setOverviewStateEnabled(false);
- RecentsModel.getInstance(launcher).resetAssistCache();
+ RecentsModel.INSTANCE.get(launcher).resetAssistCache();
}
@Override
@@ -130,4 +131,14 @@
DeviceProfile dp = launcher.getDeviceProfile();
return dp.allAppsCellHeightPx - dp.allAppsIconTextSizePx;
}
+
+ @Override
+ public void onBackPressed(Launcher launcher) {
+ TaskView taskView = launcher.<RecentsView>getOverviewPanel().getRunningTaskView();
+ if (taskView != null) {
+ taskView.launchTask(true);
+ } else {
+ super.onBackPressed(launcher);
+ }
+ }
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/PortraitStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/PortraitStatesTouchController.java
index 1d1b7da..a1ae99e 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/PortraitStatesTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/PortraitStatesTouchController.java
@@ -256,7 +256,7 @@
protected void onSwipeInteractionCompleted(LauncherState targetState, int logAction) {
super.onSwipeInteractionCompleted(targetState, logAction);
if (mStartState == NORMAL && targetState == OVERVIEW) {
- RecentsModel.getInstance(mLauncher).onOverviewShown(true, TAG);
+ RecentsModel.INSTANCE.get(mLauncher).onOverviewShown(true, TAG);
}
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/TaskViewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/TaskViewTouchController.java
index 9a920c8..88f2315 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/TaskViewTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/TaskViewTouchController.java
@@ -121,7 +121,7 @@
if (mRecentsView.isTaskViewVisible(view) && mActivity.getDragLayer()
.isEventOverView(view, ev)) {
mTaskBeingDragged = view;
- if (!OverviewInteractionState.getInstance(mActivity)
+ if (!OverviewInteractionState.INSTANCE.get(mActivity)
.isSwipeUpGestureEnabled()) {
// Don't allow swipe down to open if we don't support swipe up
// to enter overview.
diff --git a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
index ac9f863..c939330 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
@@ -57,7 +57,7 @@
public class UiFactory {
public static TouchController[] createTouchControllers(Launcher launcher) {
- boolean swipeUpEnabled = OverviewInteractionState.getInstance(launcher)
+ boolean swipeUpEnabled = OverviewInteractionState.INSTANCE.get(launcher)
.isSwipeUpGestureEnabled();
if (!swipeUpEnabled) {
return new TouchController[] {
@@ -80,7 +80,7 @@
}
public static void setOnTouchControllersChangedListener(Context context, Runnable listener) {
- OverviewInteractionState.getInstance(context).setOnSwipeUpSettingChangedListener(listener);
+ OverviewInteractionState.INSTANCE.get(context).setOnSwipeUpSettingChangedListener(listener);
}
public static StateHandler[] getStateHandler(Launcher launcher) {
@@ -100,7 +100,7 @@
shouldBackButtonBeHidden = AbstractFloatingView.getTopOpenViewWithType(launcher,
TYPE_ALL & ~TYPE_HIDE_BACK_BUTTON) == null;
}
- OverviewInteractionState.getInstance(launcher)
+ OverviewInteractionState.INSTANCE.get(launcher)
.setBackButtonAlpha(shouldBackButtonBeHidden ? 0 : 1, true /* animate */);
}
@@ -122,7 +122,7 @@
@Override
public void onStateTransitionComplete(LauncherState finalState) {
- boolean swipeUpEnabled = OverviewInteractionState.getInstance(launcher)
+ boolean swipeUpEnabled = OverviewInteractionState.INSTANCE.get(launcher)
.isSwipeUpGestureEnabled();
LauncherState prevState = launcher.getStateManager().getLastState();
@@ -159,19 +159,29 @@
}
public static void onStart(Context context) {
- RecentsModel model = RecentsModel.getInstance(context);
+ RecentsModel model = RecentsModel.INSTANCE.get(context);
if (model != null) {
model.onStart();
}
}
+ public static void onEnterAnimationComplete(Context context) {
+ // After the transition to home, enable the high-res thumbnail loader if it wasn't enabled
+ // as a part of quickstep/scrub, so that high-res thumbnails can load the next time we
+ // enter overview
+ RecentsModel.INSTANCE.get(context).getRecentsTaskLoader()
+ .getHighResThumbnailLoader().setVisible(true);
+ }
+
public static void onLauncherStateOrResumeChanged(Launcher launcher) {
LauncherState state = launcher.getStateManager().getState();
- DeviceProfile profile = launcher.getDeviceProfile();
- WindowManagerWrapper.getInstance().setShelfHeight(
- (state == NORMAL || state == OVERVIEW) && launcher.isUserActive()
- && !profile.isVerticalBarLayout(),
- profile.hotseatBarSizePx);
+ if (!OverviewInteractionState.INSTANCE.get(launcher).swipeGestureInitializing()) {
+ DeviceProfile profile = launcher.getDeviceProfile();
+ WindowManagerWrapper.getInstance().setShelfHeight(
+ (state == NORMAL || state == OVERVIEW) && launcher.isUserActive()
+ && !profile.isVerticalBarLayout(),
+ profile.hotseatBarSizePx);
+ }
if (state == NORMAL) {
launcher.<RecentsView>getOverviewPanel().setSwipeDownShouldLaunchApp(false);
@@ -179,7 +189,7 @@
}
public static void onTrimMemory(Context context, int level) {
- RecentsModel model = RecentsModel.getInstance(context);
+ RecentsModel model = RecentsModel.INSTANCE.get(context);
if (model != null) {
model.onTrimMemory(level);
}
diff --git a/quickstep/src/com/android/quickstep/ActivityControlHelper.java b/quickstep/src/com/android/quickstep/ActivityControlHelper.java
index d37ac49..322e270 100644
--- a/quickstep/src/com/android/quickstep/ActivityControlHelper.java
+++ b/quickstep/src/com/android/quickstep/ActivityControlHelper.java
@@ -42,8 +42,6 @@
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
-import android.support.annotation.Nullable;
-import android.support.annotation.UiThread;
import android.view.View;
import com.android.launcher3.BaseDraggingActivity;
@@ -53,10 +51,12 @@
import com.android.launcher3.LauncherInitListener;
import com.android.launcher3.LauncherState;
import com.android.launcher3.R;
+import com.android.launcher3.TestProtocol;
import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.allapps.DiscoveryBounce;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
+import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.uioverrides.FastOverviewState;
import com.android.launcher3.userevent.nano.LauncherLogProto;
@@ -76,6 +76,9 @@
import java.util.function.BiPredicate;
import java.util.function.Consumer;
+import androidx.annotation.Nullable;
+import androidx.annotation.UiThread;
+
/**
* Utility class which abstracts out the logical differences between Launcher and RecentsActivity.
*/
@@ -230,6 +233,9 @@
// Optimization, hide the all apps view to prevent layout while initializing
activity.getAppsView().getContentView().setVisibility(View.GONE);
+
+ AccessibilityManagerCompat.sendEventToTest(
+ activity, TestProtocol.SWITCHED_TO_STATE_MESSAGE);
}
return new AnimationFactory() {
@@ -299,6 +305,9 @@
private void playScaleDownAnim(AnimatorSet anim, Launcher launcher) {
RecentsView recentsView = launcher.getOverviewPanel();
TaskView v = recentsView.getTaskViewAt(recentsView.getCurrentPage());
+ if (v == null) {
+ return;
+ }
ClipAnimationHelper clipHelper = new ClipAnimationHelper();
clipHelper.fromTaskThumbnailView(v.getThumbnail(), (RecentsView) v.getParent(), null);
if (!clipHelper.getSourceRect().isEmpty() && !clipHelper.getTargetRect().isEmpty()) {
diff --git a/quickstep/src/com/android/quickstep/NormalizedIconLoader.java b/quickstep/src/com/android/quickstep/NormalizedIconLoader.java
index f875bb7..a4a2e56 100644
--- a/quickstep/src/com/android/quickstep/NormalizedIconLoader.java
+++ b/quickstep/src/com/android/quickstep/NormalizedIconLoader.java
@@ -42,12 +42,15 @@
private final SparseArray<BitmapInfo> mDefaultIcons = new SparseArray<>();
private final DrawableFactory mDrawableFactory;
+ private final boolean mDisableColorExtraction;
private LauncherIcons mLauncherIcons;
public NormalizedIconLoader(Context context, TaskKeyLruCache<Drawable> iconCache,
- LruCache<ComponentName, ActivityInfo> activityInfoCache) {
+ LruCache<ComponentName, ActivityInfo> activityInfoCache,
+ boolean disableColorExtraction) {
super(context, iconCache, activityInfoCache);
mDrawableFactory = DrawableFactory.get(context);
+ mDisableColorExtraction = disableColorExtraction;
}
@Override
@@ -74,6 +77,9 @@
int primaryColor, boolean isInstantApp) {
if (mLauncherIcons == null) {
mLauncherIcons = LauncherIcons.obtain(mContext);
+ if (mDisableColorExtraction) {
+ mLauncherIcons.disableColorExtraction();
+ }
}
mLauncherIcons.setWrapperBackgroundColor(primaryColor);
diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
index 7c6eb32..3d54b82 100644
--- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
+++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
@@ -111,7 +111,7 @@
mContext = context;
mAM = ActivityManagerWrapper.getInstance();
mMainThreadExecutor = new MainThreadExecutor();
- mRecentsModel = RecentsModel.getInstance(mContext);
+ mRecentsModel = RecentsModel.INSTANCE.get(mContext);
Intent myHomeIntent = new Intent(Intent.ACTION_MAIN)
.addCategory(Intent.CATEGORY_HOME)
diff --git a/quickstep/src/com/android/quickstep/OverviewInteractionState.java b/quickstep/src/com/android/quickstep/OverviewInteractionState.java
index 922a7ff..d71c08a 100644
--- a/quickstep/src/com/android/quickstep/OverviewInteractionState.java
+++ b/quickstep/src/com/android/quickstep/OverviewInteractionState.java
@@ -22,23 +22,20 @@
import android.content.ContentResolver;
import android.content.Context;
-import android.content.res.Resources;
import android.database.ContentObserver;
import android.os.Handler;
-import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.provider.Settings;
-import android.support.annotation.WorkerThread;
import android.util.Log;
-import com.android.launcher3.MainThreadExecutor;
import com.android.launcher3.Utilities;
import com.android.launcher3.allapps.DiscoveryBounce;
+import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.UiThreadHelper;
import com.android.systemui.shared.recents.ISystemUiProxy;
-import java.util.concurrent.ExecutionException;
+import androidx.annotation.WorkerThread;
/**
* Sets overview interaction flags, such as:
@@ -54,29 +51,10 @@
private static final String TAG = "OverviewFlags";
private static final String HAS_ENABLED_QUICKSTEP_ONCE = "launcher.has_enabled_quickstep_once";
- private static final String SWIPE_UP_SETTING_AVAILABLE_RES_NAME =
- "config_swipe_up_gesture_setting_available";
- private static final String SWIPE_UP_ENABLED_DEFAULT_RES_NAME =
- "config_swipe_up_gesture_default";
// We do not need any synchronization for this variable as its only written on UI thread.
- private static OverviewInteractionState INSTANCE;
-
- public static OverviewInteractionState getInstance(final Context context) {
- if (INSTANCE == null) {
- if (Looper.myLooper() == Looper.getMainLooper()) {
- INSTANCE = new OverviewInteractionState(context.getApplicationContext());
- } else {
- try {
- return new MainThreadExecutor().submit(
- () -> OverviewInteractionState.getInstance(context)).get();
- } catch (InterruptedException|ExecutionException e) {
- throw new RuntimeException(e);
- }
- }
- }
- return INSTANCE;
- }
+ public static final MainThreadInitializedObject<OverviewInteractionState> INSTANCE =
+ new MainThreadInitializedObject<>((c) -> new OverviewInteractionState(c));
private static final int MSG_SET_PROXY = 200;
private static final int MSG_SET_BACK_BUTTON_ALPHA = 201;
@@ -88,6 +66,8 @@
private final Handler mUiHandler;
private final Handler mBgHandler;
+ private boolean mSwipeGestureInitializing = false;
+
// These are updated on the background thread
private ISystemUiProxy mISystemUiProxy;
private boolean mSwipeUpEnabled = true;
@@ -104,13 +84,13 @@
mUiHandler = new Handler(this::handleUiMessage);
mBgHandler = new Handler(UiThreadHelper.getBackgroundLooper(), this::handleBgMessage);
- if (getSystemBooleanRes(SWIPE_UP_SETTING_AVAILABLE_RES_NAME)) {
+ if (SwipeUpSetting.isSwipeUpSettingAvailable()) {
mSwipeUpSettingObserver = new SwipeUpGestureEnabledSettingObserver(mUiHandler,
context.getContentResolver());
mSwipeUpSettingObserver.register();
} else {
mSwipeUpSettingObserver = null;
- mSwipeUpEnabled = getSystemBooleanRes(SWIPE_UP_ENABLED_DEFAULT_RES_NAME);
+ mSwipeUpEnabled = SwipeUpSetting.isSwipeUpEnabledDefaultValue();
}
}
@@ -197,16 +177,29 @@
}
}
+ @WorkerThread
+ public void setSwipeGestureInitializing(boolean swipeGestureInitializing) {
+ mSwipeGestureInitializing = swipeGestureInitializing;
+ }
+
+ public boolean swipeGestureInitializing() {
+ return mSwipeGestureInitializing;
+ }
+
+ public void notifySwipeUpSettingChanged(boolean swipeUpEnabled) {
+ mUiHandler.removeMessages(MSG_SET_SWIPE_UP_ENABLED);
+ mUiHandler.obtainMessage(MSG_SET_SWIPE_UP_ENABLED, swipeUpEnabled ? 1 : 0, 0).
+ sendToTarget();
+ }
+
private class SwipeUpGestureEnabledSettingObserver extends ContentObserver {
- private Handler mHandler;
private ContentResolver mResolver;
private final int defaultValue;
SwipeUpGestureEnabledSettingObserver(Handler handler, ContentResolver resolver) {
super(handler);
- mHandler = handler;
mResolver = resolver;
- defaultValue = getSystemBooleanRes(SWIPE_UP_ENABLED_DEFAULT_RES_NAME) ? 1 : 0;
+ defaultValue = SwipeUpSetting.isSwipeUpEnabledDefaultValue() ? 1 : 0;
}
public void register() {
@@ -219,8 +212,7 @@
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
- mHandler.removeMessages(MSG_SET_SWIPE_UP_ENABLED);
- mHandler.obtainMessage(MSG_SET_SWIPE_UP_ENABLED, getValue() ? 1 : 0, 0).sendToTarget();
+ notifySwipeUpSettingChanged(getValue());
}
private boolean getValue() {
@@ -228,18 +220,6 @@
}
}
- private 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;
- }
- }
-
private void resetHomeBounceSeenOnQuickstepEnabledFirstTime() {
if (mSwipeUpEnabled && !Utilities.getPrefs(mContext).getBoolean(
HAS_ENABLED_QUICKSTEP_ONCE, true)) {
diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
index 32079bf..b93a54b 100644
--- a/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -232,6 +232,12 @@
}
@Override
+ public void onEnterAnimationComplete() {
+ super.onEnterAnimationComplete();
+ UiFactory.onEnterAnimationComplete(this);
+ }
+
+ @Override
public void onTrimMemory(int level) {
super.onTrimMemory(level);
UiFactory.onTrimMemory(this, level);
diff --git a/quickstep/src/com/android/quickstep/RecentsModel.java b/quickstep/src/com/android/quickstep/RecentsModel.java
index 0c8e47f..196f0cc 100644
--- a/quickstep/src/com/android/quickstep/RecentsModel.java
+++ b/quickstep/src/com/android/quickstep/RecentsModel.java
@@ -27,10 +27,8 @@
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
-import android.os.Looper;
import android.os.RemoteException;
import android.os.UserHandle;
-import android.support.annotation.WorkerThread;
import android.util.Log;
import android.util.LruCache;
import android.util.SparseArray;
@@ -38,6 +36,7 @@
import com.android.launcher3.MainThreadExecutor;
import com.android.launcher3.R;
+import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.Preconditions;
import com.android.systemui.shared.recents.ISystemUiProxy;
import com.android.systemui.shared.recents.model.IconLoader;
@@ -50,32 +49,18 @@
import com.android.systemui.shared.system.TaskStackChangeListener;
import java.util.ArrayList;
-import java.util.concurrent.ExecutionException;
import java.util.function.Consumer;
+import androidx.annotation.WorkerThread;
+
/**
* Singleton class to load and manage recents model.
*/
@TargetApi(Build.VERSION_CODES.O)
public class RecentsModel extends TaskStackChangeListener {
// We do not need any synchronization for this variable as its only written on UI thread.
- private static RecentsModel INSTANCE;
-
- public static RecentsModel getInstance(final Context context) {
- if (INSTANCE == null) {
- if (Looper.myLooper() == Looper.getMainLooper()) {
- INSTANCE = new RecentsModel(context.getApplicationContext());
- } else {
- try {
- return new MainThreadExecutor().submit(
- () -> RecentsModel.getInstance(context)).get();
- } catch (InterruptedException|ExecutionException e) {
- throw new RuntimeException(e);
- }
- }
- }
- return INSTANCE;
- }
+ public static final MainThreadInitializedObject<RecentsModel> INSTANCE =
+ new MainThreadInitializedObject<>(c -> new RecentsModel(c));
private final SparseArray<Bundle> mCachedAssistData = new SparseArray<>(1);
private final ArrayList<AssistDataListener> mAssistDataListeners = new ArrayList<>();
@@ -110,7 +95,9 @@
protected IconLoader createNewIconLoader(Context context,
TaskKeyLruCache<Drawable> iconCache,
LruCache<ComponentName, ActivityInfo> activityInfoCache) {
- return new NormalizedIconLoader(context, iconCache, activityInfoCache);
+ // Disable finding the dominant color since we don't need to use it
+ return new NormalizedIconLoader(context, iconCache, activityInfoCache,
+ true /* disableColorExtraction */);
}
};
mRecentsTaskLoader.startLoader(mContext);
@@ -232,7 +219,6 @@
public void onStart() {
mRecentsTaskLoader.startLoader(mContext);
- mRecentsTaskLoader.getHighResThumbnailLoader().setVisible(true);
}
public void onTrimMemory(int level) {
diff --git a/quickstep/src/com/android/quickstep/SwipeUpSetting.java b/quickstep/src/com/android/quickstep/SwipeUpSetting.java
new file mode 100644
index 0000000..0f91f97
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/SwipeUpSetting.java
@@ -0,0 +1,50 @@
+/*
+ * 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";
+
+ private static final String SWIPE_UP_ENABLED_DEFAULT_RES_NAME =
+ "config_swipe_up_gesture_default";
+
+ 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;
+ }
+ }
+
+ public static boolean isSwipeUpSettingAvailable() {
+ return getSystemBooleanRes(SWIPE_UP_SETTING_AVAILABLE_RES_NAME);
+ }
+
+ public static boolean isSwipeUpEnabledDefaultValue() {
+ return getSystemBooleanRes(SWIPE_UP_ENABLED_DEFAULT_RES_NAME);
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
index c272b1a..7289516 100644
--- a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
@@ -18,7 +18,6 @@
import android.content.Context;
import android.graphics.Matrix;
-import android.support.annotation.AnyThread;
import android.view.View;
import com.android.launcher3.R;
@@ -27,6 +26,8 @@
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData;
+import androidx.annotation.AnyThread;
+
/**
* Factory class to create and add an overlays on the TaskView
*/
diff --git a/quickstep/src/com/android/quickstep/TaskSystemShortcut.java b/quickstep/src/com/android/quickstep/TaskSystemShortcut.java
index d9da002..e64d04a 100644
--- a/quickstep/src/com/android/quickstep/TaskSystemShortcut.java
+++ b/quickstep/src/com/android/quickstep/TaskSystemShortcut.java
@@ -30,7 +30,6 @@
import android.util.Log;
import android.view.View;
-import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.ItemInfo;
@@ -161,7 +160,7 @@
boolean dockTopOrLeft = navBarPosition != WindowManagerWrapper.NAV_BAR_POS_LEFT;
if (ActivityManagerWrapper.getInstance().startActivityFromRecents(taskId,
ActivityOptionsCompat.makeSplitScreenOptions(dockTopOrLeft))) {
- ISystemUiProxy sysUiProxy = RecentsModel.getInstance(activity).getSystemUiProxy();
+ ISystemUiProxy sysUiProxy = RecentsModel.INSTANCE.get(activity).getSystemUiProxy();
try {
sysUiProxy.onSplitScreenInvoked();
} catch (RemoteException e) {
@@ -226,7 +225,7 @@
@Override
public View.OnClickListener getOnClickListener(
BaseDraggingActivity activity, TaskView taskView) {
- ISystemUiProxy sysUiProxy = RecentsModel.getInstance(activity).getSystemUiProxy();
+ ISystemUiProxy sysUiProxy = RecentsModel.INSTANCE.get(activity).getSystemUiProxy();
if (sysUiProxy == null) {
return null;
}
@@ -270,9 +269,4 @@
return null;
}
}
-
- private static void dismissTaskMenuView(BaseDraggingActivity activity) {
- AbstractFloatingView.closeOpenViews(activity, true,
- AbstractFloatingView.TYPE_ALL & ~AbstractFloatingView.TYPE_REBIND_SAFE);
- }
}
diff --git a/quickstep/src/com/android/quickstep/TaskUtils.java b/quickstep/src/com/android/quickstep/TaskUtils.java
index f9b5e30..5cae2b9 100644
--- a/quickstep/src/com/android/quickstep/TaskUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskUtils.java
@@ -18,8 +18,6 @@
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR;
-import static com.android.systemui.shared.recents.utilities.Utilities.getNextFrameNumber;
-import static com.android.systemui.shared.recents.utilities.Utilities.getSurface;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING;
import android.animation.ValueAnimator;
@@ -30,7 +28,6 @@
import android.graphics.RectF;
import android.os.UserHandle;
import android.util.Log;
-import android.view.Surface;
import android.view.View;
import com.android.launcher3.BaseDraggingActivity;
@@ -92,10 +89,11 @@
*/
public static TaskView findTaskViewToLaunch(
BaseDraggingActivity activity, View v, RemoteAnimationTargetCompat[] targets) {
- if (v instanceof TaskView) {
- return (TaskView) v;
- }
RecentsView recentsView = activity.getOverviewPanel();
+ if (v instanceof TaskView) {
+ TaskView taskView = (TaskView) v;
+ return recentsView.isTaskViewVisible(taskView) ? taskView : null;
+ }
// It's possible that the launched view can still be resolved to a visible task view, check
// the task id of the opening task and see if we can find a match.
diff --git a/quickstep/src/com/android/quickstep/TouchConsumer.java b/quickstep/src/com/android/quickstep/TouchConsumer.java
index 42e9aee..646fc57 100644
--- a/quickstep/src/com/android/quickstep/TouchConsumer.java
+++ b/quickstep/src/com/android/quickstep/TouchConsumer.java
@@ -17,7 +17,6 @@
import android.annotation.TargetApi;
import android.os.Build;
-import android.support.annotation.IntDef;
import android.view.Choreographer;
import android.view.MotionEvent;
@@ -25,6 +24,8 @@
import java.lang.annotation.RetentionPolicy;
import java.util.function.Consumer;
+import androidx.annotation.IntDef;
+
@TargetApi(Build.VERSION_CODES.O)
@FunctionalInterface
public interface TouchConsumer extends Consumer<MotionEvent> {
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 5a1f523..bd79301 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -90,7 +90,14 @@
public void onMotionEvent(MotionEvent ev) {
mEventQueue.queue(ev);
- String name = sMotionEventNames.get(ev.getActionMasked());
+ int action = ev.getActionMasked();
+ if (action == ACTION_DOWN) {
+ mOverviewInteractionState.setSwipeGestureInitializing(true);
+ } else if (action == ACTION_UP || action == ACTION_CANCEL) {
+ mOverviewInteractionState.setSwipeGestureInitializing(false);
+ }
+
+ String name = sMotionEventNames.get(action);
if (name != null){
TraceHelper.partitionSection("SysUiBinder", name);
}
@@ -106,6 +113,7 @@
@Override
public void onQuickScrubStart() {
mEventQueue.onQuickScrubStart();
+ mOverviewInteractionState.setSwipeGestureInitializing(false);
TraceHelper.partitionSection("SysUiBinder", "onQuickScrubStart");
}
@@ -146,8 +154,8 @@
@Override
public void onQuickStep(MotionEvent motionEvent) {
mEventQueue.onQuickStep(motionEvent);
+ mOverviewInteractionState.setSwipeGestureInitializing(false);
TraceHelper.endSection("SysUiBinder", "onQuickStep");
-
}
@Override
@@ -179,13 +187,13 @@
public void onCreate() {
super.onCreate();
mAM = ActivityManagerWrapper.getInstance();
- mRecentsModel = RecentsModel.getInstance(this);
+ mRecentsModel = RecentsModel.INSTANCE.get(this);
mRecentsModel.setPreloadTasksInBackground(true);
mMainThreadExecutor = new MainThreadExecutor();
mOverviewCommandHelper = new OverviewCommandHelper(this);
mMainThreadChoreographer = Choreographer.getInstance();
mEventQueue = new MotionEventQueue(mMainThreadChoreographer, TouchConsumer.NO_OP);
- mOverviewInteractionState = OverviewInteractionState.getInstance(this);
+ mOverviewInteractionState = OverviewInteractionState.INSTANCE.get(this);
mOverviewCallbacks = OverviewCallbacks.get(this);
mTaskOverlayFactory = TaskOverlayFactory.get(this);
diff --git a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
index d3d38af..66655bd 100644
--- a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
@@ -43,9 +43,6 @@
import android.os.Looper;
import android.os.SystemClock;
import android.os.UserHandle;
-import android.support.annotation.AnyThread;
-import android.support.annotation.UiThread;
-import android.support.annotation.WorkerThread;
import android.util.Log;
import android.view.HapticFeedbackConstants;
import android.view.View;
@@ -86,11 +83,14 @@
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplier;
import com.android.systemui.shared.system.WindowCallbacksCompat;
-import com.android.systemui.shared.system.WindowManagerWrapper;
import java.util.StringJoiner;
import java.util.function.BiFunction;
+import androidx.annotation.AnyThread;
+import androidx.annotation.UiThread;
+import androidx.annotation.WorkerThread;
+
@TargetApi(Build.VERSION_CODES.O)
public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> {
private static final String TAG = WindowTransformSwipeHandler.class.getSimpleName();
@@ -256,6 +256,11 @@
}
};
+ // Re-setup the recents UI when gesture starts, as the state could have been changed during
+ // that time by a previous window transition.
+ mStateCallback.addCallback(STATE_LAUNCHER_STARTED | STATE_GESTURE_STARTED_QUICKSTEP,
+ this::setupRecentsViewUi);
+
mStateCallback.addCallback(STATE_LAUNCHER_DRAWN | STATE_GESTURE_STARTED_QUICKSCRUB,
this::initializeLauncherAnimationController);
mStateCallback.addCallback(STATE_LAUNCHER_DRAWN | STATE_GESTURE_STARTED_QUICKSTEP,
@@ -429,11 +434,15 @@
});
}
+ setupRecentsViewUi();
+ mLayoutListener.open();
+ mStateCallback.setState(STATE_LAUNCHER_STARTED);
+ }
+
+ private void setupRecentsViewUi() {
mRecentsView.showTask(mRunningTaskId);
mRecentsView.setRunningTaskHidden(true);
mRecentsView.setRunningTaskIconScaledDown(true);
- mLayoutListener.open();
- mStateCallback.setState(STATE_LAUNCHER_STARTED);
}
public void setLauncherOnDrawCallback(Runnable callback) {
@@ -477,6 +486,12 @@
if (LatencyTrackerCompat.isEnabled(mContext)) {
LatencyTrackerCompat.logToggleRecents((int) (mLauncherFrameDrawnTime - mTouchTimeMs));
}
+
+ // This method is only called when STATE_GESTURE_STARTED_QUICKSTEP/
+ // STATE_GESTURE_STARTED_QUICKSCRUB is set, so we can enable the high-res thumbnail loader
+ // here once we are sure that we will end up in an overview state
+ RecentsModel.INSTANCE.get(mContext).getRecentsTaskLoader()
+ .getHighResThumbnailLoader().setVisible(true);
}
public void updateInteractionType(@InteractionType int interactionType) {
@@ -626,10 +641,8 @@
overviewStackBounds = new Rect(0, 0, dp.widthPx, dp.heightPx);
}
// If we are not in multi-window mode, home insets should be same as system insets.
- Rect insets = new Rect();
- WindowManagerWrapper.getInstance().getStableInsets(insets);
dp = dp.copy(mContext);
- dp.updateInsets(insets);
+ dp.updateInsets(homeContentInsets);
}
dp.updateIsSeascape(mContext.getSystemService(WindowManager.class));
@@ -934,7 +947,7 @@
mRecentsView.animateUpRunningTaskIconScale();
mRecentsView.setSwipeDownShouldLaunchApp(true);
- RecentsModel.getInstance(mContext).onOverviewShown(false, TAG);
+ RecentsModel.INSTANCE.get(mContext).onOverviewShown(false, TAG);
doLogGesture(true /* toLauncher */);
reset();
@@ -964,7 +977,7 @@
mQuickScrubController.onFinishedTransitionToQuickScrub();
mRecentsView.animateUpRunningTaskIconScale();
- RecentsModel.getInstance(mContext).onOverviewShown(false, TAG);
+ RecentsModel.INSTANCE.get(mContext).onOverviewShown(false, TAG);
}
public void onQuickScrubProgress(float progress) {
@@ -1098,7 +1111,7 @@
}
private void preloadAssistData() {
- RecentsModel.getInstance(mContext).preloadAssistData(mRunningTaskId, mAssistData);
+ RecentsModel.INSTANCE.get(mContext).preloadAssistData(mRunningTaskId, mAssistData);
}
public static float getHiddenTargetAlpha(RemoteAnimationTargetCompat app, Float expectedAlpha) {
diff --git a/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java b/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java
index df70a8a..c3ce439 100644
--- a/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java
+++ b/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java
@@ -29,8 +29,6 @@
import android.graphics.RectF;
import android.os.Build;
import android.os.RemoteException;
-import android.support.annotation.Nullable;
-import android.view.Surface;
import android.view.animation.Interpolator;
import com.android.launcher3.BaseDraggingActivity;
@@ -50,9 +48,10 @@
import com.android.systemui.shared.system.TransactionCompat;
import com.android.systemui.shared.system.WindowManagerWrapper;
-import java.util.function.BiConsumer;
import java.util.function.BiFunction;
+import androidx.annotation.Nullable;
+
/**
* Utility class to handle window clip animation
*/
@@ -260,7 +259,7 @@
}
private void updateStackBoundsToMultiWindowTaskSize(BaseDraggingActivity activity) {
- ISystemUiProxy sysUiProxy = RecentsModel.getInstance(activity).getSystemUiProxy();
+ ISystemUiProxy sysUiProxy = RecentsModel.INSTANCE.get(activity).getSystemUiProxy();
if (sysUiProxy != null) {
try {
mSourceStackBounds.set(sysUiProxy.getNonMinimizedSplitScreenSecondaryBounds());
diff --git a/quickstep/src/com/android/quickstep/util/LayoutUtils.java b/quickstep/src/com/android/quickstep/util/LayoutUtils.java
index ec9c7ea..7715f35 100644
--- a/quickstep/src/com/android/quickstep/util/LayoutUtils.java
+++ b/quickstep/src/com/android/quickstep/util/LayoutUtils.java
@@ -20,14 +20,15 @@
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Rect;
-import android.support.annotation.AnyThread;
-import android.support.annotation.IntDef;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import java.lang.annotation.Retention;
+import androidx.annotation.AnyThread;
+import androidx.annotation.IntDef;
+
public class LayoutUtils {
private static final int MULTI_WINDOW_STRATEGY_HALF_SCREEN = 1;
diff --git a/quickstep/src/com/android/quickstep/views/IconView.java b/quickstep/src/com/android/quickstep/views/IconView.java
index c359966..eb8da6e 100644
--- a/quickstep/src/com/android/quickstep/views/IconView.java
+++ b/quickstep/src/com/android/quickstep/views/IconView.java
@@ -21,14 +21,26 @@
import android.util.AttributeSet;
import android.view.View;
+import com.android.launcher3.FastBitmapDrawable;
+
+import java.util.ArrayList;
+
+import androidx.annotation.NonNull;
+
/**
* A view which draws a drawable stretched to fit its size. Unlike ImageView, it avoids relayout
* when the drawable changes.
*/
public class IconView extends View {
+ public interface OnScaleUpdateListener {
+ public void onScaleUpdate(float scale);
+ }
+
private Drawable mDrawable;
+ private ArrayList<OnScaleUpdateListener> mScaleListeners;
+
public IconView(Context context) {
super(context);
}
@@ -53,6 +65,10 @@
invalidate();
}
+ public Drawable getDrawable() {
+ return mDrawable;
+ }
+
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
@@ -78,6 +94,16 @@
}
@Override
+ public void invalidateDrawable(@NonNull Drawable drawable) {
+ super.invalidateDrawable(drawable);
+ if (drawable instanceof FastBitmapDrawable && mScaleListeners != null) {
+ for (OnScaleUpdateListener listener : mScaleListeners) {
+ listener.onScaleUpdate(((FastBitmapDrawable) drawable).getScale());
+ }
+ }
+ }
+
+ @Override
protected void onDraw(Canvas canvas) {
if (mDrawable != null) {
mDrawable.draw(canvas);
@@ -88,4 +114,20 @@
public boolean hasOverlappingRendering() {
return false;
}
+
+ public void addUpdateScaleListener(OnScaleUpdateListener listener) {
+ if (mScaleListeners == null) {
+ mScaleListeners = new ArrayList<>();
+ }
+ mScaleListeners.add(listener);
+ if (mDrawable instanceof FastBitmapDrawable) {
+ listener.onScaleUpdate(((FastBitmapDrawable) mDrawable).getScale());
+ }
+ }
+
+ public void removeUpdateScaleListener(OnScaleUpdateListener listener) {
+ if (mScaleListeners != null) {
+ mScaleListeners.remove(listener);
+ }
+ }
}
diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
index 7c5828b..697bb4f 100644
--- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -124,7 +124,7 @@
ClipAnimationHelper helper) {
AnimatorSet anim = super.createAdjacentPageAnimForTaskLaunch(tv, helper);
- if (!OverviewInteractionState.getInstance(mActivity).isSwipeUpGestureEnabled()) {
+ if (!OverviewInteractionState.INSTANCE.get(mActivity).isSwipeUpGestureEnabled()) {
// Hotseat doesn't move when opening recents with the button,
// so don't animate it here either.
return anim;
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 2680a26..f3dec9a 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -44,7 +44,6 @@
import android.os.Build;
import android.os.Handler;
import android.os.UserHandle;
-import android.support.annotation.Nullable;
import android.text.Layout;
import android.text.StaticLayout;
import android.text.TextPaint;
@@ -95,6 +94,8 @@
import java.util.ArrayList;
import java.util.function.Consumer;
+import androidx.annotation.Nullable;
+
/**
* A list of recent tasks.
*/
@@ -271,13 +272,13 @@
public RecentsView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setPageSpacing(getResources().getDimensionPixelSize(R.dimen.recents_page_spacing));
- enableFreeScroll(true);
+ setEnableFreeScroll(true);
mFastFlingVelocity = getResources()
.getDimensionPixelSize(R.dimen.recents_fast_fling_velocity);
mActivity = (T) BaseActivity.fromContext(context);
mQuickScrubController = new QuickScrubController(mActivity, this);
- mModel = RecentsModel.getInstance(context);
+ mModel = RecentsModel.INSTANCE.get(context);
mClearAllButton = (ClearAllButton) LayoutInflater.from(context)
.inflate(R.layout.overview_clear_all_button, this, false);
@@ -415,7 +416,7 @@
case MotionEvent.ACTION_DOWN:
// Touch down anywhere but the deadzone around the visible clear all button and
// between the task views will start home on touch up
- if (mTouchState == TOUCH_STATE_REST) {
+ if (!isHandlingTouch()) {
updateDeadZoneRects();
final boolean clearAllButtonDeadZoneConsumed = mClearAllButton.getAlpha() == 1
&& mClearAllButtonDeadZoneRect.contains(x, y);
@@ -560,7 +561,7 @@
boolean scrolling = super.computeScrollHelper();
boolean isFlingingFast = false;
updateCurveProperties();
- if (scrolling || (mTouchState == TOUCH_STATE_SCROLLING)) {
+ if (scrolling || isHandlingTouch()) {
if (scrolling) {
// Check if we are flinging quickly to disable high res thumbnail loading
isFlingingFast = mScroller.getCurrVelocity() > mFastFlingVelocity;
@@ -714,12 +715,16 @@
setCurrentTask(runningTaskId);
}
+ public TaskView getRunningTaskView() {
+ return getTaskView(mRunningTaskId);
+ }
+
/**
* Hides the tile associated with {@link #mRunningTaskId}
*/
public void setRunningTaskHidden(boolean isHidden) {
mRunningTaskTileHidden = isHidden;
- TaskView runningTask = getTaskView(mRunningTaskId);
+ TaskView runningTask = getRunningTaskView();
if (runningTask != null) {
runningTask.setAlpha(isHidden ? 0 : mContentAlpha);
}
@@ -745,7 +750,7 @@
}
public void showNextTask() {
- TaskView runningTaskView = getTaskView(mRunningTaskId);
+ TaskView runningTaskView = getRunningTaskView();
if (runningTaskView == null) {
// Launch the first task
if (getTaskViewCount() > 0) {
@@ -773,7 +778,7 @@
}
private void applyRunningTaskIconScale() {
- TaskView firstTask = getTaskView(mRunningTaskId);
+ TaskView firstTask = getRunningTaskView();
if (firstTask != null) {
firstTask.setIconScaleAndDim(mRunningTaskIconScaledDown ? 0 : 1);
}
@@ -781,7 +786,7 @@
public void animateUpRunningTaskIconScale() {
mRunningTaskIconScaledDown = false;
- TaskView firstTask = getTaskView(mRunningTaskId);
+ TaskView firstTask = getRunningTaskView();
if (firstTask != null) {
firstTask.animateIconScaleAndDimIntoView();
}
@@ -990,10 +995,8 @@
mPendingAnimation = pendingAnimation;
mPendingAnimation.addEndListener((onEndListener) -> {
if (onEndListener.isSuccess) {
- int taskViewCount = getTaskViewCount();
- for (int i = 0; i < taskViewCount; i++) {
- removeTask(getTaskViewAt(i).getTask(), -1, onEndListener, false);
- }
+ // Remove all the task views now
+ ActivityManagerWrapper.getInstance().removeAllRecentTasks();
removeAllViews();
onAllTasksRemoved();
}
@@ -1267,11 +1270,10 @@
int otherAdjacentTaskIndex = centerTaskIndex + (centerTaskIndex - taskIndex);
if (otherAdjacentTaskIndex >= 0 && otherAdjacentTaskIndex < getPageCount()) {
- anim.play(ObjectAnimator.ofPropertyValuesHolder(getPageAt(otherAdjacentTaskIndex),
- new PropertyListBuilder()
- .translationX(mIsRtl ? -displacementX : displacementX)
- .scale(1)
- .build()));
+ anim.play(new PropertyListBuilder()
+ .translationX(mIsRtl ? -displacementX : displacementX)
+ .scale(1)
+ .build(getPageAt(otherAdjacentTaskIndex)));
}
}
return anim;
@@ -1280,11 +1282,10 @@
private Animator createAnimForChild(TaskView child, float[] toScaleAndTranslation) {
AnimatorSet anim = new AnimatorSet();
anim.play(ObjectAnimator.ofFloat(child, TaskView.ZOOM_SCALE, toScaleAndTranslation[0]));
- anim.play(ObjectAnimator.ofPropertyValuesHolder(child,
- new PropertyListBuilder()
- .translationX(toScaleAndTranslation[1])
- .translationY(toScaleAndTranslation[2])
- .build()));
+ anim.play(new PropertyListBuilder()
+ .translationX(toScaleAndTranslation[1])
+ .translationY(toScaleAndTranslation[2])
+ .build(child));
return anim;
}
diff --git a/quickstep/src/com/android/quickstep/views/ShelfScrimView.java b/quickstep/src/com/android/quickstep/views/ShelfScrimView.java
index 8b5e832..8965575 100644
--- a/quickstep/src/com/android/quickstep/views/ShelfScrimView.java
+++ b/quickstep/src/com/android/quickstep/views/ShelfScrimView.java
@@ -15,11 +15,12 @@
*/
package com.android.quickstep.views;
-import static android.support.v4.graphics.ColorUtils.setAlphaComponent;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.anim.Interpolators.ACCEL;
import static com.android.launcher3.anim.Interpolators.LINEAR;
+import static androidx.core.graphics.ColorUtils.setAlphaComponent;
+
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuView.java b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
index 098349a..28928a8 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
@@ -22,7 +22,6 @@
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
-import android.content.res.Configuration;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
@@ -34,15 +33,15 @@
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BaseDraggingActivity;
-import com.android.launcher3.LauncherAnimUtils;
+import com.android.launcher3.FastBitmapDrawable;
import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
import com.android.launcher3.views.BaseDragLayer;
import com.android.quickstep.TaskSystemShortcut;
import com.android.quickstep.TaskUtils;
+import com.android.quickstep.views.IconView.OnScaleUpdateListener;
/**
* Contains options for a recent task when long-pressing its icon.
@@ -59,14 +58,42 @@
new TaskSystemShortcut.Install(),
};
+ private final OnScaleUpdateListener mTaskViewIconScaleListener = new OnScaleUpdateListener() {
+ @Override
+ public void onScaleUpdate(float scale) {
+ final Drawable drawable = mTaskIcon.getDrawable();
+ if (drawable instanceof FastBitmapDrawable) {
+ if (scale != ((FastBitmapDrawable) drawable).getScale()) {
+ mMenuIconDrawable.setScale(scale);
+ }
+ }
+ }
+ };
+
+ private final OnScaleUpdateListener mMenuIconScaleListener = new OnScaleUpdateListener() {
+ @Override
+ public void onScaleUpdate(float scale) {
+ final Drawable taskViewDrawable = mTaskView.getIconView().getDrawable();
+ if (taskViewDrawable instanceof FastBitmapDrawable) {
+ final float currentScale = ((FastBitmapDrawable) taskViewDrawable).getScale();
+ if (currentScale != scale) {
+ ((FastBitmapDrawable) taskViewDrawable).setScale(scale);
+ }
+ }
+ }
+ };
+
private static final int REVEAL_OPEN_DURATION = 150;
private static final int REVEAL_CLOSE_DURATION = 100;
+ private final float mThumbnailTopMargin;
private BaseDraggingActivity mActivity;
- private TextView mTaskIconAndName;
+ private TextView mTaskName;
+ private IconView mTaskIcon;
private AnimatorSet mOpenCloseAnimator;
private TaskView mTaskView;
private LinearLayout mOptionLayout;
+ private FastBitmapDrawable mMenuIconDrawable;
public TaskMenuView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
@@ -76,12 +103,14 @@
super(context, attrs, defStyleAttr);
mActivity = BaseDraggingActivity.fromContext(context);
+ mThumbnailTopMargin = getResources().getDimension(R.dimen.task_thumbnail_top_margin);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- mTaskIconAndName = findViewById(R.id.task_icon_and_name);
+ mTaskName = findViewById(R.id.task_name);
+ mTaskIcon = findViewById(R.id.task_icon);
mOptionLayout = findViewById(R.id.menu_option_layout);
}
@@ -113,15 +142,29 @@
}
@Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+
+ // Remove all scale listeners when menu is removed
+ mTaskView.getIconView().removeUpdateScaleListener(mTaskViewIconScaleListener);
+ mTaskIcon.removeUpdateScaleListener(mMenuIconScaleListener);
+ }
+
+ @Override
protected boolean isOfType(int type) {
return (type & TYPE_TASK_MENU) != 0;
}
- public static boolean showForTask(TaskView taskView) {
+ public void setPosition(float x, float y) {
+ setX(x);
+ setY(y + mThumbnailTopMargin);
+ }
+
+ public static TaskMenuView showForTask(TaskView taskView) {
BaseDraggingActivity activity = BaseDraggingActivity.fromContext(taskView.getContext());
final TaskMenuView taskMenuView = (TaskMenuView) activity.getLayoutInflater().inflate(
R.layout.task_menu, activity.getDragLayer(), false);
- return taskMenuView.populateAndShowForTask(taskView);
+ return taskMenuView.populateAndShowForTask(taskView) ? taskMenuView : null;
}
private boolean populateAndShowForTask(TaskView taskView) {
@@ -138,17 +181,21 @@
private void addMenuOptions(TaskView taskView) {
Drawable icon = taskView.getTask().icon.getConstantState().newDrawable();
- int iconSize = getResources().getDimensionPixelSize(R.dimen.task_thumbnail_icon_size);
- icon.setBounds(0, 0, iconSize, iconSize);
- mTaskIconAndName.setCompoundDrawables(null, icon, null, null);
- mTaskIconAndName.setText(TaskUtils.getTitle(getContext(), taskView.getTask()));
- mTaskIconAndName.setOnClickListener(v -> close(true));
+ mTaskIcon.setDrawable(icon);
+ mTaskIcon.setOnClickListener(v -> close(true));
+ mTaskName.setText(TaskUtils.getTitle(getContext(), taskView.getTask()));
+ mTaskName.setOnClickListener(v -> close(true));
+
+ // Set the icons to match scale by listening to each other's changes
+ mMenuIconDrawable = icon instanceof FastBitmapDrawable ? (FastBitmapDrawable) icon : null;
+ taskView.getIconView().addUpdateScaleListener(mTaskViewIconScaleListener);
+ mTaskIcon.addUpdateScaleListener(mMenuIconScaleListener);
// Move the icon and text up half an icon size to lay over the TaskView
LinearLayout.LayoutParams params =
- (LinearLayout.LayoutParams) mTaskIconAndName.getLayoutParams();
- params.topMargin = (int) -getResources().getDimension(R.dimen.task_thumbnail_top_margin);
- mTaskIconAndName.setLayoutParams(params);
+ (LinearLayout.LayoutParams) mTaskIcon.getLayoutParams();
+ params.topMargin = (int) -mThumbnailTopMargin;
+ mTaskIcon.setLayoutParams(params);
for (TaskSystemShortcut menuOption : MENU_OPTIONS) {
OnClickListener onClickListener = menuOption.getOnClickListener(mActivity, taskView);
@@ -172,12 +219,12 @@
mActivity.getDragLayer().getDescendantRectRelativeToSelf(taskView, sTempRect);
Rect insets = mActivity.getDragLayer().getInsets();
BaseDragLayer.LayoutParams params = (BaseDragLayer.LayoutParams) getLayoutParams();
- params.width = sTempRect.width();
- params.gravity = Gravity.LEFT;
+ params.width = taskView.getMeasuredWidth();
+ params.gravity = Gravity.START;
setLayoutParams(params);
- setX(Math.round(sTempRect.left - insets.left));
- setY(Math.round(sTempRect.top - insets.top
- + getResources().getDimension(R.dimen.task_thumbnail_top_margin)));
+ setScaleX(taskView.getScaleX());
+ setScaleY(taskView.getScaleY());
+ setPosition(sTempRect.left - insets.left, sTempRect.top - insets.top);
}
private void animateOpen() {
@@ -191,9 +238,9 @@
private void animateOpenOrClosed(boolean closing) {
if (mOpenCloseAnimator != null && mOpenCloseAnimator.isRunning()) {
- return;
+ mOpenCloseAnimator.end();
}
- mOpenCloseAnimator = LauncherAnimUtils.createAnimatorSet();
+ mOpenCloseAnimator = new AnimatorSet();
final Animator revealAnimator = createOpenCloseOutlineProvider()
.createRevealAnimator(this, closing);
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index 1653038..ee542d5 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -110,8 +110,24 @@
}
};
+ private final OnAttachStateChangeListener mTaskMenuStateListener =
+ new OnAttachStateChangeListener() {
+ @Override
+ public void onViewAttachedToWindow(View view) {
+ }
+
+ @Override
+ public void onViewDetachedFromWindow(View view) {
+ if (mMenuView != null) {
+ mMenuView.removeOnAttachStateChangeListener(this);
+ mMenuView = null;
+ }
+ }
+ };
+
private Task mTask;
private TaskThumbnailView mSnapshotView;
+ private TaskMenuView mMenuView;
private IconView mIconView;
private float mCurveScale;
private float mZoomScale;
@@ -200,13 +216,22 @@
public void onTaskDataLoaded(Task task, ThumbnailData thumbnailData) {
mSnapshotView.setThumbnail(task, thumbnailData);
mIconView.setDrawable(task.icon);
- mIconView.setOnClickListener(icon -> TaskMenuView.showForTask(this));
+ mIconView.setOnClickListener(icon -> showTaskMenu());
mIconView.setOnLongClickListener(icon -> {
requestDisallowInterceptTouchEvent(true);
- return TaskMenuView.showForTask(this);
+ return showTaskMenu();
});
}
+ private boolean showTaskMenu() {
+ getRecentsView().snapToPage(getRecentsView().indexOfChild(this));
+ mMenuView = TaskMenuView.showForTask(this);
+ if (mMenuView != null) {
+ mMenuView.addOnAttachStateChangeListener(mTaskMenuStateListener);
+ }
+ return mMenuView != null;
+ }
+
@Override
public void onTaskDataUnloaded() {
mSnapshotView.setThumbnail(null, null);
@@ -266,6 +291,12 @@
mSnapshotView.setDimAlpha(curveInterpolation * MAX_PAGE_SCRIM_ALPHA);
setCurveScale(getCurveScaleForCurveInterpolation(curveInterpolation));
+
+ if (mMenuView != null) {
+ mMenuView.setPosition(getX() - getRecentsView().getScrollX(), getY());
+ mMenuView.setScaleX(getScaleX());
+ mMenuView.setScaleY(getScaleY());
+ }
}
@Override
diff --git a/res/drawable-hdpi/ic_allapps.png b/res/drawable-hdpi/ic_allapps.png
deleted file mode 100644
index 253755f..0000000
--- a/res/drawable-hdpi/ic_allapps.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_allapps_pressed.png b/res/drawable-hdpi/ic_allapps_pressed.png
deleted file mode 100644
index 1e644c5..0000000
--- a/res/drawable-hdpi/ic_allapps_pressed.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_allapps.png b/res/drawable-mdpi/ic_allapps.png
deleted file mode 100644
index 6936b20..0000000
--- a/res/drawable-mdpi/ic_allapps.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_allapps_pressed.png b/res/drawable-mdpi/ic_allapps_pressed.png
deleted file mode 100644
index 850ded6..0000000
--- a/res/drawable-mdpi/ic_allapps_pressed.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_allapps.png b/res/drawable-xhdpi/ic_allapps.png
deleted file mode 100644
index c11c103..0000000
--- a/res/drawable-xhdpi/ic_allapps.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_allapps_pressed.png b/res/drawable-xhdpi/ic_allapps_pressed.png
deleted file mode 100644
index f319bf1..0000000
--- a/res/drawable-xhdpi/ic_allapps_pressed.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_allapps.png b/res/drawable-xxhdpi/ic_allapps.png
deleted file mode 100644
index cf6a2cb..0000000
--- a/res/drawable-xxhdpi/ic_allapps.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_allapps_pressed.png b/res/drawable-xxhdpi/ic_allapps_pressed.png
deleted file mode 100644
index 379389a..0000000
--- a/res/drawable-xxhdpi/ic_allapps_pressed.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable/all_apps_button_icon.xml b/res/drawable/all_apps_button_icon.xml
deleted file mode 100644
index 7c69cad..0000000
--- a/res/drawable/all_apps_button_icon.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 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.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_focused="true" android:drawable="@drawable/ic_allapps_pressed" />
- <item android:state_pressed="true" android:drawable="@drawable/ic_allapps_pressed" />
- <item android:drawable="@drawable/ic_allapps" />
-</selector>
diff --git a/res/layout/all_apps_button.xml b/res/layout/all_apps_button.xml
deleted file mode 100644
index 4bc780a..0000000
--- a/res/layout/all_apps_button.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 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.
--->
-
-<TextView style="@style/BaseIcon" />
diff --git a/res/values-sw720dp/dimens.xml b/res/values-sw720dp/dimens.xml
index b211207..691219a 100644
--- a/res/values-sw720dp/dimens.xml
+++ b/res/values-sw720dp/dimens.xml
@@ -16,7 +16,6 @@
<resources>
<!-- All Apps -->
- <dimen name="all_apps_button_scale_down">8dp</dimen>
<dimen name="all_apps_empty_search_message_top_offset">64dp</dimen>
<dimen name="all_apps_empty_search_bg_top_offset">180dp</dimen>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 30091a5..045e4e9 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -33,6 +33,7 @@
<attr name="workspaceKeyShadowColor" format="color" />
<attr name="workspaceStatusBarScrim" format="reference" />
<attr name="widgetsTheme" format="reference" />
+ <attr name="folderBadgeColor" format="color" />
<!-- BubbleTextView specific attributes. -->
<declare-styleable name="BubbleTextView">
diff --git a/res/values/config.xml b/res/values/config.xml
index f462b9c..8d31bd2 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -148,6 +148,4 @@
<item type="id" name="overview_panel"/>
<integer name="config_recentsMaxThumbnailCacheSize">6</integer>
<integer name="config_recentsMaxIconCacheSize">12</integer>
-
- <item name="workspace_page_container" type="id" />
</resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 3bb7a79..58fce34 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -76,7 +76,6 @@
<dimen name="fastscroll_end_margin">-26dp</dimen>
<!-- All Apps -->
- <dimen name="all_apps_button_scale_down">0dp</dimen>
<dimen name="all_apps_search_bar_field_height">48dp</dimen>
<dimen name="all_apps_search_bar_bottom_padding">30dp</dimen>
<dimen name="all_apps_empty_search_message_top_offset">40dp</dimen>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 07bd800..7ea28cc 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -42,6 +42,7 @@
<item name="workspaceKeyShadowColor">#44000000</item>
<item name="workspaceStatusBarScrim">@drawable/workspace_bg</item>
<item name="widgetsTheme">@style/WidgetContainerTheme</item>
+ <item name="folderBadgeColor">?android:attr/colorPrimary</item>
</style>
<style name="LauncherTheme" parent="@style/BaseLauncherThemeWithCustomAttrs"></style>
@@ -70,6 +71,7 @@
<item name="popupColorSecondary">#424242</item> <!-- Gray 800 -->
<item name="popupColorTertiary">#757575</item> <!-- Gray 600 -->
<item name="widgetsTheme">@style/WidgetContainerTheme.Dark</item>
+ <item name="folderBadgeColor">#FF464646</item>
<item name="isMainColorDark">true</item>
</style>
diff --git a/res/xml/device_profiles.xml b/res/xml/device_profiles.xml
index a34f225..ef6e145 100644
--- a/res/xml/device_profiles.xml
+++ b/res/xml/device_profiles.xml
@@ -133,13 +133,13 @@
launcher:name="Nexus 7"
launcher:minWidthDps="575"
launcher:minHeightDps="904"
- launcher:numRows="5"
+ launcher:numRows="6"
launcher:numColumns="6"
launcher:numFolderRows="4"
launcher:numFolderColumns="5"
launcher:iconSize="64"
launcher:iconTextSize="14.4"
- launcher:numHotseatIcons="7"
+ launcher:numHotseatIcons="6"
launcher:defaultLayoutId="@xml/default_workspace_5x6"
/>
@@ -147,8 +147,8 @@
launcher:name="Nexus 10"
launcher:minWidthDps="727"
launcher:minHeightDps="1207"
- launcher:numRows="5"
- launcher:numColumns="6"
+ launcher:numRows="6"
+ launcher:numColumns="7"
launcher:numFolderRows="4"
launcher:numFolderColumns="5"
launcher:iconSize="76"
diff --git a/res/xml/dw_phone_hotseat.xml b/res/xml/dw_phone_hotseat.xml
index b58994d..c691ebc 100644
--- a/res/xml/dw_phone_hotseat.xml
+++ b/res/xml/dw_phone_hotseat.xml
@@ -16,7 +16,7 @@
<favorites xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3">
<!-- Hotseat (We use the screen as the position of the item in the hotseat) -->
- <!-- Dialer, Messaging, [All Apps], Browser, Camera -->
+ <!-- Dialer, Messaging, [Maps/Music], Browser, Camera -->
<resolve
launcher:container="-101"
launcher:screen="0"
@@ -39,7 +39,14 @@
<favorite launcher:uri="mmsto:" />
</resolve>
- <!-- All Apps -->
+ <resolve
+ launcher:container="-101"
+ launcher:screen="2"
+ launcher:x="2"
+ launcher:y="0" >
+ <favorite launcher:uri="#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_MAPS;end" />
+ <favorite launcher:uri="#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_MUSIC;end" />
+ </resolve>
<resolve
launcher:container="-101"
diff --git a/res/xml/dw_tablet_hotseat.xml b/res/xml/dw_tablet_hotseat.xml
index 671ccba..6fe7f93 100644
--- a/res/xml/dw_tablet_hotseat.xml
+++ b/res/xml/dw_tablet_hotseat.xml
@@ -16,7 +16,7 @@
<favorites xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3">
<!-- Hotseat (We use the screen as the position of the item in the hotseat) -->
- <!-- Messaging, Email, Browser, [All Apps], Music, Gallery, Camera -->
+ <!-- Messaging, Email, Browser, Maps, Music, Gallery, Camera -->
<resolve
launcher:container="-101"
launcher:screen="0"
@@ -48,7 +48,13 @@
<favorite launcher:uri="http://www.example.com/" />
</resolve>
- <!-- All Apps -->
+ <resolve
+ launcher:container="-101"
+ launcher:screen="3"
+ launcher:x="3"
+ launcher:y="0" >
+ <favorite launcher:uri="#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_MAPS;end" />
+ </resolve>
<favorite
launcher:container="-101"
diff --git a/src/com/android/launcher3/AbstractFloatingView.java b/src/com/android/launcher3/AbstractFloatingView.java
index 3223837..1c07ea4 100644
--- a/src/com/android/launcher3/AbstractFloatingView.java
+++ b/src/com/android/launcher3/AbstractFloatingView.java
@@ -25,7 +25,6 @@
import android.annotation.SuppressLint;
import android.content.Context;
-import android.support.annotation.IntDef;
import android.util.AttributeSet;
import android.util.Pair;
import android.view.MotionEvent;
@@ -40,6 +39,8 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import androidx.annotation.IntDef;
+
/**
* Base class for a View which shows a floating UI on top of the launcher UI.
*/
@@ -69,9 +70,9 @@
public static final int TYPE_DISCOVERY_BOUNCE = 1 << 6;
// Popups related to quickstep UI
- public static final int TYPE_QUICKSTEP_PREVIEW = 1 << 6;
- public static final int TYPE_TASK_MENU = 1 << 7;
- public static final int TYPE_OPTIONS_POPUP = 1 << 8;
+ public static final int TYPE_QUICKSTEP_PREVIEW = 1 << 7;
+ public static final int TYPE_TASK_MENU = 1 << 8;
+ public static final int TYPE_OPTIONS_POPUP = 1 << 9;
public static final int TYPE_ALL = TYPE_FOLDER | TYPE_ACTION_POPUP
| TYPE_WIDGETS_BOTTOM_SHEET | TYPE_WIDGET_RESIZE_FRAME | TYPE_WIDGETS_FULL_SHEET
diff --git a/src/com/android/launcher3/AllAppsList.java b/src/com/android/launcher3/AllAppsList.java
index 5eb6cc7..2482691 100644
--- a/src/com/android/launcher3/AllAppsList.java
+++ b/src/com/android/launcher3/AllAppsList.java
@@ -22,8 +22,6 @@
import android.content.pm.LauncherActivityInfo;
import android.os.Process;
import android.os.UserHandle;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
import android.util.Log;
import com.android.launcher3.compat.LauncherAppsCompat;
@@ -35,6 +33,9 @@
import java.util.HashSet;
import java.util.List;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
/**
* Stores the list of all applications for the all apps view.
diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java
index 7648e30..0f5317b 100644
--- a/src/com/android/launcher3/AppWidgetResizeFrame.java
+++ b/src/com/android/launcher3/AppWidgetResizeFrame.java
@@ -3,8 +3,6 @@
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
-import android.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.appwidget.AppWidgetHostView;
import android.appwidget.AppWidgetProviderInfo;
import android.content.Context;
@@ -39,6 +37,7 @@
private final Launcher mLauncher;
private final DragViewStateAnnouncer mStateAnnouncer;
+ private final FirstFrameAnimatorHelper mFirstFrameAnimatorHelper;
private final View[] mDragHandles = new View[HANDLE_COUNT];
@@ -101,6 +100,7 @@
mBackgroundPadding = getResources()
.getDimensionPixelSize(R.dimen.resize_frame_background_padding);
mTouchTargetWidth = 2 * mBackgroundPadding;
+ mFirstFrameAnimatorHelper = new FirstFrameAnimatorHelper(this);
}
@Override
@@ -368,12 +368,7 @@
mDeltaX = 0;
mDeltaY = 0;
- post(new Runnable() {
- @Override
- public void run() {
- snapToWidget(true);
- }
- });
+ post(() -> snapToWidget(true));
}
/**
@@ -433,24 +428,19 @@
}
requestLayout();
} else {
- PropertyValuesHolder width = PropertyValuesHolder.ofInt("width", lp.width, newWidth);
- PropertyValuesHolder height = PropertyValuesHolder.ofInt("height", lp.height,
- newHeight);
- PropertyValuesHolder x = PropertyValuesHolder.ofInt("x", lp.x, newX);
- PropertyValuesHolder y = PropertyValuesHolder.ofInt("y", lp.y, newY);
- ObjectAnimator oa =
- LauncherAnimUtils.ofPropertyValuesHolder(lp, this, width, height, x, y);
- oa.addUpdateListener(new AnimatorUpdateListener() {
- public void onAnimationUpdate(ValueAnimator animation) {
- requestLayout();
- }
- });
- AnimatorSet set = LauncherAnimUtils.createAnimatorSet();
+ ObjectAnimator oa = ObjectAnimator.ofPropertyValuesHolder(lp,
+ PropertyValuesHolder.ofInt("width", lp.width, newWidth),
+ PropertyValuesHolder.ofInt("height", lp.height, newHeight),
+ PropertyValuesHolder.ofInt("x", lp.x, newX),
+ PropertyValuesHolder.ofInt("y", lp.y, newY));
+ mFirstFrameAnimatorHelper.addTo(oa).addUpdateListener(a -> requestLayout());
+
+ AnimatorSet set = new AnimatorSet();
set.play(oa);
for (int i = 0; i < HANDLE_COUNT; i++) {
- set.play(LauncherAnimUtils.ofFloat(mDragHandles[i], ALPHA, 1.0f));
+ set.play(mFirstFrameAnimatorHelper.addTo(
+ ObjectAnimator.ofFloat(mDragHandles[i], ALPHA, 1f)));
}
-
set.setDuration(SNAP_DURATION);
set.start();
}
diff --git a/src/com/android/launcher3/AppWidgetsRestoredReceiver.java b/src/com/android/launcher3/AppWidgetsRestoredReceiver.java
index b249c95..0250c36 100644
--- a/src/com/android/launcher3/AppWidgetsRestoredReceiver.java
+++ b/src/com/android/launcher3/AppWidgetsRestoredReceiver.java
@@ -9,7 +9,6 @@
import android.content.Intent;
import android.database.Cursor;
import android.os.Handler;
-import android.support.annotation.WorkerThread;
import android.util.Log;
import com.android.launcher3.LauncherSettings.Favorites;
@@ -18,6 +17,8 @@
import com.android.launcher3.provider.RestoreDbTask;
import com.android.launcher3.util.ContentWriter;
+import androidx.annotation.WorkerThread;
+
public class AppWidgetsRestoredReceiver extends BroadcastReceiver {
private static final String TAG = "AWRestoredReceiver";
diff --git a/src/com/android/launcher3/AutoInstallsLayout.java b/src/com/android/launcher3/AutoInstallsLayout.java
index 469b8bb..6b0a90a 100644
--- a/src/com/android/launcher3/AutoInstallsLayout.java
+++ b/src/com/android/launcher3/AutoInstallsLayout.java
@@ -28,7 +28,6 @@
import android.database.sqlite.SQLiteDatabase;
import android.graphics.drawable.Drawable;
import android.net.Uri;
-import android.os.Build;
import android.os.Build.VERSION;
import android.os.Bundle;
import android.os.Process;
@@ -37,16 +36,18 @@
import android.util.Log;
import android.util.Pair;
import android.util.Patterns;
+
import com.android.launcher3.LauncherProvider.SqlArguments;
import com.android.launcher3.LauncherSettings.Favorites;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.graphics.LauncherIcons;
import com.android.launcher3.util.Thunk;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
import java.io.IOException;
import java.util.ArrayList;
import java.util.Locale;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
/**
* Layout parsing code for auto installs layout
@@ -230,9 +231,7 @@
if (HOTSEAT_CONTAINER_NAME.equals(getAttributeValue(parser, ATTR_CONTAINER))) {
out[0] = Favorites.CONTAINER_HOTSEAT;
// Hack: hotseat items are stored using screen ids
- long rank = Long.parseLong(getAttributeValue(parser, ATTR_RANK));
- out[1] = (FeatureFlags.NO_ALL_APPS_ICON || rank < mIdp.getAllAppsButtonRank())
- ? rank : (rank + 1);
+ out[1] = Long.parseLong(getAttributeValue(parser, ATTR_RANK));
} else {
out[0] = Favorites.CONTAINER_DESKTOP;
out[1] = Long.parseLong(getAttributeValue(parser, ATTR_SCREEN));
diff --git a/src/com/android/launcher3/BaseActivity.java b/src/com/android/launcher3/BaseActivity.java
index 6c82e63..2ec7e01 100644
--- a/src/com/android/launcher3/BaseActivity.java
+++ b/src/com/android/launcher3/BaseActivity.java
@@ -25,7 +25,6 @@
import android.content.ContextWrapper;
import android.content.Intent;
import android.content.res.Configuration;
-import android.support.annotation.IntDef;
import android.view.ContextThemeWrapper;
import android.view.View.AccessibilityDelegate;
@@ -41,6 +40,8 @@
import java.lang.annotation.Retention;
import java.util.ArrayList;
+import androidx.annotation.IntDef;
+
public abstract class BaseActivity extends Activity implements UserEventDelegate{
public static final int INVISIBLE_BY_STATE_HANDLER = 1 << 0;
diff --git a/src/com/android/launcher3/BaseDraggingActivity.java b/src/com/android/launcher3/BaseDraggingActivity.java
index d6635dc..f5fbf80 100644
--- a/src/com/android/launcher3/BaseDraggingActivity.java
+++ b/src/com/android/launcher3/BaseDraggingActivity.java
@@ -19,7 +19,9 @@
import android.app.ActivityOptions;
import android.content.ActivityNotFoundException;
import android.content.Intent;
+import android.content.res.Configuration;
import android.graphics.Rect;
+import android.os.Build;
import android.os.Bundle;
import android.os.Process;
import android.os.StrictMode;
@@ -81,13 +83,33 @@
@Override
public void onExtractedColorsChanged(WallpaperColorInfo wallpaperColorInfo) {
+ updateTheme();
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ updateTheme();
+ }
+
+ private void updateTheme() {
+ WallpaperColorInfo wallpaperColorInfo = WallpaperColorInfo.getInstance(this);
if (mThemeRes != getThemeRes(wallpaperColorInfo)) {
recreate();
}
}
protected int getThemeRes(WallpaperColorInfo wallpaperColorInfo) {
- if (wallpaperColorInfo.isDark()) {
+ boolean darkTheme;
+ if (Utilities.ATLEAST_Q) {
+ Configuration configuration = getResources().getConfiguration();
+ int nightMode = configuration.uiMode & Configuration.UI_MODE_NIGHT_MASK;
+ darkTheme = nightMode == Configuration.UI_MODE_NIGHT_YES;
+ } else {
+ darkTheme = wallpaperColorInfo.isDark();
+ }
+
+ if (darkTheme) {
return wallpaperColorInfo.supportsDarkText() ?
R.style.AppTheme_Dark_DarkText : R.style.AppTheme_Dark;
} else {
diff --git a/src/com/android/launcher3/BaseRecyclerView.java b/src/com/android/launcher3/BaseRecyclerView.java
index 74b9cfa..f300ef7 100644
--- a/src/com/android/launcher3/BaseRecyclerView.java
+++ b/src/com/android/launcher3/BaseRecyclerView.java
@@ -17,7 +17,6 @@
package com.android.launcher3;
import android.content.Context;
-import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
@@ -25,6 +24,8 @@
import com.android.launcher3.views.RecyclerViewFastScroller;
+import androidx.recyclerview.widget.RecyclerView;
+
/**
* A base {@link RecyclerView}, which does the following:
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index fb7c0ce..01e3a10 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -27,7 +27,6 @@
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
-import android.support.v4.graphics.ColorUtils;
import android.text.TextUtils.TruncateAt;
import android.util.AttributeSet;
import android.util.Property;
@@ -52,6 +51,8 @@
import java.text.NumberFormat;
+import androidx.core.graphics.ColorUtils;
+
/**
* TextView that draws a bubble behind the text. We cannot use a LineBackgroundSpan
* because we want to make the bubble taller than the text and TextView's clip is
@@ -386,10 +387,14 @@
}
public void getIconBounds(Rect outBounds) {
- int top = getPaddingTop();
- int left = (getWidth() - mIconSize) / 2;
- int right = left + mIconSize;
- int bottom = top + mIconSize;
+ getIconBounds(this, outBounds, mIconSize);
+ }
+
+ public static void getIconBounds(View iconView, Rect outBounds, int iconSize) {
+ int top = iconView.getPaddingTop();
+ int left = (iconView.getWidth() - iconSize) / 2;
+ int right = left + iconSize;
+ int bottom = top + iconSize;
outBounds.set(left, top, right, bottom);
}
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index 6c2fd8e..f6f1496 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -16,8 +16,11 @@
package com.android.launcher3;
+import static com.android.launcher3.anim.Interpolators.DEACCEL_1_5;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
@@ -34,11 +37,10 @@
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Parcelable;
-import android.support.annotation.IntDef;
-import android.support.v4.view.ViewCompat;
import android.util.ArrayMap;
import android.util.AttributeSet;
import android.util.Log;
+import android.util.Property;
import android.util.SparseArray;
import android.view.MotionEvent;
import android.view.View;
@@ -70,6 +72,9 @@
import java.util.Comparator;
import java.util.Stack;
+import androidx.annotation.IntDef;
+import androidx.core.view.ViewCompat;
+
public class CellLayout extends ViewGroup {
public static final int WORKSPACE_ACCESSIBILITY_DRAG = 2;
public static final int FOLDER_ACCESSIBILITY_DRAG = 1;
@@ -243,7 +248,7 @@
for (int i = 0; i < mDragOutlineAnims.length; i++) {
final InterruptibleInOutAnimator anim =
- new InterruptibleInOutAnimator(this, duration, fromAlphaValue, toAlphaValue);
+ new InterruptibleInOutAnimator(duration, fromAlphaValue, toAlphaValue);
anim.getAnimator().setInterpolator(mEaseOutInterpolator);
final int thisIndex = i;
anim.getAnimator().addUpdateListener(new AnimatorUpdateListener() {
@@ -877,7 +882,7 @@
return true;
}
- ValueAnimator va = LauncherAnimUtils.ofFloat(0f, 1f);
+ ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
va.setDuration(duration);
mReorderAnimators.put(lp, va);
@@ -1884,6 +1889,19 @@
}
}
+ private static final Property<ReorderPreviewAnimation, Float> ANIMATION_PROGRESS =
+ new Property<ReorderPreviewAnimation, Float>(float.class, "animationProgress") {
+ @Override
+ public Float get(ReorderPreviewAnimation anim) {
+ return anim.animationProgress;
+ }
+
+ @Override
+ public void set(ReorderPreviewAnimation anim, Float progress) {
+ anim.setAnimationProgress(progress);
+ }
+ };
+
// Class which represents the reorder preview animations. These animations show that an item is
// in a temporary state, and hint at where the item will return to.
class ReorderPreviewAnimation {
@@ -1904,7 +1922,8 @@
public static final int MODE_HINT = 0;
public static final int MODE_PREVIEW = 1;
- Animator a;
+ float animationProgress = 0;
+ ValueAnimator a;
public ReorderPreviewAnimation(View child, int mode, int cellX0, int cellY0, int cellX1,
int cellY1, int spanX, int spanY) {
@@ -1974,7 +1993,7 @@
if (noMovement) {
return;
}
- ValueAnimator va = LauncherAnimUtils.ofFloat(0f, 1f);
+ ValueAnimator va = ObjectAnimator.ofFloat(this, ANIMATION_PROGRESS, 0, 1);
a = va;
// Animations are disabled in power save mode, causing the repeated animation to jump
@@ -1987,20 +2006,6 @@
va.setDuration(mode == MODE_HINT ? HINT_DURATION : PREVIEW_DURATION);
va.setStartDelay((int) (Math.random() * 60));
- va.addUpdateListener(new AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- float r = (Float) animation.getAnimatedValue();
- float r1 = (mode == MODE_HINT && repeating) ? 1.0f : r;
- float x = r1 * finalDeltaX + (1 - r1) * initDeltaX;
- float y = r1 * finalDeltaY + (1 - r1) * initDeltaY;
- child.setTranslationX(x);
- child.setTranslationY(y);
- float s = r * finalScale + (1 - r) * initScale;
- child.setScaleX(s);
- child.setScaleY(s);
- }
- });
va.addListener(new AnimatorListenerAdapter() {
public void onAnimationRepeat(Animator animation) {
// We make sure to end only after a full period
@@ -2012,6 +2017,18 @@
va.start();
}
+ private void setAnimationProgress(float progress) {
+ animationProgress = progress;
+ float r1 = (mode == MODE_HINT && repeating) ? 1.0f : animationProgress;
+ float x = r1 * finalDeltaX + (1 - r1) * initDeltaX;
+ float y = r1 * finalDeltaY + (1 - r1) * initDeltaY;
+ child.setTranslationX(x);
+ child.setTranslationY(y);
+ float s = animationProgress * finalScale + (1 - animationProgress) * initScale;
+ child.setScaleX(s);
+ child.setScaleY(s);
+ }
+
private void cancel() {
if (a != null) {
a.cancel();
@@ -2024,14 +2041,14 @@
}
setInitialAnimationValues(true);
- a = LauncherAnimUtils.ofPropertyValuesHolder(child,
- new PropertyListBuilder()
- .scale(initScale)
- .translationX(initDeltaX)
- .translationY(initDeltaY)
- .build())
+ a = new PropertyListBuilder()
+ .scale(initScale)
+ .translationX(initDeltaX)
+ .translationY(initDeltaY)
+ .build(child)
.setDuration(REORDER_ANIMATION_DURATION);
- a.setInterpolator(new android.view.animation.DecelerateInterpolator(1.5f));
+ mLauncher.getDragController().addFirstFrameAnimationHelper(a);
+ a.setInterpolator(DEACCEL_1_5);
a.start();
}
}
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 820c125..9839c12 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -59,6 +59,9 @@
private static final float TALL_DEVICE_ASPECT_RATIO_THRESHOLD = 2.0f;
+ // To evenly space the icons, increase the left/right margins for tablets in portrait mode.
+ private static final int PORTRAIT_TABLET_LEFT_RIGHT_PADDING_MULTIPLIER = 4;
+
// Workspace
public final int desiredWorkspaceLeftRightMarginPx;
public final int cellLayoutPaddingLeftRightPx;
@@ -172,7 +175,9 @@
defaultWidgetPadding = AppWidgetHostView.getDefaultPaddingForWidget(context, cn, null);
edgeMarginPx = res.getDimensionPixelSize(R.dimen.dynamic_grid_edge_margin);
desiredWorkspaceLeftRightMarginPx = isVerticalBarLayout() ? 0 : edgeMarginPx;
- cellLayoutPaddingLeftRightPx =
+ 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);
diff --git a/src/com/android/launcher3/FastBitmapDrawable.java b/src/com/android/launcher3/FastBitmapDrawable.java
index 9217ca9..7efb6ec 100644
--- a/src/com/android/launcher3/FastBitmapDrawable.java
+++ b/src/com/android/launcher3/FastBitmapDrawable.java
@@ -109,7 +109,7 @@
@Override
public final void draw(Canvas canvas) {
- if (mScaleAnimation != null) {
+ if (mScale != 1f) {
int count = canvas.save();
Rect bounds = getBounds();
canvas.scale(mScale, mScale, bounds.exactCenterX(), bounds.exactCenterY());
@@ -150,10 +150,23 @@
return mAlpha;
}
+ public void setScale(float scale) {
+ if (mScaleAnimation != null) {
+ mScaleAnimation.cancel();
+ mScaleAnimation = null;
+ }
+ mScale = scale;
+ invalidateSelf();
+ }
+
public float getAnimatedScale() {
return mScaleAnimation == null ? 1 : mScale;
}
+ public float getScale() {
+ return mScale;
+ }
+
@Override
public int getIntrinsicWidth() {
return mBitmap.getWidth();
diff --git a/src/com/android/launcher3/FirstFrameAnimatorHelper.java b/src/com/android/launcher3/FirstFrameAnimatorHelper.java
index e7ca121..c967a96 100644
--- a/src/com/android/launcher3/FirstFrameAnimatorHelper.java
+++ b/src/com/android/launcher3/FirstFrameAnimatorHelper.java
@@ -13,126 +13,124 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package com.android.launcher3;
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
+import static com.android.launcher3.Utilities.SINGLE_FRAME_MS;
+
import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.util.Log;
import android.view.View;
-import android.view.ViewPropertyAnimator;
-import android.view.ViewTreeObserver;
-import com.android.launcher3.util.Thunk;
-
-import static com.android.launcher3.Utilities.SINGLE_FRAME_MS;
+import android.view.View.OnAttachStateChangeListener;
+import android.view.ViewTreeObserver.OnDrawListener;
/*
* This is a helper class that listens to updates from the corresponding animation.
* For the first two frames, it adjusts the current play time of the animation to
* prevent jank at the beginning of the animation
*/
-public class FirstFrameAnimatorHelper extends AnimatorListenerAdapter
- implements ValueAnimator.AnimatorUpdateListener {
+public class FirstFrameAnimatorHelper implements OnDrawListener, OnAttachStateChangeListener {
+
private static final String TAG = "FirstFrameAnimatorHlpr";
private static final boolean DEBUG = false;
private static final int MAX_DELAY = 1000;
- private final View mTarget;
- private long mStartFrame;
- private long mStartTime = -1;
- private boolean mHandlingOnAnimationUpdate;
- private boolean mAdjustedSecondFrameTime;
- private static ViewTreeObserver.OnDrawListener sGlobalDrawListener;
- @Thunk static long sGlobalFrameCounter;
- private static boolean sVisible;
+ private View mRootView;
+ private long mGlobalFrameCount;
- public FirstFrameAnimatorHelper(ValueAnimator animator, View target) {
- mTarget = target;
- animator.addUpdateListener(this);
- }
-
- public FirstFrameAnimatorHelper(ViewPropertyAnimator vpa, View target) {
- mTarget = target;
- vpa.setListener(this);
- }
-
- // only used for ViewPropertyAnimators
- public void onAnimationStart(Animator animation) {
- final ValueAnimator va = (ValueAnimator) animation;
- va.addUpdateListener(FirstFrameAnimatorHelper.this);
- onAnimationUpdate(va);
- }
-
- public static void setIsVisible(boolean visible) {
- sVisible = visible;
- }
-
- public static void initializeDrawListener(View view) {
- if (sGlobalDrawListener != null) {
- view.getViewTreeObserver().removeOnDrawListener(sGlobalDrawListener);
+ public FirstFrameAnimatorHelper(View target) {
+ target.addOnAttachStateChangeListener(this);
+ if (target.isAttachedToWindow()) {
+ onViewAttachedToWindow(target);
}
-
- sGlobalDrawListener = () -> sGlobalFrameCounter++;
- view.getViewTreeObserver().addOnDrawListener(sGlobalDrawListener);
- sVisible = true;
}
- public void onAnimationUpdate(final ValueAnimator animation) {
- final long currentTime = System.currentTimeMillis();
- if (mStartTime == -1) {
- mStartFrame = sGlobalFrameCounter;
- mStartTime = currentTime;
+ public <T extends ValueAnimator> T addTo(T anim) {
+ anim.addUpdateListener(new MyListener());
+ return anim;
+ }
+
+ @Override
+ public void onDraw() {
+ mGlobalFrameCount ++;
+ }
+
+ @Override
+ public void onViewAttachedToWindow(View view) {
+ mRootView = view.getRootView();
+ mRootView.getViewTreeObserver().addOnDrawListener(this);
+ }
+
+ @Override
+ public void onViewDetachedFromWindow(View view) {
+ if (mRootView != null) {
+ mRootView.getViewTreeObserver().removeOnDrawListener(this);
+ mRootView = null;
}
+ }
- final long currentPlayTime = animation.getCurrentPlayTime();
- boolean isFinalFrame = Float.compare(1f, animation.getAnimatedFraction()) == 0;
+ private class MyListener implements AnimatorUpdateListener {
- if (!mHandlingOnAnimationUpdate &&
- sVisible &&
- // If the current play time exceeds the duration, or the animated fraction is 1,
- // the animation will get finished, even if we call setCurrentPlayTime -- therefore
- // don't adjust the animation in that case
- currentPlayTime < animation.getDuration() && !isFinalFrame) {
- mHandlingOnAnimationUpdate = true;
- long frameNum = sGlobalFrameCounter - mStartFrame;
- // If we haven't drawn our first frame, reset the time to t = 0
- // (give up after MAX_DELAY ms of waiting though - might happen, for example, if we
- // are no longer in the foreground and no frames are being rendered ever)
- if (frameNum == 0 && currentTime < mStartTime + MAX_DELAY && currentPlayTime > 0) {
- // The first frame on animations doesn't always trigger an invalidate...
- // force an invalidate here to make sure the animation continues to advance
- mTarget.getRootView().invalidate();
- animation.setCurrentPlayTime(0);
- // For the second frame, if the first frame took more than 16ms,
- // adjust the start time and pretend it took only 16ms anyway. This
- // prevents a large jump in the animation due to an expensive first frame
- } else if (frameNum == 1 && currentTime < mStartTime + MAX_DELAY &&
- !mAdjustedSecondFrameTime &&
- currentTime > mStartTime + SINGLE_FRAME_MS &&
- currentPlayTime > SINGLE_FRAME_MS) {
- animation.setCurrentPlayTime(SINGLE_FRAME_MS);
- mAdjustedSecondFrameTime = true;
- } else {
- if (frameNum > 1) {
- mTarget.post(new Runnable() {
- public void run() {
- animation.removeUpdateListener(FirstFrameAnimatorHelper.this);
- }
- });
+ private long mStartFrame;
+ private long mStartTime = -1;
+ private boolean mHandlingOnAnimationUpdate;
+ private boolean mAdjustedSecondFrameTime;
+
+ @Override
+ public void onAnimationUpdate(final ValueAnimator animation) {
+ final long currentTime = System.currentTimeMillis();
+ if (mStartTime == -1) {
+ mStartFrame = mGlobalFrameCount;
+ mStartTime = currentTime;
+ }
+
+ final long currentPlayTime = animation.getCurrentPlayTime();
+ boolean isFinalFrame = Float.compare(1f, animation.getAnimatedFraction()) == 0;
+
+ if (!mHandlingOnAnimationUpdate &&
+ mRootView != null &&
+ mRootView.getWindowVisibility() == View.VISIBLE &&
+ // If the current play time exceeds the duration, or the animated fraction is 1,
+ // the animation will get finished, even if we call setCurrentPlayTime --
+ // therefore don't adjust the animation in that case
+ currentPlayTime < animation.getDuration() && !isFinalFrame) {
+ mHandlingOnAnimationUpdate = true;
+ long frameNum = mGlobalFrameCount - mStartFrame;
+
+ // If we haven't drawn our first frame, reset the time to t = 0
+ // (give up after MAX_DELAY ms of waiting though - might happen, for example, if we
+ // are no longer in the foreground and no frames are being rendered ever)
+ if (frameNum == 0 && currentTime < mStartTime + MAX_DELAY && currentPlayTime > 0) {
+ // The first frame on animations doesn't always trigger an invalidate...
+ // force an invalidate here to make sure the animation continues to advance
+ mRootView.invalidate();
+ animation.setCurrentPlayTime(0);
+ // For the second frame, if the first frame took more than 16ms,
+ // adjust the start time and pretend it took only 16ms anyway. This
+ // prevents a large jump in the animation due to an expensive first frame
+ } else if (frameNum == 1 && currentTime < mStartTime + MAX_DELAY &&
+ !mAdjustedSecondFrameTime &&
+ currentTime > mStartTime + SINGLE_FRAME_MS &&
+ currentPlayTime > SINGLE_FRAME_MS) {
+ animation.setCurrentPlayTime(SINGLE_FRAME_MS);
+ mAdjustedSecondFrameTime = true;
+ } else {
+ if (frameNum > 1) {
+ mRootView.post(() -> animation.removeUpdateListener(this));
+ }
+ if (DEBUG) print(animation);
}
+ mHandlingOnAnimationUpdate = false;
+ } else {
if (DEBUG) print(animation);
}
- mHandlingOnAnimationUpdate = false;
- } else {
- if (DEBUG) print(animation);
}
- }
- public void print(ValueAnimator animation) {
- float flatFraction = animation.getCurrentPlayTime() / (float) animation.getDuration();
- Log.d(TAG, sGlobalFrameCounter +
- "(" + (sGlobalFrameCounter - mStartFrame) + ") " + mTarget + " dirty? " +
- mTarget.isDirty() + " " + flatFraction + " " + this + " " + animation);
+ public void print(ValueAnimator animation) {
+ float flatFraction = animation.getCurrentPlayTime() / (float) animation.getDuration();
+ Log.d(TAG, mGlobalFrameCount +
+ "(" + (mGlobalFrameCount - mStartFrame) + ") " + mRootView + " dirty? " +
+ mRootView.isDirty() + " " + flatFraction + " " + this + " " + animation);
+ }
}
}
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index 6668f2c..15a9f2e 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -16,26 +16,18 @@
package com.android.launcher3;
-import static com.android.launcher3.LauncherState.ALL_APPS;
-
import android.content.Context;
import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.Gravity;
-import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewDebug;
import android.view.ViewGroup;
import android.widget.FrameLayout;
-import android.widget.TextView;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.logging.UserEventDispatcher.LogContainerProvider;
-import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
-import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType;
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
public class Hotseat extends FrameLayout implements LogContainerProvider, Insettable {
@@ -92,45 +84,6 @@
} else {
mContent.setGridSize(idp.numHotseatIcons, 1);
}
-
- if (!FeatureFlags.NO_ALL_APPS_ICON) {
- // Add the Apps button
- Context context = getContext();
- DeviceProfile grid = mLauncher.getDeviceProfile();
- int allAppsButtonRank = grid.inv.getAllAppsButtonRank();
-
- LayoutInflater inflater = LayoutInflater.from(context);
- TextView allAppsButton = (TextView)
- inflater.inflate(R.layout.all_apps_button, mContent, false);
- Drawable d = context.getResources().getDrawable(R.drawable.all_apps_button_icon);
- d.setBounds(0, 0, grid.iconSizePx, grid.iconSizePx);
-
- int scaleDownPx = getResources().getDimensionPixelSize(R.dimen.all_apps_button_scale_down);
- Rect bounds = d.getBounds();
- d.setBounds(bounds.left, bounds.top + scaleDownPx / 2, bounds.right - scaleDownPx,
- bounds.bottom - scaleDownPx / 2);
- allAppsButton.setCompoundDrawables(null, d, null, null);
-
- allAppsButton.setContentDescription(context.getString(R.string.all_apps_button_label));
- if (mLauncher != null) {
- allAppsButton.setOnClickListener((v) -> {
- if (!mLauncher.isInState(ALL_APPS)) {
- mLauncher.getUserEventDispatcher().logActionOnControl(Action.Touch.TAP,
- ControlType.ALL_APPS_BUTTON);
- mLauncher.getStateManager().goToState(ALL_APPS);
- }
- });
- allAppsButton.setOnFocusChangeListener(mLauncher.mFocusHandler);
- }
-
- // Note: We do this to ensure that the hotseat is always laid out in the orientation of
- // the hotseat in order regardless of which orientation they were added
- int x = getCellXFromOrder(allAppsButtonRank);
- int y = getCellYFromOrder(allAppsButtonRank);
- CellLayout.LayoutParams lp = new CellLayout.LayoutParams(x, y, 1, 1);
- lp.canReorder = false;
- mContent.addViewToCellLayout(allAppsButton, -1, allAppsButton.getId(), lp, true);
- }
}
@Override
diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java
index f496600..abd5538 100644
--- a/src/com/android/launcher3/IconCache.java
+++ b/src/com/android/launcher3/IconCache.java
@@ -38,8 +38,6 @@
import android.os.Process;
import android.os.SystemClock;
import android.os.UserHandle;
-import android.support.annotation.NonNull;
-import android.support.v4.graphics.ColorUtils;
import android.text.TextUtils;
import android.util.Log;
@@ -63,6 +61,9 @@
import java.util.Set;
import java.util.Stack;
+import androidx.annotation.NonNull;
+import androidx.core.graphics.ColorUtils;
+
/**
* Cache of application icons. Icons can be made from any thread.
*/
diff --git a/src/com/android/launcher3/InterruptibleInOutAnimator.java b/src/com/android/launcher3/InterruptibleInOutAnimator.java
index 8501e24..f4395ca 100644
--- a/src/com/android/launcher3/InterruptibleInOutAnimator.java
+++ b/src/com/android/launcher3/InterruptibleInOutAnimator.java
@@ -18,7 +18,9 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
+import android.util.Property;
import android.view.View;
import com.android.launcher3.util.Thunk;
@@ -31,11 +33,27 @@
* interpolator in the same direction.
*/
public class InterruptibleInOutAnimator {
+
+ private static final Property<InterruptibleInOutAnimator, Float> VALUE =
+ new Property<InterruptibleInOutAnimator, Float>(Float.TYPE, "value") {
+ @Override
+ public Float get(InterruptibleInOutAnimator anim) {
+ return anim.mValue;
+ }
+
+ @Override
+ public void set(InterruptibleInOutAnimator anim, Float value) {
+ anim.mValue = value;
+ }
+ };
+
private long mOriginalDuration;
private float mOriginalFromValue;
private float mOriginalToValue;
private ValueAnimator mAnimator;
+ private float mValue;
+
private boolean mFirstRun = true;
private Object mTag = null;
@@ -47,8 +65,8 @@
// TODO: This isn't really necessary, but is here to help diagnose a bug in the drag viz
@Thunk int mDirection = STOPPED;
- public InterruptibleInOutAnimator(View view, long duration, float fromValue, float toValue) {
- mAnimator = LauncherAnimUtils.ofFloat(fromValue, toValue).setDuration(duration);
+ public InterruptibleInOutAnimator(long duration, float fromValue, float toValue) {
+ mAnimator = ObjectAnimator.ofFloat(this, VALUE, fromValue, toValue).setDuration(duration);
mOriginalDuration = duration;
mOriginalFromValue = fromValue;
mOriginalToValue = toValue;
@@ -64,8 +82,7 @@
private void animate(int direction) {
final long currentPlayTime = mAnimator.getCurrentPlayTime();
final float toValue = (direction == IN) ? mOriginalToValue : mOriginalFromValue;
- final float startValue = mFirstRun ? mOriginalFromValue :
- ((Float) mAnimator.getAnimatedValue()).floatValue();
+ final float startValue = mFirstRun ? mOriginalFromValue : mValue;
// Make sure it's stopped before we modify any values
cancel();
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index 22bc162..f3f2238 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -22,13 +22,11 @@
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.graphics.Point;
-import android.support.annotation.VisibleForTesting;
import android.util.DisplayMetrics;
import android.util.Xml;
import android.view.Display;
import android.view.WindowManager;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.ConfigMonitor;
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.Thunk;
@@ -41,6 +39,8 @@
import java.util.Collections;
import java.util.Comparator;
+import androidx.annotation.VisibleForTesting;
+
public class InvariantDeviceProfile {
// We do not need any synchronization for this variable as its only written on UI thread.
@@ -314,17 +314,6 @@
return this;
}
- public int getAllAppsButtonRank() {
- if (FeatureFlags.IS_DOGFOOD_BUILD && FeatureFlags.NO_ALL_APPS_ICON) {
- throw new IllegalAccessError("Accessing all apps rank when all-apps is disabled");
- }
- return numHotseatIcons / 2;
- }
-
- public boolean isAllAppsButtonRank(int rank) {
- return rank == getAllAppsButtonRank();
- }
-
public DeviceProfile getDeviceProfile(Context context) {
return context.getResources().getConfiguration().orientation
== Configuration.ORIENTATION_LANDSCAPE ? landscapeProfile : portraitProfile;
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 7ab9768..7f99323 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -16,6 +16,7 @@
package com.android.launcher3;
+import static android.content.pm.ActivityInfo.CONFIG_LOCALE;
import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
@@ -39,7 +40,6 @@
import android.content.BroadcastReceiver;
import android.content.ComponentCallbacks2;
import android.content.Context;
-import android.content.ContextWrapper;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentSender;
@@ -56,7 +56,6 @@
import android.os.Process;
import android.os.StrictMode;
import android.os.UserHandle;
-import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.text.method.TextKeyListener;
import android.util.Log;
@@ -78,6 +77,7 @@
import com.android.launcher3.allapps.AllAppsContainerView;
import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.allapps.DiscoveryBounce;
+import com.android.launcher3.anim.PropertyListBuilder;
import com.android.launcher3.badge.BadgeInfo;
import com.android.launcher3.compat.AppWidgetManagerCompat;
import com.android.launcher3.compat.LauncherAppsCompatVO;
@@ -85,6 +85,7 @@
import com.android.launcher3.dragndrop.DragController;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.dragndrop.DragView;
+import com.android.launcher3.folder.Folder;
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.folder.FolderIconPreviewVerifier;
import com.android.launcher3.keyboard.CustomActionsPopup;
@@ -139,6 +140,8 @@
import java.util.List;
import java.util.Set;
+import androidx.annotation.Nullable;
+
/**
* Default launcher application.
*/
@@ -347,8 +350,19 @@
}
@Override
+ public void onEnterAnimationComplete() {
+ super.onEnterAnimationComplete();
+ UiFactory.onEnterAnimationComplete(this);
+ }
+
+ @Override
public void onConfigurationChanged(Configuration newConfig) {
int diff = newConfig.diff(mOldConfig);
+
+ if ((diff & CONFIG_LOCALE) != 0) {
+ Folder.setLocaleDependentFields(getResources(), true /* force */);
+ }
+
if ((diff & (CONFIG_ORIENTATION | CONFIG_SCREEN_SIZE)) != 0) {
mUserEventDispatcher = null;
initDeviceProfile(mDeviceProfile.inv);
@@ -727,8 +741,6 @@
@Override
protected void onStop() {
super.onStop();
- FirstFrameAnimatorHelper.setIsVisible(false);
-
if (mLauncherCallbacks != null) {
mLauncherCallbacks.onStop();
}
@@ -749,8 +761,6 @@
@Override
protected void onStart() {
super.onStart();
- FirstFrameAnimatorHelper.setIsVisible(true);
-
if (mLauncherCallbacks != null) {
mLauncherCallbacks.onStart();
}
@@ -1118,7 +1128,6 @@
public void onAttachedToWindow() {
super.onAttachedToWindow();
- FirstFrameAnimatorHelper.initializeDrawListener(getWindow().getDecorView());
if (mLauncherCallbacks != null) {
mLauncherCallbacks.onAttachedToWindow();
}
@@ -1234,7 +1243,7 @@
mAppsView.reset(isStarted() /* animate */);
}
- if (shouldMoveToDefaultScreen && !mWorkspace.isTouchActive()) {
+ if (shouldMoveToDefaultScreen && !mWorkspace.isHandlingTouch()) {
mWorkspace.post(mWorkspace::moveToDefaultScreen);
}
}
@@ -1320,9 +1329,6 @@
}
TextKeyListener.getInstance().release();
-
- LauncherAnimUtils.onDestroyActivity();
-
clearPendingBinds();
if (mLauncherCallbacks != null) {
@@ -1593,14 +1599,8 @@
AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(this);
if (topView != null && topView.onBackPressed()) {
// Handled by the floating view.
- } else if (!isInState(NORMAL)) {
- LauncherState lastState = mStateManager.getLastState();
- ued.logActionCommand(Action.Command.BACK, mStateManager.getState().containerType,
- lastState.containerType);
- mStateManager.goToState(lastState);
} else {
- // Back button is a no-op here, but give at least some feedback for the button press
- mWorkspace.showOutlinesTemporarily();
+ mStateManager.getState().onBackPressed(this);
}
}
@@ -1835,7 +1835,6 @@
@Override
public void bindItems(final List<ItemInfo> items, final boolean forceAnimateIcons) {
// Get the list of added items and intersect them with the set of items here
- final AnimatorSet anim = LauncherAnimUtils.createAnimatorSet();
final Collection<Animator> bounceAnims = new ArrayList<>();
final boolean animateIcons = forceAnimateIcons && canRunNewAppsAnimation();
Workspace workspace = mWorkspace;
@@ -1907,34 +1906,31 @@
}
}
- if (animateIcons) {
- // Animate to the correct page
- if (newItemsScreenId > -1) {
- long currentScreenId = mWorkspace.getScreenIdForPageIndex(mWorkspace.getNextPage());
- final int newScreenIndex = mWorkspace.getPageIndexForScreenId(newItemsScreenId);
- final Runnable startBounceAnimRunnable = new Runnable() {
- public void run() {
- anim.playTogether(bounceAnims);
- anim.start();
- }
- };
- if (newItemsScreenId != currentScreenId) {
- // We post the animation slightly delayed to prevent slowdowns
- // when we are loading right after we return to launcher.
- mWorkspace.postDelayed(new Runnable() {
- public void run() {
- if (mWorkspace != null) {
- AbstractFloatingView.closeAllOpenViews(Launcher.this, false);
+ // Animate to the correct page
+ if (animateIcons && newItemsScreenId > -1) {
+ AnimatorSet anim = new AnimatorSet();
+ anim.playTogether(bounceAnims);
- mWorkspace.snapToPage(newScreenIndex);
- mWorkspace.postDelayed(startBounceAnimRunnable,
- NEW_APPS_ANIMATION_DELAY);
- }
+ long currentScreenId = mWorkspace.getScreenIdForPageIndex(mWorkspace.getNextPage());
+ final int newScreenIndex = mWorkspace.getPageIndexForScreenId(newItemsScreenId);
+ final Runnable startBounceAnimRunnable = anim::start;
+
+ if (newItemsScreenId != currentScreenId) {
+ // We post the animation slightly delayed to prevent slowdowns
+ // when we are loading right after we return to launcher.
+ mWorkspace.postDelayed(new Runnable() {
+ public void run() {
+ if (mWorkspace != null) {
+ AbstractFloatingView.closeAllOpenViews(Launcher.this, false);
+
+ mWorkspace.snapToPage(newScreenIndex);
+ mWorkspace.postDelayed(startBounceAnimRunnable,
+ NEW_APPS_ANIMATION_DELAY);
}
- }, NEW_APPS_PAGE_MOVE_DELAY);
- } else {
- mWorkspace.postDelayed(startBounceAnimRunnable, NEW_APPS_ANIMATION_DELAY);
- }
+ }
+ }, NEW_APPS_PAGE_MOVE_DELAY);
+ } else {
+ mWorkspace.postDelayed(startBounceAnimRunnable, NEW_APPS_ANIMATION_DELAY);
}
}
workspace.requestLayout();
@@ -2157,8 +2153,8 @@
}
private ValueAnimator createNewAppBounceAnimation(View v, int i) {
- ValueAnimator bounceAnim = LauncherAnimUtils.ofViewAlphaAndScale(v, 1, 1, 1);
- bounceAnim.setDuration(InstallShortcutReceiver.NEW_SHORTCUT_BOUNCE_DURATION);
+ ValueAnimator bounceAnim = new PropertyListBuilder().alpha(1).scale(1).build(v)
+ .setDuration(InstallShortcutReceiver.NEW_SHORTCUT_BOUNCE_DURATION);
bounceAnim.setStartDelay(i * InstallShortcutReceiver.NEW_SHORTCUT_STAGGER_DELAY);
bounceAnim.setInterpolator(new OvershootInterpolator(BOUNCE_ANIMATION_TENSION));
return bounceAnim;
diff --git a/src/com/android/launcher3/LauncherAnimUtils.java b/src/com/android/launcher3/LauncherAnimUtils.java
index 03ffded..ac07e88 100644
--- a/src/com/android/launcher3/LauncherAnimUtils.java
+++ b/src/com/android/launcher3/LauncherAnimUtils.java
@@ -16,18 +16,9 @@
package com.android.launcher3;
-import android.animation.Animator;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
-import android.animation.PropertyValuesHolder;
-import android.animation.ValueAnimator;
import android.graphics.drawable.Drawable;
import android.util.Property;
import android.view.View;
-import android.view.ViewTreeObserver;
-
-import java.util.HashSet;
-import java.util.WeakHashMap;
public class LauncherAnimUtils {
/**
@@ -42,105 +33,6 @@
// The progress of an animation to all apps must be at least this far along to snap to all apps.
public static final float MIN_PROGRESS_TO_ALL_APPS = 0.5f;
- static WeakHashMap<Animator, Object> sAnimators = new WeakHashMap<Animator, Object>();
- static Animator.AnimatorListener sEndAnimListener = new Animator.AnimatorListener() {
- public void onAnimationStart(Animator animation) {
- sAnimators.put(animation, null);
- }
-
- public void onAnimationRepeat(Animator animation) {
- }
-
- public void onAnimationEnd(Animator animation) {
- sAnimators.remove(animation);
- }
-
- public void onAnimationCancel(Animator animation) {
- sAnimators.remove(animation);
- }
- };
-
- public static void cancelOnDestroyActivity(Animator a) {
- a.addListener(sEndAnimListener);
- }
-
- // Helper method. Assumes a draw is pending, and that if the animation's duration is 0
- // it should be cancelled
- public static void startAnimationAfterNextDraw(final Animator animator, final View view) {
- view.getViewTreeObserver().addOnDrawListener(new ViewTreeObserver.OnDrawListener() {
- private boolean mStarted = false;
-
- public void onDraw() {
- if (mStarted) return;
- mStarted = true;
- // Use this as a signal that the animation was cancelled
- if (animator.getDuration() == 0) {
- return;
- }
- animator.start();
-
- final ViewTreeObserver.OnDrawListener listener = this;
- view.post(new Runnable() {
- public void run() {
- view.getViewTreeObserver().removeOnDrawListener(listener);
- }
- });
- }
- });
- }
-
- public static void onDestroyActivity() {
- HashSet<Animator> animators = new HashSet<Animator>(sAnimators.keySet());
- for (Animator a : animators) {
- if (a.isRunning()) {
- a.cancel();
- }
- sAnimators.remove(a);
- }
- }
-
- public static AnimatorSet createAnimatorSet() {
- AnimatorSet anim = new AnimatorSet();
- cancelOnDestroyActivity(anim);
- return anim;
- }
-
- public static ValueAnimator ofFloat(float... values) {
- ValueAnimator anim = new ValueAnimator();
- anim.setFloatValues(values);
- cancelOnDestroyActivity(anim);
- return anim;
- }
-
- public static ObjectAnimator ofFloat(View target, Property<View, Float> property,
- float... values) {
- ObjectAnimator anim = ObjectAnimator.ofFloat(target, property, values);
- cancelOnDestroyActivity(anim);
- new FirstFrameAnimatorHelper(anim, target);
- return anim;
- }
-
- public static ObjectAnimator ofViewAlphaAndScale(View target,
- float alpha, float scaleX, float scaleY) {
- return ofPropertyValuesHolder(target,
- PropertyValuesHolder.ofFloat(View.ALPHA, alpha),
- PropertyValuesHolder.ofFloat(View.SCALE_X, scaleX),
- PropertyValuesHolder.ofFloat(View.SCALE_Y, scaleY));
- }
-
- public static ObjectAnimator ofPropertyValuesHolder(View target,
- PropertyValuesHolder... values) {
- return ofPropertyValuesHolder(target, target, values);
- }
-
- public static ObjectAnimator ofPropertyValuesHolder(Object target,
- View view, PropertyValuesHolder... values) {
- ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(target, values);
- cancelOnDestroyActivity(anim);
- new FirstFrameAnimatorHelper(anim, view);
- return anim;
- }
-
public static final Property<Drawable, Integer> DRAWABLE_ALPHA =
new Property<Drawable, Integer>(Integer.TYPE, "drawableAlpha") {
@Override
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 19aa795..fe9f901 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -31,7 +31,6 @@
import android.os.Looper;
import android.os.Process;
import android.os.UserHandle;
-import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
@@ -74,6 +73,8 @@
import java.util.concurrent.CancellationException;
import java.util.concurrent.Executor;
+import androidx.annotation.Nullable;
+
/**
* Maintains in-memory state of the Launcher. It is expected that there should be only one
* LauncherModel object held in a static. Also provide APIs for updating the database state
diff --git a/src/com/android/launcher3/LauncherScroller.java b/src/com/android/launcher3/LauncherScroller.java
deleted file mode 100644
index e5042c4..0000000
--- a/src/com/android/launcher3/LauncherScroller.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2006 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;
-
-import android.animation.TimeInterpolator;
-import android.content.Context;
-import android.view.animation.Interpolator;
-import android.widget.Scroller;
-
-/**
- * Extension of {@link android.widget.Scroller} with the ability to modify the
- * Interpolator post-construction.
- */
-public class LauncherScroller extends Scroller {
-
- private final InterpolatorWrapper mInterpolatorWrapper;
-
- public LauncherScroller(Context context) {
- this(context, new InterpolatorWrapper());
- }
-
- private LauncherScroller(Context context, InterpolatorWrapper interpolatorWrapper) {
- super(context, interpolatorWrapper);
- mInterpolatorWrapper = interpolatorWrapper;
- }
-
- public void setInterpolator(TimeInterpolator interpolator) {
- mInterpolatorWrapper.interpolator = interpolator;
- }
-
- private static class InterpolatorWrapper implements Interpolator {
-
- public TimeInterpolator interpolator;
-
- @Override
- public float getInterpolation(float v) {
- return interpolator == null ? v : interpolator.getInterpolation(v);
- }
- }
-}
diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java
index 8a15b24..bbe44c0 100644
--- a/src/com/android/launcher3/LauncherState.java
+++ b/src/com/android/launcher3/LauncherState.java
@@ -30,6 +30,7 @@
import com.android.launcher3.uioverrides.FastOverviewState;
import com.android.launcher3.uioverrides.OverviewState;
import com.android.launcher3.uioverrides.UiFactory;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import java.util.Arrays;
@@ -251,6 +252,16 @@
}
}
+ public void onBackPressed(Launcher launcher) {
+ if (this != NORMAL) {
+ LauncherStateManager lsm = launcher.getStateManager();
+ LauncherState lastState = lsm.getLastState();
+ launcher.getUserEventDispatcher().logActionCommand(Action.Command.BACK,
+ containerType, lastState.containerType);
+ lsm.goToState(lastState);
+ }
+ }
+
protected static void dispatchWindowStateChanged(Launcher launcher) {
launcher.getWindow().getDecorView().sendAccessibilityEvent(TYPE_WINDOW_STATE_CHANGED);
}
diff --git a/src/com/android/launcher3/LauncherStateManager.java b/src/com/android/launcher3/LauncherStateManager.java
index 3c7c1aa..fe3df95 100644
--- a/src/com/android/launcher3/LauncherStateManager.java
+++ b/src/com/android/launcher3/LauncherStateManager.java
@@ -17,6 +17,7 @@
package com.android.launcher3;
import static android.view.View.VISIBLE;
+
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_FADE;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_SCALE;
@@ -34,7 +35,6 @@
import android.animation.AnimatorSet;
import android.os.Handler;
import android.os.Looper;
-import android.support.annotation.IntDef;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
@@ -47,6 +47,8 @@
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
*
@@ -306,7 +308,13 @@
*/
public AnimatorPlaybackController createAnimationToNewWorkspace(
LauncherState fromState, LauncherState state, long duration) {
+ // Since we are creating a state animation to a different state, temporarily prevent state
+ // change as part of config reset.
+ LauncherState originalRestState = mRestState;
+ mRestState = state;
mConfig.reset();
+ mRestState = originalRestState;
+
for (StateHandler handler : getStateHandlers()) {
handler.setState(fromState);
}
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index db5dc66..394b950 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -18,6 +18,7 @@
import static com.android.launcher3.compat.AccessibilityManagerCompat.isAccessibilityEnabled;
import static com.android.launcher3.compat.AccessibilityManagerCompat.isObservedEventType;
+import static com.android.launcher3.touch.OverScroll.OVERSCROLL_DAMP_FACTOR;
import android.animation.LayoutTransition;
import android.animation.TimeInterpolator;
@@ -47,6 +48,7 @@
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.pageindicators.PageIndicator;
import com.android.launcher3.touch.OverScroll;
+import com.android.launcher3.util.OverScroller;
import com.android.launcher3.util.Thunk;
import java.util.ArrayList;
@@ -63,7 +65,6 @@
protected static final ComputePageScrollsLogic SIMPLE_SCROLL_LOGIC = (v) -> v.getVisibility() != GONE;
public static final int PAGE_SNAP_ANIMATION_DURATION = 750;
- public static final int SLOW_PAGE_SNAP_ANIMATION_DURATION = 950;
// OverScroll constants
private final static int OVERSCROLL_PAGE_SNAP_ANIMATION_DURATION = 270;
@@ -83,7 +84,6 @@
public static final int INVALID_RESTORE_PAGE = -1001;
private boolean mFreeScroll = false;
- private boolean mSettleOnPageInFreeScroll = false;
protected int mFlingThresholdVelocity;
protected int mMinFlingVelocity;
@@ -97,7 +97,7 @@
@ViewDebug.ExportedProperty(category = "launcher")
protected int mNextPage = INVALID_PAGE;
protected int mMaxScrollX;
- protected LauncherScroller mScroller;
+ protected OverScroller mScroller;
private Interpolator mDefaultInterpolator;
private VelocityTracker mVelocityTracker;
protected int mPageSpacing = 0;
@@ -109,13 +109,7 @@
private float mTotalMotionX;
protected int[] mPageScrolls;
-
- protected final static int TOUCH_STATE_REST = 0;
- protected final static int TOUCH_STATE_SCROLLING = 1;
- protected final static int TOUCH_STATE_PREV_PAGE = 2;
- protected final static int TOUCH_STATE_NEXT_PAGE = 3;
-
- protected int mTouchState = TOUCH_STATE_REST;
+ private boolean mIsBeingDragged;
protected int mTouchSlop;
private int mMaximumVelocity;
@@ -129,11 +123,6 @@
protected boolean mWasInOverscroll = false;
- // mOverScrollX is equal to getScrollX() when we're within the normal scroll range. Otherwise
- // it is equal to the scaled overscroll position. We use a separate value so as to prevent
- // the screens from continuing to translate beyond the normal bounds.
- protected int mOverScrollX;
-
protected int mUnboundedScrollX;
// Page Indicator
@@ -176,7 +165,7 @@
* Initializes various states for this workspace.
*/
protected void init() {
- mScroller = new LauncherScroller(getContext());
+ mScroller = new OverScroller(getContext());
setDefaultInterpolator(Interpolators.SCROLL);
mCurrentPage = 0;
@@ -251,7 +240,7 @@
newX = getScrollForPage(mCurrentPage);
}
scrollTo(newX, 0);
- mScroller.setFinalX(newX);
+ mScroller.startScroll(mScroller.getCurrPos(), newX - mScroller.getCurrPos());
forceFinishScroller(true);
}
@@ -356,17 +345,6 @@
@Override
public void scrollTo(int x, int y) {
- // In free scroll mode, we clamp the scrollX
- if (mFreeScroll) {
- // If the scroller is trying to move to a location beyond the maximum allowed
- // in the free scroll mode, we make sure to end the scroll operation.
- if (!mScroller.isFinished() && (x > mMaxScrollX || x < 0)) {
- forceFinishScroller(false);
- }
-
- x = Utilities.boundToRange(x, 0, mMaxScrollX);
- }
-
mUnboundedScrollX = x;
boolean isXBeforeFirstPage = mIsRtl ? (x > mMaxScrollX) : (x < 0);
@@ -396,9 +374,9 @@
overScroll(0);
mWasInOverscroll = false;
}
- mOverScrollX = x;
super.scrollTo(x, y);
}
+
}
private void sendScrollAccessibilityEvent() {
@@ -432,10 +410,9 @@
protected boolean computeScrollHelper(boolean shouldInvalidate) {
if (mScroller.computeScrollOffset()) {
// Don't bother scrolling if the page does not need to be moved
- if (getUnboundedScrollX() != mScroller.getCurrX()
- || getScrollY() != mScroller.getCurrY()
- || mOverScrollX != mScroller.getCurrX()) {
- scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
+ if (getUnboundedScrollX() != mScroller.getCurrPos()
+ || getScrollX() != mScroller.getCurrPos()) {
+ scrollTo(mScroller.getCurrPos(), 0);
}
if (shouldInvalidate) {
invalidate();
@@ -451,7 +428,7 @@
// We don't want to trigger a page end moving unless the page has settled
// and the user has stopped scrolling
- if (mTouchState == TOUCH_STATE_REST) {
+ if (!mIsBeingDragged) {
pageEndTransition();
}
@@ -812,9 +789,9 @@
}
/** Returns whether x and y originated within the buffered viewport */
- private boolean isTouchPointInViewportWithBuffer(int x, int y) {
+ private boolean isTouchPointInViewportWithBuffer(float x, float y) {
sTmpRect.set(-getMeasuredWidth() / 2, 0, 3 * getMeasuredWidth() / 2, getMeasuredHeight());
- return sTmpRect.contains(x, y);
+ return sTmpRect.contains((int) x, (int) y);
}
@Override
@@ -835,8 +812,7 @@
* motion.
*/
final int action = ev.getAction();
- if ((action == MotionEvent.ACTION_MOVE) &&
- (mTouchState == TOUCH_STATE_SCROLLING)) {
+ if ((action == MotionEvent.ACTION_MOVE) && mIsBeingDragged) {
return true;
}
@@ -873,21 +849,17 @@
* otherwise don't. mScroller.isFinished should be false when
* being flinged.
*/
- final int xDist = Math.abs(mScroller.getFinalX() - mScroller.getCurrX());
+ final int xDist = Math.abs(mScroller.getFinalPos() - mScroller.getCurrPos());
final boolean finishedScrolling = (mScroller.isFinished() || xDist < mTouchSlop / 3);
if (finishedScrolling) {
- mTouchState = TOUCH_STATE_REST;
+ mIsBeingDragged = false;
if (!mScroller.isFinished() && !mFreeScroll) {
setCurrentPage(getNextPage());
pageEndTransition();
}
} else {
- if (isTouchPointInViewportWithBuffer((int) mDownMotionX, (int) mDownMotionY)) {
- mTouchState = TOUCH_STATE_SCROLLING;
- } else {
- mTouchState = TOUCH_STATE_REST;
- }
+ mIsBeingDragged = isTouchPointInViewportWithBuffer(mDownMotionX, mDownMotionY);
}
break;
@@ -908,11 +880,11 @@
* The only time we want to intercept motion events is if we are in the
* drag mode.
*/
- return mTouchState != TOUCH_STATE_REST;
+ return mIsBeingDragged;
}
public boolean isHandlingTouch() {
- return mTouchState != TOUCH_STATE_REST;
+ return mIsBeingDragged;
}
protected void determineScrollingStart(MotionEvent ev) {
@@ -931,7 +903,7 @@
// Disallow scrolling if we started the gesture from outside the viewport
final float x = ev.getX(pointerIndex);
final float y = ev.getY(pointerIndex);
- if (!isTouchPointInViewportWithBuffer((int) x, (int) y)) return;
+ if (!isTouchPointInViewportWithBuffer(x, y)) return;
final int xDiff = (int) Math.abs(x - mLastMotionX);
@@ -940,7 +912,7 @@
if (xMoved) {
// Scroll if the user moved far enough along the X axis
- mTouchState = TOUCH_STATE_SCROLLING;
+ mIsBeingDragged = true;
mTotalMotionX += Math.abs(mLastMotionX - x);
mLastMotionX = x;
mLastMotionXRemainder = 0;
@@ -1008,31 +980,34 @@
}
}
- protected void dampedOverScroll(float amount) {
- if (Float.compare(amount, 0f) == 0) return;
+ protected void dampedOverScroll(int amount) {
+ if (amount == 0) return;
int overScrollAmount = OverScroll.dampedScroll(amount, getMeasuredWidth());
if (amount < 0) {
- mOverScrollX = overScrollAmount;
- super.scrollTo(mOverScrollX, getScrollY());
+ super.scrollTo(overScrollAmount, getScrollY());
} else {
- mOverScrollX = mMaxScrollX + overScrollAmount;
- super.scrollTo(mOverScrollX, getScrollY());
+ super.scrollTo(mMaxScrollX + overScrollAmount, getScrollY());
}
invalidate();
}
- protected void overScroll(float amount) {
- dampedOverScroll(amount);
+ protected void overScroll(int amount) {
+ if (amount == 0) return;
+
+ if (mFreeScroll && !mScroller.isFinished()) {
+ if (amount < 0) {
+ super.scrollTo(amount, getScrollY());
+ } else {
+ super.scrollTo(mMaxScrollX + amount, getScrollY());
+ }
+ } else {
+ dampedOverScroll(amount);
+ }
}
- protected void enableFreeScroll(boolean settleOnPageInFreeScroll) {
- setEnableFreeScroll(true);
- mSettleOnPageInFreeScroll = settleOnPageInFreeScroll;
- }
-
- private void setEnableFreeScroll(boolean freeScroll) {
+ protected void setEnableFreeScroll(boolean freeScroll) {
boolean wasFreeScroll = mFreeScroll;
mFreeScroll = freeScroll;
@@ -1041,8 +1016,6 @@
} else if (wasFreeScroll) {
snapToPage(getNextPage());
}
-
- setEnableOverscroll(!freeScroll);
}
protected void setEnableOverscroll(boolean enable) {
@@ -1077,14 +1050,14 @@
mTotalMotionX = 0;
mActivePointerId = ev.getPointerId(0);
- if (mTouchState == TOUCH_STATE_SCROLLING) {
+ if (mIsBeingDragged) {
onScrollInteractionBegin();
pageBeginTransition();
}
break;
case MotionEvent.ACTION_MOVE:
- if (mTouchState == TOUCH_STATE_SCROLLING) {
+ if (mIsBeingDragged) {
// Scroll to follow the motion event
final int pointerIndex = ev.findPointerIndex(mActivePointerId);
@@ -1111,7 +1084,7 @@
break;
case MotionEvent.ACTION_UP:
- if (mTouchState == TOUCH_STATE_SCROLLING) {
+ if (mIsBeingDragged) {
final int activePointerId = mActivePointerId;
final int pointerIndex = ev.findPointerIndex(activePointerId);
final float x = ev.getX(pointerIndex);
@@ -1125,6 +1098,8 @@
mTotalMotionX += Math.abs(mLastMotionX + mLastMotionXRemainder - x);
boolean isFling = mTotalMotionX > mTouchSlop && shouldFlingForVelocity(velocityX);
+ boolean isDeltaXLeft = mIsRtl ? deltaX > 0 : deltaX < 0;
+ boolean isVelocityXLeft = mIsRtl ? velocityX > 0 : velocityX < 0;
if (!mFreeScroll) {
// In the case that the page is moved far to one direction and then is flung
@@ -1140,8 +1115,7 @@
// We give flings precedence over large moves, which is why we short-circuit our
// test for a large move if a fling has been registered. That is, a large
// move to the left and fling to the right will register as a fling to the right.
- boolean isDeltaXLeft = mIsRtl ? deltaX > 0 : deltaX < 0;
- boolean isVelocityXLeft = mIsRtl ? velocityX > 0 : velocityX < 0;
+
if (((isSignificantMove && !isDeltaXLeft && !isFling) ||
(isFling && !isVelocityXLeft)) && mCurrentPage > 0) {
finalPage = returnToOriginalPage ? mCurrentPage : mCurrentPage - 1;
@@ -1159,60 +1133,44 @@
abortScrollerAnimation(true);
}
- float scaleX = getScaleX();
- int vX = (int) (-velocityX * scaleX);
- int initialScrollX = (int) (getScrollX() * scaleX);
+ int initialScrollX = getScrollX();
- mScroller.setInterpolator(mDefaultInterpolator);
- mScroller.fling(initialScrollX,
- getScrollY(), vX, 0, Integer.MIN_VALUE, Integer.MAX_VALUE, 0, 0);
- int unscaledScrollX = (int) (mScroller.getFinalX() / scaleX);
- mNextPage = getPageNearestToCenterOfScreen(unscaledScrollX);
- int firstPageScroll = getScrollForPage(!mIsRtl ? 0 : getPageCount() - 1);
- int lastPageScroll = getScrollForPage(!mIsRtl ? getPageCount() - 1 : 0);
- if (mSettleOnPageInFreeScroll && unscaledScrollX > 0
- && unscaledScrollX < mMaxScrollX) {
- // If scrolling ends in the half of the added space that is closer to the
- // end, settle to the end. Otherwise snap to the nearest page.
- // If flinging past one of the ends, don't change the velocity as it will
- // get stopped at the end anyway.
- final int finalX = unscaledScrollX < firstPageScroll / 2 ?
- 0 :
- unscaledScrollX > (lastPageScroll + mMaxScrollX) / 2 ?
- mMaxScrollX :
- getScrollForPage(mNextPage);
+ if (((initialScrollX >= mMaxScrollX) && (isVelocityXLeft || !isFling)) ||
+ ((initialScrollX <= 0) && (!isVelocityXLeft || !isFling))) {
+ mScroller.springBack(getScrollX(), 0, mMaxScrollX);
+ } else {
+ mScroller.setInterpolator(mDefaultInterpolator);
+ mScroller.fling(initialScrollX, -velocityX,
+ 0, mMaxScrollX,
+ Math.round(getWidth() * 0.5f * OVERSCROLL_DAMP_FACTOR));
- mScroller.setFinalX((int) (finalX * getScaleX()));
- // Ensure the scroll/snap doesn't happen too fast;
- int extraScrollDuration = OVERSCROLL_PAGE_SNAP_ANIMATION_DURATION
- - mScroller.getDuration();
- if (extraScrollDuration > 0) {
- mScroller.extendDuration(extraScrollDuration);
+ int finalX = mScroller.getFinalPos();
+ mNextPage = getPageNearestToCenterOfScreen(finalX);
+
+ int firstPageScroll = getScrollForPage(!mIsRtl ? 0 : getPageCount() - 1);
+ int lastPageScroll = getScrollForPage(!mIsRtl ? getPageCount() - 1 : 0);
+ if (finalX > 0 && finalX < mMaxScrollX) {
+ // If scrolling ends in the half of the added space that is closer to
+ // the end, settle to the end. Otherwise snap to the nearest page.
+ // If flinging past one of the ends, don't change the velocity as it
+ // will get stopped at the end anyway.
+ int pageSnappedX = finalX < firstPageScroll / 2 ? 0
+ : finalX > (lastPageScroll + mMaxScrollX) / 2
+ ? mMaxScrollX
+ : getScrollForPage(mNextPage);
+
+ mScroller.setFinalPos(pageSnappedX);
+ // Ensure the scroll/snap doesn't happen too fast;
+ int extraScrollDuration = OVERSCROLL_PAGE_SNAP_ANIMATION_DURATION
+ - mScroller.getDuration();
+ if (extraScrollDuration > 0) {
+ mScroller.extendDuration(extraScrollDuration);
+ }
}
}
invalidate();
}
onScrollInteractionEnd();
- } else if (mTouchState == TOUCH_STATE_PREV_PAGE) {
- // at this point we have not moved beyond the touch slop
- // (otherwise mTouchState would be TOUCH_STATE_SCROLLING), so
- // we can just page
- int nextPage = Math.max(0, mCurrentPage - 1);
- if (nextPage != mCurrentPage) {
- snapToPage(nextPage);
- } else {
- snapToDestination();
- }
- } else if (mTouchState == TOUCH_STATE_NEXT_PAGE) {
- // at this point we have not moved beyond the touch slop
- // (otherwise mTouchState would be TOUCH_STATE_SCROLLING), so
- // we can just page
- int nextPage = Math.min(getChildCount() - 1, mCurrentPage + 1);
- if (nextPage != mCurrentPage) {
- snapToPage(nextPage);
- } else {
- snapToDestination();
- }
}
// End any intermediate reordering states
@@ -1220,7 +1178,7 @@
break;
case MotionEvent.ACTION_CANCEL:
- if (mTouchState == TOUCH_STATE_SCROLLING) {
+ if (mIsBeingDragged) {
snapToDestination();
onScrollInteractionEnd();
}
@@ -1242,7 +1200,7 @@
private void resetTouchState() {
releaseVelocityTracker();
- mTouchState = TOUCH_STATE_REST;
+ mIsBeingDragged = false;
mActivePointerId = INVALID_POINTER;
}
@@ -1356,7 +1314,7 @@
}
protected boolean isInOverScroll() {
- return (mOverScrollX > mMaxScrollX || mOverScrollX < 0);
+ return (getScrollX() > mMaxScrollX || getScrollX() < 0);
}
protected int getPageSnapDuration() {
@@ -1475,7 +1433,7 @@
mScroller.setInterpolator(mDefaultInterpolator);
}
- mScroller.startScroll(getUnboundedScrollX(), 0, delta, 0, duration);
+ mScroller.startScroll(getUnboundedScrollX(), delta, duration);
updatePageIndicator();
diff --git a/src/com/android/launcher3/PromiseAppInfo.java b/src/com/android/launcher3/PromiseAppInfo.java
index ea9f752..ea151cd 100644
--- a/src/com/android/launcher3/PromiseAppInfo.java
+++ b/src/com/android/launcher3/PromiseAppInfo.java
@@ -18,11 +18,12 @@
import android.content.Context;
import android.content.Intent;
-import android.support.annotation.NonNull;
import com.android.launcher3.compat.PackageInstallerCompat;
import com.android.launcher3.util.PackageManagerHelper;
+import androidx.annotation.NonNull;
+
public class PromiseAppInfo extends AppInfo {
public int level = 0;
diff --git a/src/com/android/launcher3/TestProtocol.java b/src/com/android/launcher3/TestProtocol.java
new file mode 100644
index 0000000..0a3b86d
--- /dev/null
+++ b/src/com/android/launcher3/TestProtocol.java
@@ -0,0 +1,27 @@
+/*
+ * 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;
+
+/**
+ * Protocol for custom accessibility events for communication with UI Automation tests.
+ */
+public final class TestProtocol {
+ public static final String GET_SCROLL_MESSAGE = "TAPL_GET_SCROLL";
+ public static final String SCROLL_Y_FIELD = "scrollY";
+ public static final String SWITCHED_TO_STATE_MESSAGE = "TAPL_SWITCHED_TO_STATE";
+ public static final String RESPONSE_MESSAGE_POSTFIX = "_RESPONSE";
+}
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 8683b21..1c12464 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -16,6 +16,7 @@
package com.android.launcher3;
+import android.app.ActivityManager;
import android.app.WallpaperManager;
import android.content.ComponentName;
import android.content.Context;
@@ -82,6 +83,10 @@
private static final Matrix sMatrix = new Matrix();
private static final Matrix sInverseMatrix = new Matrix();
+ public static final boolean ATLEAST_Q = Build.VERSION.CODENAME.length() == 1
+ && Build.VERSION.CODENAME.charAt(0) >= 'Q'
+ && Build.VERSION.CODENAME.charAt(0) <= 'Z';
+
public static final boolean ATLEAST_P =
Build.VERSION.SDK_INT >= Build.VERSION_CODES.P;
@@ -130,6 +135,9 @@
CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
+ public static final boolean IS_RUNNING_IN_TEST_HARNESS =
+ ActivityManager.isRunningInTestHarness();
+
public static boolean isPropertyEnabled(String propertyName) {
return Log.isLoggable(propertyName, Log.VERBOSE);
}
@@ -598,4 +606,8 @@
msg.setAsynchronous(true);
handler.sendMessage(msg);
}
+
+ public interface Consumer<T> {
+ void accept(T var1);
+ }
}
diff --git a/src/com/android/launcher3/WidgetPreviewLoader.java b/src/com/android/launcher3/WidgetPreviewLoader.java
index 7af4bf9..84bad08 100644
--- a/src/com/android/launcher3/WidgetPreviewLoader.java
+++ b/src/com/android/launcher3/WidgetPreviewLoader.java
@@ -25,7 +25,6 @@
import android.os.CancellationSignal;
import android.os.Handler;
import android.os.UserHandle;
-import android.support.annotation.Nullable;
import android.util.Log;
import android.util.LongSparseArray;
@@ -51,6 +50,8 @@
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
+import androidx.annotation.Nullable;
+
public class WidgetPreviewLoader {
private static final String TAG = "WidgetPreviewLoader";
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 67bdd3b..d652fe0 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -54,6 +54,7 @@
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
+import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.Toast;
import com.android.launcher3.Launcher.LauncherOverlay;
@@ -286,7 +287,9 @@
mInsets.set(insets);
DeviceProfile grid = mLauncher.getDeviceProfile();
- mMaxDistanceForFolderCreation = (0.55f * grid.iconSizePx);
+ mMaxDistanceForFolderCreation = grid.isTablet
+ ? 0.75f * grid.iconSizePx
+ : 0.55f * grid.iconSizePx;
mWorkspaceFadeInAdjacentScreens = grid.shouldFadeAdjacentWorkspaceScreens();
Rect padding = grid.workspacePadding;
@@ -471,10 +474,6 @@
super.onViewAdded(child);
}
- public boolean isTouchActive() {
- return mTouchState != TOUCH_STATE_REST;
- }
-
/**
* Initializes and binds the first page
* @param qsb an existing qsb to recycle or null.
@@ -547,7 +546,6 @@
// created CellLayout.
CellLayout newScreen = (CellLayout) LayoutInflater.from(getContext()).inflate(
R.layout.workspace_screen, this, false /* attachToRoot */);
- newScreen.getShortcutsAndWidgets().setId(R.id.workspace_page_container);
int paddingLeftRight = mLauncher.getDeviceProfile().cellLayoutPaddingLeftRightPx;
int paddingBottom = mLauncher.getDeviceProfile().cellLayoutBottomPaddingPx;
newScreen.setPadding(paddingLeftRight, 0, paddingLeftRight, paddingBottom);
@@ -1034,7 +1032,7 @@
}
protected void onScrollInteractionBegin() {
- super.onScrollInteractionEnd();
+ super.onScrollInteractionBegin();
mScrollInteractionBegan = true;
}
@@ -1098,7 +1096,7 @@
}
@Override
- protected void overScroll(float amount) {
+ protected void overScroll(int amount) {
boolean shouldScrollOverlay = mLauncherOverlay != null &&
((amount <= 0 && !mIsRtl) || (amount >= 0 && mIsRtl));
@@ -1111,7 +1109,7 @@
mLauncherOverlay.onScrollInteractionBegin();
}
- mLastOverlayScroll = Math.abs(amount / getMeasuredWidth());
+ mLastOverlayScroll = Math.abs(((float) amount) / getMeasuredWidth());
mLauncherOverlay.onScrollChange(mLastOverlayScroll, mIsRtl);
} else {
dampedOverScroll(amount);
@@ -1289,12 +1287,6 @@
}
}
- public void showOutlinesTemporarily() {
- if (!mIsPageInTransition && !isTouchActive()) {
- snapToPage(mCurrentPage);
- }
- }
-
private void updatePageAlphaValues() {
// We need to check the isDragging case because updatePageAlphaValues is called between
// goToState(SPRING_LOADED) and onStartStateTransition.
@@ -1493,6 +1485,18 @@
}
}
+ @Override
+ public AccessibilityNodeInfo createAccessibilityNodeInfo() {
+ if (getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) {
+ // TAPL tests verify that workspace is not present in Overview and AllApps states.
+ // TAPL can work only if UIDevice is set up as setCompressedLayoutHeirarchy(false).
+ // Hiding workspace from the tests when it's
+ // IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS.
+ return null;
+ }
+ return super.createAccessibilityNodeInfo();
+ }
+
private void updateAccessibilityFlags(int accessibilityFlag, CellLayout page) {
page.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
page.getShortcutsAndWidgets().setImportantForAccessibility(accessibilityFlag);
@@ -2019,22 +2023,8 @@
}
public void onNoCellFound(View dropTargetLayout) {
- if (mLauncher.isHotseatLayout(dropTargetLayout)) {
- Hotseat hotseat = mLauncher.getHotseat();
- boolean droppedOnAllAppsIcon = !FeatureFlags.NO_ALL_APPS_ICON
- && mTargetCell != null && !mLauncher.getDeviceProfile().inv.isAllAppsButtonRank(
- hotseat.getOrderInHotseat(mTargetCell[0], mTargetCell[1]));
- if (!droppedOnAllAppsIcon) {
- // Only show message when hotseat is full and drop target was not AllApps button
- showOutOfSpaceMessage(true);
- }
- } else {
- showOutOfSpaceMessage(false);
- }
- }
-
- private void showOutOfSpaceMessage(boolean isHotseatLayout) {
- int strId = (isHotseatLayout ? R.string.hotseat_out_of_space : R.string.out_of_space);
+ int strId = mLauncher.isHotseatLayout(dropTargetLayout)
+ ? R.string.hotseat_out_of_space : R.string.out_of_space;
Toast.makeText(mLauncher, mLauncher.getString(strId), Toast.LENGTH_SHORT).show();
}
@@ -2630,16 +2620,10 @@
case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT:
- if (info.container == NO_ID) {
+ if (info.container == NO_ID && info instanceof AppInfo) {
// Came from all apps -- make a copy
- if (info instanceof AppInfo) {
- info = ((AppInfo) info).makeShortcut();
- d.dragInfo = info;
- } else if (info instanceof ShortcutInfo) {
- info = new ShortcutInfo((ShortcutInfo) info);
- d.dragInfo = info;
- }
-
+ info = ((AppInfo) info).makeShortcut();
+ d.dragInfo = info;
}
view = mLauncher.createShortcut(cellLayout, (ShortcutInfo) info);
break;
diff --git a/src/com/android/launcher3/accessibility/DragAndDropAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/DragAndDropAccessibilityDelegate.java
index bd3bb4d..117296d 100644
--- a/src/com/android/launcher3/accessibility/DragAndDropAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/DragAndDropAccessibilityDelegate.java
@@ -19,8 +19,6 @@
import android.content.Context;
import android.graphics.Rect;
import android.os.Bundle;
-import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
-import android.support.v4.widget.ExploreByTouchHelper;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.accessibility.AccessibilityEvent;
@@ -31,6 +29,9 @@
import java.util.List;
+import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
+import androidx.customview.widget.ExploreByTouchHelper;
+
/**
* Helper class to make drag-and-drop in a {@link CellLayout} accessible.
*/
diff --git a/src/com/android/launcher3/accessibility/WorkspaceAccessibilityHelper.java b/src/com/android/launcher3/accessibility/WorkspaceAccessibilityHelper.java
index e6f120f..1c088db 100644
--- a/src/com/android/launcher3/accessibility/WorkspaceAccessibilityHelper.java
+++ b/src/com/android/launcher3/accessibility/WorkspaceAccessibilityHelper.java
@@ -18,7 +18,6 @@
import android.content.Context;
import android.graphics.Rect;
-import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
import android.text.TextUtils;
import android.view.View;
@@ -32,6 +31,8 @@
import com.android.launcher3.accessibility.LauncherAccessibilityDelegate.DragType;
import com.android.launcher3.dragndrop.DragLayer;
+import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
+
/**
* Implementation of {@link DragAndDropAccessibilityDelegate} to support DnD on workspace.
*/
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index fdf32af..6908ab4 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -21,13 +21,8 @@
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect;
+import android.os.Bundle;
import android.os.Process;
-import android.support.animation.DynamicAnimation;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.StringRes;
-import android.support.v7.widget.LinearLayoutManager;
-import android.support.v7.widget.RecyclerView;
import android.text.Selection;
import android.text.SpannableStringBuilder;
import android.util.AttributeSet;
@@ -47,7 +42,9 @@
import com.android.launcher3.ItemInfo;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
+import com.android.launcher3.TestProtocol;
import com.android.launcher3.Utilities;
+import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.keyboard.FocusedItemDecorator;
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
@@ -57,6 +54,13 @@
import com.android.launcher3.views.RecyclerViewFastScroller;
import com.android.launcher3.views.SpringRelativeLayout;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.StringRes;
+import androidx.dynamicanimation.animation.DynamicAnimation;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
/**
* The all apps view container.
*/
@@ -388,6 +392,26 @@
}
}
+ // Used by tests only
+ private boolean isDescendantViewVisible(int viewId) {
+ final View view = findViewById(viewId);
+ if (view == null) return false;
+
+ if (!view.isShown()) return false;
+
+ return view.getGlobalVisibleRect(new Rect());
+ }
+
+ // Used by tests only
+ public boolean isPersonalTabVisible() {
+ return isDescendantViewVisible(R.id.tab_personal);
+ }
+
+ // Used by tests only
+ public boolean isWorkTabVisible() {
+ return isDescendantViewVisible(R.id.tab_work);
+ }
+
public AlphabeticalAppsList getApps() {
return mAH[AdapterHolder.MAIN].appsList;
}
@@ -549,4 +573,17 @@
&& verticalFadingEdge);
}
}
+
+ @Override
+ public boolean performAccessibilityAction(int action, Bundle arguments) {
+ if (AccessibilityManagerCompat.processTestRequest(
+ mLauncher, TestProtocol.GET_SCROLL_MESSAGE, action, arguments,
+ response ->
+ response.putInt(TestProtocol.SCROLL_Y_FIELD,
+ getActiveRecyclerView().getCurrentScrollY()))) {
+ return true;
+ }
+
+ return super.performAccessibilityAction(action, arguments);
+ }
}
diff --git a/src/com/android/launcher3/allapps/AllAppsFastScrollHelper.java b/src/com/android/launcher3/allapps/AllAppsFastScrollHelper.java
index e08cb15..3ee1293 100644
--- a/src/com/android/launcher3/allapps/AllAppsFastScrollHelper.java
+++ b/src/com/android/launcher3/allapps/AllAppsFastScrollHelper.java
@@ -15,13 +15,13 @@
*/
package com.android.launcher3.allapps;
-import android.support.v7.widget.RecyclerView;
-
import com.android.launcher3.util.Thunk;
import java.util.HashSet;
import java.util.List;
+import androidx.recyclerview.widget.RecyclerView;
+
public class AllAppsFastScrollHelper implements AllAppsGridAdapter.BindViewCallback {
private static final int INITIAL_TOUCH_SETTLING_DURATION = 100;
diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
index 27fc53a..0f13550 100644
--- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
+++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
@@ -18,11 +18,6 @@
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
-import android.support.v4.view.accessibility.AccessibilityEventCompat;
-import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
-import android.support.v4.view.accessibility.AccessibilityRecordCompat;
-import android.support.v7.widget.GridLayoutManager;
-import android.support.v7.widget.RecyclerView;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
@@ -44,6 +39,12 @@
import java.util.List;
+import androidx.core.view.accessibility.AccessibilityEventCompat;
+import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
+import androidx.core.view.accessibility.AccessibilityRecordCompat;
+import androidx.recyclerview.widget.GridLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
/**
* The grid view adapter of all the apps.
*/
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
index a6c1346..adc4a72 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -21,7 +21,6 @@
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
-import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.util.SparseIntArray;
import android.view.MotionEvent;
@@ -41,6 +40,8 @@
import java.util.List;
+import androidx.recyclerview.widget.RecyclerView;
+
/**
* A RecyclerView with custom fast scroll support for the all apps view.
*/
diff --git a/src/com/android/launcher3/allapps/FloatingHeaderView.java b/src/com/android/launcher3/allapps/FloatingHeaderView.java
index eaa7774..5348349 100644
--- a/src/com/android/launcher3/allapps/FloatingHeaderView.java
+++ b/src/com/android/launcher3/allapps/FloatingHeaderView.java
@@ -19,9 +19,6 @@
import android.content.Context;
import android.graphics.Point;
import android.graphics.Rect;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
@@ -32,6 +29,10 @@
import com.android.launcher3.R;
import com.android.launcher3.anim.PropertySetter;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.recyclerview.widget.RecyclerView;
+
public class FloatingHeaderView extends LinearLayout implements
ValueAnimator.AnimatorUpdateListener {
diff --git a/src/com/android/launcher3/allapps/PersonalWorkSlidingTabStrip.java b/src/com/android/launcher3/allapps/PersonalWorkSlidingTabStrip.java
index 31c5914..decdcc0 100644
--- a/src/com/android/launcher3/allapps/PersonalWorkSlidingTabStrip.java
+++ b/src/com/android/launcher3/allapps/PersonalWorkSlidingTabStrip.java
@@ -19,8 +19,6 @@
import android.content.SharedPreferences;
import android.graphics.Canvas;
import android.graphics.Paint;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
import android.widget.Button;
@@ -32,6 +30,9 @@
import com.android.launcher3.pageindicators.PageIndicator;
import com.android.launcher3.util.Themes;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
/**
* Supports two indicator colors, dedicated for personal and work tabs.
*/
diff --git a/src/com/android/launcher3/allapps/WorkModeSwitch.java b/src/com/android/launcher3/allapps/WorkModeSwitch.java
index d529f6f..717bbd4 100644
--- a/src/com/android/launcher3/allapps/WorkModeSwitch.java
+++ b/src/com/android/launcher3/allapps/WorkModeSwitch.java
@@ -25,6 +25,7 @@
import com.android.launcher3.compat.UserManagerCompat;
+import java.lang.ref.WeakReference;
import java.util.List;
public class WorkModeSwitch extends Switch {
@@ -67,34 +68,57 @@
}
private void trySetQuietModeEnabledToAllProfilesAsync(boolean enabled) {
- new AsyncTask<Void, Void, Boolean>() {
+ new SetQuietModeEnabledAsyncTask(enabled, new WeakReference<>(this)).execute();
+ }
- @Override
- protected void onPreExecute() {
- super.onPreExecute();
- setEnabled(false);
+ private static final class SetQuietModeEnabledAsyncTask
+ extends AsyncTask<Void, Void, Boolean> {
+
+ private final boolean enabled;
+ private final WeakReference<WorkModeSwitch> switchWeakReference;
+
+ SetQuietModeEnabledAsyncTask(boolean enabled,
+ WeakReference<WorkModeSwitch> switchWeakReference) {
+ this.enabled = enabled;
+ this.switchWeakReference = switchWeakReference;
+ }
+
+ @Override
+ protected void onPreExecute() {
+ super.onPreExecute();
+ WorkModeSwitch workModeSwitch = switchWeakReference.get();
+ if (workModeSwitch != null) {
+ workModeSwitch.setEnabled(false);
}
+ }
- @Override
- protected Boolean doInBackground(Void... voids) {
- UserManagerCompat userManager = UserManagerCompat.getInstance(getContext());
- List<UserHandle> userProfiles = userManager.getUserProfiles();
- boolean showConfirm = false;
- for (UserHandle userProfile : userProfiles) {
- if (Process.myUserHandle().equals(userProfile)) {
- continue;
- }
- showConfirm |= !userManager.requestQuietModeEnabled(enabled, userProfile);
+ @Override
+ protected Boolean doInBackground(Void... voids) {
+ WorkModeSwitch workModeSwitch = switchWeakReference.get();
+ if (workModeSwitch == null) {
+ return false;
+ }
+ UserManagerCompat userManager =
+ UserManagerCompat.getInstance(workModeSwitch.getContext());
+ List<UserHandle> userProfiles = userManager.getUserProfiles();
+ boolean showConfirm = false;
+ for (UserHandle userProfile : userProfiles) {
+ if (Process.myUserHandle().equals(userProfile)) {
+ continue;
}
- return showConfirm;
+ showConfirm |= !userManager.requestQuietModeEnabled(enabled, userProfile);
}
+ return showConfirm;
+ }
- @Override
- protected void onPostExecute(Boolean showConfirm) {
- if (showConfirm) {
- setEnabled(true);
+ @Override
+ protected void onPostExecute(Boolean showConfirm) {
+ if (showConfirm) {
+ WorkModeSwitch workModeSwitch = switchWeakReference.get();
+ if (workModeSwitch != null) {
+ workModeSwitch.setEnabled(true);
}
}
- }.execute();
+ }
}
}
diff --git a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
index dcc4554..91be504 100644
--- a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
+++ b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
@@ -15,8 +15,6 @@
*/
package com.android.launcher3.allapps.search;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
diff --git a/src/com/android/launcher3/anim/AnimatorSetBuilder.java b/src/com/android/launcher3/anim/AnimatorSetBuilder.java
index 307f258..fdac5c8 100644
--- a/src/com/android/launcher3/anim/AnimatorSetBuilder.java
+++ b/src/com/android/launcher3/anim/AnimatorSetBuilder.java
@@ -20,8 +20,6 @@
import android.util.SparseArray;
import android.view.animation.Interpolator;
-import com.android.launcher3.LauncherAnimUtils;
-
import java.util.ArrayList;
import java.util.List;
@@ -56,7 +54,7 @@
}
public AnimatorSet build() {
- AnimatorSet anim = LauncherAnimUtils.createAnimatorSet();
+ AnimatorSet anim = new AnimatorSet();
anim.playTogether(mAnims);
if (!mOnFinishRunnables.isEmpty()) {
anim.addListener(new AnimationSuccessListener() {
diff --git a/src/com/android/launcher3/anim/PropertyListBuilder.java b/src/com/android/launcher3/anim/PropertyListBuilder.java
index 33e7f66..acc3b45 100644
--- a/src/com/android/launcher3/anim/PropertyListBuilder.java
+++ b/src/com/android/launcher3/anim/PropertyListBuilder.java
@@ -1,5 +1,6 @@
package com.android.launcher3.anim;
+import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.view.View;
@@ -44,7 +45,8 @@
return this;
}
- public PropertyValuesHolder[] build() {
- return mProperties.toArray(new PropertyValuesHolder[mProperties.size()]);
+ public ObjectAnimator build(View view) {
+ return ObjectAnimator.ofPropertyValuesHolder(view,
+ mProperties.toArray(new PropertyValuesHolder[mProperties.size()]));
}
}
diff --git a/src/com/android/launcher3/badge/BadgeRenderer.java b/src/com/android/launcher3/badge/BadgeRenderer.java
index 9487427..8998b24 100644
--- a/src/com/android/launcher3/badge/BadgeRenderer.java
+++ b/src/com/android/launcher3/badge/BadgeRenderer.java
@@ -60,6 +60,7 @@
int size = (int) (DOT_SCALE * mDotCenterOffset);
ShadowGenerator.Builder builder = new ShadowGenerator.Builder(Color.TRANSPARENT);
+ builder.ambientShadowAlpha = 88;
mBackgroundWithShadow = builder.setupBlurForSize(size).createPill(size, size);
mCircleRadius = builder.radius;
diff --git a/src/com/android/launcher3/compat/AccessibilityManagerCompat.java b/src/com/android/launcher3/compat/AccessibilityManagerCompat.java
index 0c78381..02da861 100644
--- a/src/com/android/launcher3/compat/AccessibilityManagerCompat.java
+++ b/src/com/android/launcher3/compat/AccessibilityManagerCompat.java
@@ -17,9 +17,14 @@
package com.android.launcher3.compat;
import android.content.Context;
+import android.os.Bundle;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.AccessibilityNodeInfo;
+
+import com.android.launcher3.TestProtocol;
+import com.android.launcher3.Utilities;
public class AccessibilityManagerCompat {
@@ -44,4 +49,56 @@
private static AccessibilityManager getManager(Context context) {
return (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE);
}
+
+ public static void sendEventToTest(Context context, String eventTag) {
+ final AccessibilityManager accessibilityManager = getAccessibilityManagerForTest(context);
+ if (accessibilityManager == null) return;
+
+ sendEventToTest(accessibilityManager, eventTag, null);
+ }
+
+ private static void sendEventToTest(
+ AccessibilityManager accessibilityManager, String eventTag, Bundle data) {
+ final AccessibilityEvent e = AccessibilityEvent.obtain(
+ AccessibilityEvent.TYPE_ANNOUNCEMENT);
+ e.setClassName(eventTag);
+ e.setParcelableData(data);
+ accessibilityManager.sendAccessibilityEvent(e);
+ }
+
+ /**
+ * Returns accessibility manager to be used for communication with UI Automation tests.
+ * The tests may exchange custom accessibility messages with the launcher; the accessibility
+ * manager is used in these communications.
+ *
+ * If the launcher runs not under a test, the return is null, and no attempt to process or send
+ * custom accessibility messages should be made.
+ */
+ private static AccessibilityManager getAccessibilityManagerForTest(Context context) {
+ // If not running in a test harness, don't participate in test exchanges.
+ if (!Utilities.IS_RUNNING_IN_TEST_HARNESS) return null;
+
+ final AccessibilityManager accessibilityManager = getManager(context);
+ if (!accessibilityManager.isEnabled()) return null;
+
+ return accessibilityManager;
+ }
+
+ public static boolean processTestRequest(Context context, String eventTag, int action,
+ Bundle request, Utilities.Consumer<Bundle> responseFiller) {
+ final AccessibilityManager accessibilityManager = getAccessibilityManagerForTest(context);
+ if (accessibilityManager == null) return false;
+
+ // The test sends a request via a ACTION_SET_TEXT.
+ if (action == AccessibilityNodeInfo.ACTION_SET_TEXT &&
+ eventTag.equals(request.getCharSequence(
+ AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE))) {
+ final Bundle response = new Bundle();
+ responseFiller.accept(response);
+ AccessibilityManagerCompat.sendEventToTest(
+ accessibilityManager, eventTag + TestProtocol.RESPONSE_MESSAGE_POSTFIX, response);
+ return true;
+ }
+ return false;
+ }
}
diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompat.java b/src/com/android/launcher3/compat/AppWidgetManagerCompat.java
index fd1f0cc..3243256 100644
--- a/src/com/android/launcher3/compat/AppWidgetManagerCompat.java
+++ b/src/com/android/launcher3/compat/AppWidgetManagerCompat.java
@@ -22,7 +22,6 @@
import android.content.Context;
import android.os.Bundle;
import android.os.UserHandle;
-import android.support.annotation.Nullable;
import com.android.launcher3.LauncherAppWidgetInfo;
import com.android.launcher3.LauncherAppWidgetProviderInfo;
@@ -35,6 +34,8 @@
import java.util.HashMap;
import java.util.List;
+import androidx.annotation.Nullable;
+
public abstract class AppWidgetManagerCompat {
private static final Object sInstanceLock = new Object();
diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java b/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java
index 8430285..1065748 100644
--- a/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java
+++ b/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java
@@ -23,7 +23,6 @@
import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
-import android.support.annotation.Nullable;
import com.android.launcher3.LauncherAppWidgetInfo;
import com.android.launcher3.LauncherAppWidgetProviderInfo;
@@ -38,6 +37,8 @@
import java.util.Iterator;
import java.util.List;
+import androidx.annotation.Nullable;
+
class AppWidgetManagerCompatVL extends AppWidgetManagerCompat {
private final UserManager mUserManager;
diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompatVO.java b/src/com/android/launcher3/compat/AppWidgetManagerCompatVO.java
index 44158ed..b7b0563 100644
--- a/src/com/android/launcher3/compat/AppWidgetManagerCompatVO.java
+++ b/src/com/android/launcher3/compat/AppWidgetManagerCompatVO.java
@@ -18,7 +18,6 @@
import android.appwidget.AppWidgetProviderInfo;
import android.content.Context;
-import android.support.annotation.Nullable;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.PackageUserKey;
@@ -26,6 +25,8 @@
import java.util.Collections;
import java.util.List;
+import androidx.annotation.Nullable;
+
class AppWidgetManagerCompatVO extends AppWidgetManagerCompatVL {
AppWidgetManagerCompatVO(Context context) {
diff --git a/src/com/android/launcher3/compat/LauncherAppsCompat.java b/src/com/android/launcher3/compat/LauncherAppsCompat.java
index 2cac536..407355c 100644
--- a/src/com/android/launcher3/compat/LauncherAppsCompat.java
+++ b/src/com/android/launcher3/compat/LauncherAppsCompat.java
@@ -24,12 +24,15 @@
import android.graphics.Rect;
import android.os.Bundle;
import android.os.UserHandle;
-import android.support.annotation.Nullable;
+
import com.android.launcher3.Utilities;
import com.android.launcher3.shortcuts.ShortcutInfoCompat;
import com.android.launcher3.util.PackageUserKey;
+
import java.util.List;
+import androidx.annotation.Nullable;
+
public abstract class LauncherAppsCompat {
public interface OnAppsChangedCallbackCompat {
diff --git a/src/com/android/launcher3/compat/LauncherAppsCompatVL.java b/src/com/android/launcher3/compat/LauncherAppsCompatVL.java
index cc3e5a7..ba0ac6e 100644
--- a/src/com/android/launcher3/compat/LauncherAppsCompatVL.java
+++ b/src/com/android/launcher3/compat/LauncherAppsCompatVL.java
@@ -29,15 +29,18 @@
import android.os.Bundle;
import android.os.Process;
import android.os.UserHandle;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
import android.util.ArrayMap;
+
import com.android.launcher3.compat.ShortcutConfigActivityInfo.ShortcutConfigActivityInfoVL;
import com.android.launcher3.shortcuts.ShortcutInfoCompat;
import com.android.launcher3.util.PackageUserKey;
+
import java.util.ArrayList;
import java.util.List;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
public class LauncherAppsCompatVL extends LauncherAppsCompat {
protected final LauncherApps mLauncherApps;
diff --git a/src/com/android/launcher3/compat/LauncherAppsCompatVO.java b/src/com/android/launcher3/compat/LauncherAppsCompatVO.java
index 173d0d1..386b3b3 100644
--- a/src/com/android/launcher3/compat/LauncherAppsCompatVO.java
+++ b/src/com/android/launcher3/compat/LauncherAppsCompatVO.java
@@ -28,7 +28,6 @@
import android.os.Parcelable;
import android.os.Process;
import android.os.UserHandle;
-import android.support.annotation.Nullable;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherModel;
@@ -42,6 +41,8 @@
import java.util.ArrayList;
import java.util.List;
+import androidx.annotation.Nullable;
+
@TargetApi(26)
public class LauncherAppsCompatVO extends LauncherAppsCompatVL {
diff --git a/src/com/android/launcher3/compat/PackageInstallerCompat.java b/src/com/android/launcher3/compat/PackageInstallerCompat.java
index 3270ba2..7dad7e9 100644
--- a/src/com/android/launcher3/compat/PackageInstallerCompat.java
+++ b/src/com/android/launcher3/compat/PackageInstallerCompat.java
@@ -19,11 +19,12 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageInstaller;
-import android.support.annotation.NonNull;
import java.util.HashMap;
import java.util.List;
+import androidx.annotation.NonNull;
+
public abstract class PackageInstallerCompat {
public static final int STATUS_INSTALLED = 0;
diff --git a/src/com/android/launcher3/config/BaseFlags.java b/src/com/android/launcher3/config/BaseFlags.java
index f4c6380..05fc33f 100644
--- a/src/com/android/launcher3/config/BaseFlags.java
+++ b/src/com/android/launcher3/config/BaseFlags.java
@@ -31,12 +31,8 @@
public static final boolean IS_DOGFOOD_BUILD = false;
public static final String AUTHORITY = "com.android.launcher3.settings".intern();
- // When enabled allows to use any point on the fast scrollbar to start dragging.
- public static final boolean LAUNCHER3_DIRECT_SCROLL = true;
// When enabled the promise icon is visible in all apps while installation an app.
public static final boolean LAUNCHER3_PROMISE_APPS_IN_ALL_APPS = false;
- // When enabled allows use of spring motions on the icons.
- public static final boolean LAUNCHER3_SPRING_ICONS = true;
// Feature flag to enable moving the QSB on the 0th screen of the workspace.
public static final boolean QSB_ON_FIRST_SCREEN = true;
diff --git a/src/com/android/launcher3/dragndrop/DragController.java b/src/com/android/launcher3/dragndrop/DragController.java
index 8a216fc..8007754 100644
--- a/src/com/android/launcher3/dragndrop/DragController.java
+++ b/src/com/android/launcher3/dragndrop/DragController.java
@@ -16,9 +16,11 @@
package com.android.launcher3.dragndrop;
+import static com.android.launcher3.AbstractFloatingView.TYPE_DISCOVERY_BOUNCE;
import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
import static com.android.launcher3.LauncherState.NORMAL;
+import android.animation.ValueAnimator;
import android.content.ComponentName;
import android.content.res.Resources;
import android.graphics.Bitmap;
@@ -31,6 +33,7 @@
import android.view.MotionEvent;
import android.view.View;
+import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.DragSource;
import com.android.launcher3.DropTarget;
import com.android.launcher3.ItemInfo;
@@ -145,6 +148,7 @@
// Hide soft keyboard, if visible
UiThreadHelper.hideKeyboardAsync(mLauncher, mWindowToken);
+ AbstractFloatingView.closeOpenViews(mLauncher, false, TYPE_DISCOVERY_BOUNCE);
mOptions = options;
if (mOptions.systemDndStartPoint != null) {
@@ -224,6 +228,12 @@
}
}
+ public void addFirstFrameAnimationHelper(ValueAnimator anim) {
+ if (mDragObject != null && mDragObject.dragView != null) {
+ mDragObject.dragView.mFirstFrameAnimatorHelper.addTo(anim);
+ }
+ }
+
/**
* Call this from a drag source view like this:
*
diff --git a/src/com/android/launcher3/dragndrop/DragView.java b/src/com/android/launcher3/dragndrop/DragView.java
index 551567a..6ac56eb 100644
--- a/src/com/android/launcher3/dragndrop/DragView.java
+++ b/src/com/android/launcher3/dragndrop/DragView.java
@@ -16,6 +16,8 @@
package com.android.launcher3.dragndrop;
+import static com.android.launcher3.ItemInfoWithIcon.FLAG_ICON_BADGED;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.FloatArrayEvaluator;
@@ -39,26 +41,21 @@
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
-import android.support.animation.FloatPropertyCompat;
-import android.support.animation.SpringAnimation;
-import android.support.animation.SpringForce;
import android.view.View;
import com.android.launcher3.FastBitmapDrawable;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.ItemInfoWithIcon;
import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherAnimUtils;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherModel;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
+import com.android.launcher3.FirstFrameAnimatorHelper;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.compat.ShortcutConfigActivityInfo;
-import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.graphics.IconNormalizer;
import com.android.launcher3.graphics.LauncherIcons;
import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.shortcuts.ShortcutInfoCompat;
@@ -70,7 +67,9 @@
import java.util.Arrays;
import java.util.List;
-import static com.android.launcher3.ItemInfoWithIcon.FLAG_ICON_BADGED;
+import androidx.dynamicanimation.animation.FloatPropertyCompat;
+import androidx.dynamicanimation.animation.SpringAnimation;
+import androidx.dynamicanimation.animation.SpringForce;
public class DragView extends View {
private static final ColorMatrix sTempMatrix1 = new ColorMatrix();
@@ -79,8 +78,6 @@
public static final int COLOR_CHANGE_DURATION = 120;
public static final int VIEW_ZOOM_DURATION = 150;
- @Thunk static float sDragAlpha = 1f;
-
private boolean mDrawBitmap = true;
private Bitmap mBitmap;
private Bitmap mCrossFadeBitmap;
@@ -97,6 +94,7 @@
private final Launcher mLauncher;
private final DragLayer mDragLayer;
@Thunk final DragController mDragController;
+ final FirstFrameAnimatorHelper mFirstFrameAnimatorHelper;
private boolean mHasDrawn = false;
@Thunk float mCrossFadeProgress = 0f;
private boolean mAnimationCancelled = false;
@@ -137,6 +135,7 @@
mLauncher = launcher;
mDragLayer = launcher.getDragLayer();
mDragController = launcher.getDragController();
+ mFirstFrameAnimatorHelper = new FirstFrameAnimatorHelper(this);
final float scale = (bitmap.getWidth() + finalScaleDps) / bitmap.getWidth();
@@ -145,22 +144,14 @@
setScaleY(initialScale);
// Animate the view into the correct position
- mAnim = LauncherAnimUtils.ofFloat(0f, 1f);
+ mAnim = ValueAnimator.ofFloat(0f, 1f);
mAnim.setDuration(VIEW_ZOOM_DURATION);
- mAnim.addUpdateListener(new AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- final float value = (Float) animation.getAnimatedValue();
-
- setScaleX(initialScale + (value * (scale - initialScale)));
- setScaleY(initialScale + (value * (scale - initialScale)));
- if (sDragAlpha != 1f) {
- setAlpha(sDragAlpha * value + (1f - value));
- }
-
- if (getParent() == null) {
- animation.cancel();
- }
+ mAnim.addUpdateListener(animation -> {
+ final float value = (Float) animation.getAnimatedValue();
+ setScaleX(initialScale + (value * (scale - initialScale)));
+ setScaleY(initialScale + (value * (scale - initialScale)));
+ if (!isAttachedToWindow()) {
+ animation.cancel();
}
});
@@ -198,7 +189,7 @@
*/
@TargetApi(Build.VERSION_CODES.O)
public void setItemInfo(final ItemInfo info) {
- if (!(FeatureFlags.LAUNCHER3_SPRING_ICONS && Utilities.ATLEAST_OREO)) {
+ if (!Utilities.ATLEAST_OREO) {
return;
}
if (info.itemType != LauncherSettings.Favorites.ITEM_TYPE_APPLICATION &&
@@ -481,15 +472,12 @@
}
public void crossFade(int duration) {
- ValueAnimator va = LauncherAnimUtils.ofFloat(0f, 1f);
+ ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
va.setDuration(duration);
va.setInterpolator(Interpolators.DEACCEL_1_5);
- va.addUpdateListener(new AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- mCrossFadeProgress = animation.getAnimatedFraction();
- invalidate();
- }
+ va.addUpdateListener(a -> {
+ mCrossFadeProgress = a.getAnimatedFraction();
+ invalidate();
});
va.start();
}
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index 6b13da7..6a3ebcf 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -25,6 +25,7 @@
import android.animation.AnimatorSet;
import android.annotation.SuppressLint;
import android.content.Context;
+import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Rect;
import android.text.InputType;
@@ -191,14 +192,9 @@
public Folder(Context context, AttributeSet attrs) {
super(context, attrs);
setAlwaysDrawnWithCacheEnabled(false);
- Resources res = getResources();
- if (sDefaultFolderName == null) {
- sDefaultFolderName = res.getString(R.string.folder_name);
- }
- if (sHintText == null) {
- sHintText = res.getString(R.string.folder_hint_text);
- }
+ setLocaleDependentFields(getResources(), false /* force */);
+
mLauncher = Launcher.getLauncher(context);
// We need this view to be focusable in touch mode so that when text editing of the folder
// name is complete, we have something to focus on, thus hiding the cursor and giving
@@ -1473,4 +1469,13 @@
}
return false;
}
+
+ public static void setLocaleDependentFields(Resources res, boolean force) {
+ if (sDefaultFolderName == null || force) {
+ sDefaultFolderName = res.getString(R.string.folder_name);
+ }
+ if (sHintText == null || force) {
+ sHintText = res.getString(R.string.folder_hint_text);
+ }
+ }
}
diff --git a/src/com/android/launcher3/folder/FolderAnimationManager.java b/src/com/android/launcher3/folder/FolderAnimationManager.java
index 9ae3775..6ef798d 100644
--- a/src/com/android/launcher3/folder/FolderAnimationManager.java
+++ b/src/com/android/launcher3/folder/FolderAnimationManager.java
@@ -27,10 +27,8 @@
import android.animation.TimeInterpolator;
import android.content.Context;
import android.content.res.Resources;
-import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.GradientDrawable;
-import android.support.v4.graphics.ColorUtils;
import android.util.Property;
import android.view.View;
import android.view.animation.AnimationUtils;
@@ -38,7 +36,6 @@
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.CellLayout;
import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherAnimUtils;
import com.android.launcher3.R;
import com.android.launcher3.ShortcutAndWidgetContainer;
import com.android.launcher3.Utilities;
@@ -49,6 +46,8 @@
import java.util.List;
+import androidx.core.graphics.ColorUtils;
+
/**
* Manages the opening and closing animations for a {@link Folder}.
*
@@ -170,7 +169,7 @@
float finalRadius = Utilities.pxFromDp(2, mContext.getResources().getDisplayMetrics());
// Create the animators.
- AnimatorSet a = LauncherAnimUtils.createAnimatorSet();
+ AnimatorSet a = new AnimatorSet();
// Initialize the Folder items' text.
PropertyResetListener colorResetListener =
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index cb5d872..87a0796 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -25,10 +25,7 @@
import android.graphics.Canvas;
import android.graphics.Point;
import android.graphics.Rect;
-import android.graphics.Region;
import android.graphics.drawable.Drawable;
-import android.os.Parcelable;
-import android.support.annotation.NonNull;
import android.util.AttributeSet;
import android.util.Property;
import android.view.LayoutInflater;
@@ -70,6 +67,8 @@
import java.util.ArrayList;
import java.util.List;
+import androidx.annotation.NonNull;
+
/**
* An icon that can appear on in the workspace representing an {@link Folder}.
*/
@@ -77,7 +76,6 @@
@Thunk Launcher mLauncher;
@Thunk Folder mFolder;
private FolderInfo mInfo;
- @Thunk static boolean sStaticValuesDirty = true;
private CheckLongPressHelper mLongPressHelper;
private StylusEventHelper mStylusEventHelper;
@@ -185,12 +183,6 @@
return icon;
}
- @Override
- protected Parcelable onSaveInstanceState() {
- sStaticValuesDirty = true;
- return super.onSaveInstanceState();
- }
-
public Folder getFolder() {
return mFolder;
}
@@ -490,10 +482,7 @@
public void drawBadge(Canvas canvas) {
if ((mBadgeInfo != null && mBadgeInfo.hasBadge()) || mBadgeScale > 0) {
- int offsetX = mBackground.getOffsetX();
- int offsetY = mBackground.getOffsetY();
- int previewSize = (int) (mBackground.previewSize * mBackground.mScale);
- mTempBounds.set(offsetX, offsetY, offsetX + previewSize, offsetY + previewSize);
+ BubbleTextView.getIconBounds(this, mTempBounds, mLauncher.getDeviceProfile().iconSizePx);
// If we are animating to the accepting state, animate the badge out.
float badgeScale = Math.max(0, mBadgeScale - mBackground.getScaleProgress());
diff --git a/src/com/android/launcher3/folder/FolderPagedView.java b/src/com/android/launcher3/folder/FolderPagedView.java
index 9be71f9..8439e79 100644
--- a/src/com/android/launcher3/folder/FolderPagedView.java
+++ b/src/com/android/launcher3/folder/FolderPagedView.java
@@ -493,7 +493,7 @@
int delta = scroll - getScrollX();
if (delta != 0) {
mScroller.setInterpolator(Interpolators.DEACCEL);
- mScroller.startScroll(getScrollX(), 0, delta, 0, Folder.SCROLL_HINT_DURATION);
+ mScroller.startScroll(getScrollX(), delta, Folder.SCROLL_HINT_DURATION);
invalidate();
}
}
diff --git a/src/com/android/launcher3/folder/FolderPreviewItemAnim.java b/src/com/android/launcher3/folder/FolderPreviewItemAnim.java
index be075bc..1e56f7d 100644
--- a/src/com/android/launcher3/folder/FolderPreviewItemAnim.java
+++ b/src/com/android/launcher3/folder/FolderPreviewItemAnim.java
@@ -17,22 +17,41 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
+import android.animation.FloatArrayEvaluator;
+import android.animation.ObjectAnimator;
+import android.util.Property;
-import com.android.launcher3.LauncherAnimUtils;
+import java.util.Arrays;
/**
* Animates a Folder preview item.
*/
class FolderPreviewItemAnim {
+ private static final Property<FolderPreviewItemAnim, float[]> PARAMS =
+ new Property<FolderPreviewItemAnim, float[]>(float[].class, "params") {
+ @Override
+ public float[] get(FolderPreviewItemAnim anim) {
+ sTempParamsArray[0] = anim.mParams.scale;
+ sTempParamsArray[1] = anim.mParams.transX;
+ sTempParamsArray[2] = anim.mParams.transY;
+ return sTempParamsArray;
+ }
+
+ @Override
+ public void set(FolderPreviewItemAnim anim, float[] value) {
+ anim.setParams(value);
+ }
+ };
+
private static PreviewItemDrawingParams sTmpParams = new PreviewItemDrawingParams(0, 0, 0, 0);
+ private static final float[] sTempParamsArray = new float[3];
- private ValueAnimator mValueAnimator;
+ private final ObjectAnimator mAnimator;
+ private final PreviewItemManager mItemManager;
+ private final PreviewItemDrawingParams mParams;
- float finalScale;
- float finalTransX;
- float finalTransY;
+ public final float[] finalState;
/**
* @param params layout params to animate
@@ -43,33 +62,21 @@
* @param duration duration in ms of the animation
* @param onCompleteRunnable runnable to execute upon animation completion
*/
- FolderPreviewItemAnim(final PreviewItemManager previewItemManager,
- final PreviewItemDrawingParams params, int index0, int items0, int index1, int items1,
+ FolderPreviewItemAnim(PreviewItemManager itemManager,
+ PreviewItemDrawingParams params, int index0, int items0, int index1, int items1,
int duration, final Runnable onCompleteRunnable) {
- previewItemManager.computePreviewItemDrawingParams(index1, items1, sTmpParams);
+ mItemManager = itemManager;
+ mParams = params;
- finalScale = sTmpParams.scale;
- finalTransX = sTmpParams.transX;
- finalTransY = sTmpParams.transY;
+ mItemManager.computePreviewItemDrawingParams(index1, items1, sTmpParams);
+ finalState = new float[] {sTmpParams.scale, sTmpParams.transX, sTmpParams.transY};
- previewItemManager.computePreviewItemDrawingParams(index0, items0, sTmpParams);
+ mItemManager.computePreviewItemDrawingParams(index0, items0, sTmpParams);
+ float[] startState = new float[] {sTmpParams.scale, sTmpParams.transX, sTmpParams.transY};
- final float scale0 = sTmpParams.scale;
- final float transX0 = sTmpParams.transX;
- final float transY0 = sTmpParams.transY;
-
- mValueAnimator = LauncherAnimUtils.ofFloat(0f, 1.0f);
- mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener(){
- public void onAnimationUpdate(ValueAnimator animation) {
- float progress = animation.getAnimatedFraction();
-
- params.transX = transX0 + progress * (finalTransX - transX0);
- params.transY = transY0 + progress * (finalTransY - transY0);
- params.scale = scale0 + progress * (finalScale - scale0);
- previewItemManager.onParamsChanged();
- }
- });
- mValueAnimator.addListener(new AnimatorListenerAdapter() {
+ mAnimator = ObjectAnimator.ofObject(this, PARAMS, new FloatArrayEvaluator(),
+ startState, finalState);
+ mAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
if (onCompleteRunnable != null) {
@@ -78,20 +85,26 @@
params.anim = null;
}
});
- mValueAnimator.setDuration(duration);
+ mAnimator.setDuration(duration);
+ }
+
+ private void setParams(float[] values) {
+ mParams.scale = values[0];
+ mParams.transX = values[1];
+ mParams.transY = values[2];
+ mItemManager.onParamsChanged();
}
public void start() {
- mValueAnimator.start();
+ mAnimator.start();
}
public void cancel() {
- mValueAnimator.cancel();
+ mAnimator.cancel();
}
public boolean hasEqualFinalState(FolderPreviewItemAnim anim) {
- return finalTransY == anim.finalTransY && finalTransX == anim.finalTransX &&
- finalScale == anim.finalScale;
+ return Arrays.equals(finalState, anim.finalState);
}
}
diff --git a/src/com/android/launcher3/folder/PreviewBackground.java b/src/com/android/launcher3/folder/PreviewBackground.java
index 069ec4b..ceb1a8c 100644
--- a/src/com/android/launcher3/folder/PreviewBackground.java
+++ b/src/com/android/launcher3/folder/PreviewBackground.java
@@ -30,16 +30,17 @@
import android.graphics.RadialGradient;
import android.graphics.Region;
import android.graphics.Shader;
-import android.support.v4.graphics.ColorUtils;
import android.util.Property;
import android.view.View;
import com.android.launcher3.CellLayout;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherAnimUtils;
+import com.android.launcher3.R;
import com.android.launcher3.util.Themes;
+import androidx.core.graphics.ColorUtils;
+
/**
* This object represents a FolderIcon preview background. It stores drawing / measurement
* information, handles drawing, and animation (accept state <--> rest state).
@@ -70,6 +71,7 @@
float mScale = 1f;
private float mColorMultiplier = 1f;
private int mBgColor;
+ private int mBadgeColor;
private float mStrokeWidth;
private int mStrokeAlpha = MAX_BG_OPACITY;
private int mShadowAlpha = 255;
@@ -132,6 +134,7 @@
int availableSpaceX, int topPadding) {
mInvalidateDelegate = invalidateDelegate;
mBgColor = Themes.getAttrColor(launcher, android.R.attr.colorPrimary);
+ mBadgeColor = Themes.getAttrColor(launcher, R.attr.folderBadgeColor);
DeviceProfile grid = launcher.getDeviceProfile();
previewSize = grid.folderIconSizePx;
@@ -198,7 +201,7 @@
}
public int getBadgeColor() {
- return mBgColor;
+ return mBadgeColor;
}
public void drawBackground(Canvas canvas) {
@@ -365,7 +368,7 @@
mScaleAnimator.cancel();
}
- mScaleAnimator = LauncherAnimUtils.ofFloat(0f, 1.0f);
+ mScaleAnimator = ValueAnimator.ofFloat(0f, 1.0f);
mScaleAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
@@ -397,37 +400,19 @@
mScaleAnimator.start();
}
- public void animateToAccept(final CellLayout cl, final int cellX, final int cellY) {
- Runnable onStart = new Runnable() {
- @Override
- public void run() {
- delegateDrawing(cl, cellX, cellY);
- }
- };
- animateScale(ACCEPT_SCALE_FACTOR, ACCEPT_COLOR_MULTIPLIER, onStart, null);
+ public void animateToAccept(CellLayout cl, int cellX, int cellY) {
+ animateScale(ACCEPT_SCALE_FACTOR, ACCEPT_COLOR_MULTIPLIER,
+ () -> delegateDrawing(cl, cellX, cellY), null);
}
public void animateToRest() {
// This can be called multiple times -- we need to make sure the drawing delegate
// is saved and restored at the beginning of the animation, since cancelling the
// existing animation can clear the delgate.
- final CellLayout cl = mDrawingDelegate;
- final int cellX = delegateCellX;
- final int cellY = delegateCellY;
-
- Runnable onStart = new Runnable() {
- @Override
- public void run() {
- delegateDrawing(cl, cellX, cellY);
- }
- };
- Runnable onEnd = new Runnable() {
- @Override
- public void run() {
- clearDrawingDelegate();
- }
- };
- animateScale(1f, 1f, onStart, onEnd);
+ CellLayout cl = mDrawingDelegate;
+ int cellX = delegateCellX;
+ int cellY = delegateCellY;
+ animateScale(1f, 1f, () -> delegateDrawing(cl, cellX, cellY), this::clearDrawingDelegate);
}
public int getBackgroundAlpha() {
diff --git a/src/com/android/launcher3/folder/PreviewItemDrawingParams.java b/src/com/android/launcher3/folder/PreviewItemDrawingParams.java
index 607b7ca..c818462 100644
--- a/src/com/android/launcher3/folder/PreviewItemDrawingParams.java
+++ b/src/com/android/launcher3/folder/PreviewItemDrawingParams.java
@@ -40,8 +40,8 @@
// We ensure the update will not interfere with an animation on the layout params
// If the final values differ, we cancel the animation.
if (anim != null) {
- if (anim.finalTransX == transX || anim.finalTransY == transY
- || anim.finalScale == scale) {
+ if (anim.finalState[1] == transX || anim.finalState[2] == transY
+ || anim.finalState[0] == scale) {
return;
}
anim.cancel();
diff --git a/src/com/android/launcher3/folder/PreviewItemManager.java b/src/com/android/launcher3/folder/PreviewItemManager.java
index 1f69f6e..0004e1e 100644
--- a/src/com/android/launcher3/folder/PreviewItemManager.java
+++ b/src/com/android/launcher3/folder/PreviewItemManager.java
@@ -16,13 +16,17 @@
package com.android.launcher3.folder;
+import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.ENTER_INDEX;
+import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.EXIT_INDEX;
+import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.MAX_NUM_ITEMS_IN_PREVIEW;
+import static com.android.launcher3.folder.FolderIcon.DROP_IN_ANIMATION_DURATION;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
-import android.support.annotation.NonNull;
import android.view.View;
import android.widget.TextView;
@@ -33,10 +37,7 @@
import java.util.ArrayList;
import java.util.List;
-import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.ENTER_INDEX;
-import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.EXIT_INDEX;
-import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.MAX_NUM_ITEMS_IN_PREVIEW;
-import static com.android.launcher3.folder.FolderIcon.DROP_IN_ANIMATION_DURATION;
+import androidx.annotation.NonNull;
/**
* Manages the drawing and animations of {@link PreviewItemDrawingParams} for a {@link FolderIcon}.
diff --git a/src/com/android/launcher3/graphics/BitmapInfo.java b/src/com/android/launcher3/graphics/BitmapInfo.java
index ab906e2..c905a78 100644
--- a/src/com/android/launcher3/graphics/BitmapInfo.java
+++ b/src/com/android/launcher3/graphics/BitmapInfo.java
@@ -35,9 +35,15 @@
}
public static BitmapInfo fromBitmap(Bitmap bitmap) {
+ return fromBitmap(bitmap, null);
+ }
+
+ public static BitmapInfo fromBitmap(Bitmap bitmap, ColorExtractor dominantColorExtractor) {
BitmapInfo info = new BitmapInfo();
info.icon = bitmap;
- info.color = ColorExtractor.findDominantColorByHue(bitmap);
+ info.color = dominantColorExtractor != null
+ ? dominantColorExtractor.findDominantColorByHue(bitmap)
+ : 0;
return info;
}
}
diff --git a/src/com/android/launcher3/graphics/ColorExtractor.java b/src/com/android/launcher3/graphics/ColorExtractor.java
index e9d72b7..da5da9c 100644
--- a/src/com/android/launcher3/graphics/ColorExtractor.java
+++ b/src/com/android/launcher3/graphics/ColorExtractor.java
@@ -18,22 +18,32 @@
import android.graphics.Bitmap;
import android.graphics.Color;
import android.util.SparseArray;
+import java.util.Arrays;
/**
* Utility class for extracting colors from a bitmap.
*/
public class ColorExtractor {
- public static int findDominantColorByHue(Bitmap bitmap) {
- return findDominantColorByHue(bitmap, 20);
+ private final int NUM_SAMPLES = 20;
+ private final float[] mTmpHsv = new float[3];
+ private final float[] mTmpHueScoreHistogram = new float[360];
+ private final int[] mTmpPixels = new int[NUM_SAMPLES];
+ private final SparseArray<Float> mTmpRgbScores = new SparseArray<>();
+
+ /**
+ * This picks a dominant color, looking for high-saturation, high-value, repeated hues.
+ * @param bitmap The bitmap to scan
+ */
+ public int findDominantColorByHue(Bitmap bitmap) {
+ return findDominantColorByHue(bitmap, NUM_SAMPLES);
}
/**
* This picks a dominant color, looking for high-saturation, high-value, repeated hues.
* @param bitmap The bitmap to scan
- * @param samples The approximate max number of samples to use.
*/
- public static int findDominantColorByHue(Bitmap bitmap, int samples) {
+ public int findDominantColorByHue(Bitmap bitmap, int samples) {
final int height = bitmap.getHeight();
final int width = bitmap.getWidth();
int sampleStride = (int) Math.sqrt((height * width) / samples);
@@ -42,15 +52,18 @@
}
// This is an out-param, for getting the hsv values for an rgb
- float[] hsv = new float[3];
+ float[] hsv = mTmpHsv;
+ Arrays.fill(hsv, 0);
// First get the best hue, by creating a histogram over 360 hue buckets,
// where each pixel contributes a score weighted by saturation, value, and alpha.
- float[] hueScoreHistogram = new float[360];
+ float[] hueScoreHistogram = mTmpHueScoreHistogram;
+ Arrays.fill(hueScoreHistogram, 0);
float highScore = -1;
int bestHue = -1;
- int[] pixels = new int[samples];
+ int[] pixels = mTmpPixels;
+ Arrays.fill(pixels, 0);
int pixelCount = 0;
for (int y = 0; y < height; y += sampleStride) {
@@ -82,7 +95,8 @@
}
}
- SparseArray<Float> rgbScores = new SparseArray<>();
+ SparseArray<Float> rgbScores = mTmpRgbScores;
+ rgbScores.clear();
int bestColor = 0xff000000;
highScore = -1;
// Go back over the RGB colors that match the winning hue,
diff --git a/src/com/android/launcher3/graphics/ColorScrim.java b/src/com/android/launcher3/graphics/ColorScrim.java
index 96d93d8..5c1081a 100644
--- a/src/com/android/launcher3/graphics/ColorScrim.java
+++ b/src/com/android/launcher3/graphics/ColorScrim.java
@@ -17,7 +17,6 @@
import android.graphics.Canvas;
import android.graphics.Color;
-import android.support.v4.graphics.ColorUtils;
import android.view.View;
import android.view.animation.Interpolator;
@@ -25,6 +24,8 @@
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.uioverrides.WallpaperColorInfo;
+import androidx.core.graphics.ColorUtils;
+
/**
* Simple scrim which draws a color
*/
diff --git a/src/com/android/launcher3/graphics/DrawableFactory.java b/src/com/android/launcher3/graphics/DrawableFactory.java
index bbc013d..5bc81e6 100644
--- a/src/com/android/launcher3/graphics/DrawableFactory.java
+++ b/src/com/android/launcher3/graphics/DrawableFactory.java
@@ -28,9 +28,9 @@
import android.graphics.drawable.Drawable;
import android.os.Process;
import android.os.UserHandle;
-import android.support.annotation.UiThread;
import android.util.ArrayMap;
import android.util.Log;
+
import com.android.launcher3.FastBitmapDrawable;
import com.android.launcher3.ItemInfoWithIcon;
import com.android.launcher3.R;
@@ -38,6 +38,8 @@
import com.android.launcher3.allapps.AllAppsBackgroundDrawable;
import com.android.launcher3.util.ResourceBasedOverride;
+import androidx.annotation.UiThread;
+
/**
* Factory for creating new drawables.
*/
diff --git a/src/com/android/launcher3/graphics/IconNormalizer.java b/src/com/android/launcher3/graphics/IconNormalizer.java
index a2a0801..df00815 100644
--- a/src/com/android/launcher3/graphics/IconNormalizer.java
+++ b/src/com/android/launcher3/graphics/IconNormalizer.java
@@ -24,22 +24,23 @@
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
-import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.AdaptiveIconDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
import android.util.Log;
+
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.Utilities;
import com.android.launcher3.dragndrop.FolderAdaptiveIcon;
import java.nio.ByteBuffer;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
public class IconNormalizer {
private static final String TAG = "IconNormalizer";
diff --git a/src/com/android/launcher3/graphics/IconPalette.java b/src/com/android/launcher3/graphics/IconPalette.java
index 9c3b77e..cda07c3 100644
--- a/src/com/android/launcher3/graphics/IconPalette.java
+++ b/src/com/android/launcher3/graphics/IconPalette.java
@@ -19,12 +19,13 @@
import android.app.Notification;
import android.content.Context;
import android.graphics.Color;
-import android.support.v4.graphics.ColorUtils;
import android.util.Log;
import com.android.launcher3.R;
import com.android.launcher3.util.Themes;
+import androidx.core.graphics.ColorUtils;
+
/**
* Contains colors based on the dominant color of an icon.
*/
diff --git a/src/com/android/launcher3/graphics/IconShapeOverride.java b/src/com/android/launcher3/graphics/IconShapeOverride.java
index 223243b..cadc6e3 100644
--- a/src/com/android/launcher3/graphics/IconShapeOverride.java
+++ b/src/com/android/launcher3/graphics/IconShapeOverride.java
@@ -30,7 +30,6 @@
import android.preference.Preference;
import android.preference.Preference.OnPreferenceChangeListener;
import android.provider.Settings;
-import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.util.Log;
@@ -42,6 +41,8 @@
import java.lang.reflect.Field;
+import androidx.annotation.NonNull;
+
/**
* Utility class to override shape of {@link android.graphics.drawable.AdaptiveIconDrawable}.
*/
diff --git a/src/com/android/launcher3/graphics/LauncherIcons.java b/src/com/android/launcher3/graphics/LauncherIcons.java
index 333fe59..087362c 100644
--- a/src/com/android/launcher3/graphics/LauncherIcons.java
+++ b/src/com/android/launcher3/graphics/LauncherIcons.java
@@ -41,7 +41,6 @@
import android.os.Build;
import android.os.Process;
import android.os.UserHandle;
-import android.support.annotation.Nullable;
import com.android.launcher3.AppInfo;
import com.android.launcher3.FastBitmapDrawable;
@@ -57,6 +56,8 @@
import com.android.launcher3.util.Provider;
import com.android.launcher3.util.Themes;
+import androidx.annotation.Nullable;
+
/**
* Helper methods for generating various launcher icons
*/
@@ -90,6 +91,7 @@
synchronized (sPoolSync) {
// Clear any temporary state variables
mWrapperBackgroundColor = DEFAULT_WRAPPER_BACKGROUND;
+ mDisableColorExtractor = false;
next = sPool;
sPool = this;
@@ -105,6 +107,8 @@
private final Context mContext;
private final Canvas mCanvas;
private final PackageManager mPm;
+ private final ColorExtractor mColorExtractor;
+ private boolean mDisableColorExtractor;
private final int mFillResIconDpi;
private final int mIconBitmapSize;
@@ -121,6 +125,7 @@
private LauncherIcons(Context context) {
mContext = context.getApplicationContext();
mPm = mContext.getPackageManager();
+ mColorExtractor = new ColorExtractor();
InvariantDeviceProfile idp = LauncherAppState.getIDP(mContext);
mFillResIconDpi = idp.fillResIconDpi;
@@ -196,7 +201,7 @@
* The bitmap is also visually normalized with other icons.
*/
public BitmapInfo createBadgedIconBitmap(Drawable icon, UserHandle user, int iconAppTargetSdk,
- boolean isInstantApp, float [] scale) {
+ boolean isInstantApp, float[] scale) {
if (scale == null) {
scale = new float[1];
}
@@ -223,7 +228,7 @@
} else {
result = bitmap;
}
- return BitmapInfo.fromBitmap(result);
+ return BitmapInfo.fromBitmap(result, mDisableColorExtractor ? null : mColorExtractor);
}
/**
@@ -245,6 +250,14 @@
mWrapperBackgroundColor = (Color.alpha(color) < 255) ? DEFAULT_WRAPPER_BACKGROUND : color;
}
+ /**
+ * Disables the dominant color extraction for all icons loaded through this session (until
+ * this instance is recycled).
+ */
+ public void disableColorExtraction() {
+ mDisableColorExtractor = true;
+ }
+
private Drawable normalizeAndWrapToAdaptiveIcon(Drawable icon, int iconAppTargetSdk,
RectF outIconBounds, float[] outScale) {
float scale = 1f;
diff --git a/src/com/android/launcher3/graphics/NinePatchDrawHelper.java b/src/com/android/launcher3/graphics/NinePatchDrawHelper.java
index fc20926..5872689 100644
--- a/src/com/android/launcher3/graphics/NinePatchDrawHelper.java
+++ b/src/com/android/launcher3/graphics/NinePatchDrawHelper.java
@@ -33,7 +33,9 @@
private final Rect mSrc = new Rect();
private final RectF mDst = new RectF();
- public final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ // Enable filtering to always get a nice edge. This avoids jagged line, when bitmap is
+ // translated by half pixel.
+ public final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
/**
* Draws the bitmap split into three parts horizontally, with the middle part having width
diff --git a/src/com/android/launcher3/graphics/ShadowDrawable.java b/src/com/android/launcher3/graphics/ShadowDrawable.java
index b40bf78..19e2768 100644
--- a/src/com/android/launcher3/graphics/ShadowDrawable.java
+++ b/src/com/android/launcher3/graphics/ShadowDrawable.java
@@ -32,7 +32,6 @@
import android.util.AttributeSet;
import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -146,7 +145,7 @@
d.draw(canvas);
}
- if (Utilities.ATLEAST_OREO) {
+ if (BitmapRenderer.USE_HARDWARE_BITMAP) {
bitmap = bitmap.copy(Bitmap.Config.HARDWARE, false);
}
mState.mLastDrawnBitmap = bitmap;
diff --git a/src/com/android/launcher3/graphics/ShadowGenerator.java b/src/com/android/launcher3/graphics/ShadowGenerator.java
index 5fbf502..d2d1699 100644
--- a/src/com/android/launcher3/graphics/ShadowGenerator.java
+++ b/src/com/android/launcher3/graphics/ShadowGenerator.java
@@ -27,10 +27,11 @@
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
-import android.support.v4.graphics.ColorUtils;
import com.android.launcher3.LauncherAppState;
+import androidx.core.graphics.ColorUtils;
+
/**
* Utility class to add shadows to bitmaps.
*/
@@ -120,19 +121,19 @@
}
public Builder setupBlurForSize(int height) {
- shadowBlur = height * 1f / 32;
+ shadowBlur = height * 1f / 24;
keyShadowDistance = height * 1f / 16;
return this;
}
public Bitmap createPill(int width, int height) {
- radius = height / 2;
+ radius = height / 2f;
- int centerX = Math.round(width / 2 + shadowBlur);
+ int centerX = Math.round(width / 2f + shadowBlur);
int centerY = Math.round(radius + shadowBlur + keyShadowDistance);
int center = Math.max(centerX, centerY);
bounds.set(0, 0, width, height);
- bounds.offsetTo(center - width / 2, center - height / 2);
+ bounds.offsetTo(center - width / 2f, center - height / 2f);
int size = center * 2;
Bitmap result = Bitmap.createBitmap(size, size, Config.ARGB_8888);
diff --git a/src/com/android/launcher3/graphics/TriangleShape.java b/src/com/android/launcher3/graphics/TriangleShape.java
index cce4e3c..2c15725 100644
--- a/src/com/android/launcher3/graphics/TriangleShape.java
+++ b/src/com/android/launcher3/graphics/TriangleShape.java
@@ -19,7 +19,8 @@
import android.graphics.Outline;
import android.graphics.Path;
import android.graphics.drawable.shapes.PathShape;
-import android.support.annotation.NonNull;
+
+import androidx.annotation.NonNull;
/**
* Wrapper around {@link android.graphics.drawable.shapes.PathShape}
diff --git a/src/com/android/launcher3/graphics/WorkspaceAndHotseatScrim.java b/src/com/android/launcher3/graphics/WorkspaceAndHotseatScrim.java
index bc4a06d..00cc1a7 100644
--- a/src/com/android/launcher3/graphics/WorkspaceAndHotseatScrim.java
+++ b/src/com/android/launcher3/graphics/WorkspaceAndHotseatScrim.java
@@ -34,7 +34,6 @@
import android.graphics.Region;
import android.graphics.Shader;
import android.graphics.drawable.Drawable;
-import android.support.v4.graphics.ColorUtils;
import android.util.DisplayMetrics;
import android.util.Property;
import android.view.View;
@@ -47,6 +46,8 @@
import com.android.launcher3.uioverrides.WallpaperColorInfo;
import com.android.launcher3.util.Themes;
+import androidx.core.graphics.ColorUtils;
+
/**
* View scrim which draws behind hotseat and workspace
*/
diff --git a/src/com/android/launcher3/keyboard/FocusedItemDecorator.java b/src/com/android/launcher3/keyboard/FocusedItemDecorator.java
index 05ae406..2476a6f 100644
--- a/src/com/android/launcher3/keyboard/FocusedItemDecorator.java
+++ b/src/com/android/launcher3/keyboard/FocusedItemDecorator.java
@@ -17,14 +17,15 @@
package com.android.launcher3.keyboard;
import android.graphics.Canvas;
-import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.RecyclerView.ItemDecoration;
-import android.support.v7.widget.RecyclerView.State;
import android.view.View;
import android.view.View.OnFocusChangeListener;
import com.android.launcher3.keyboard.FocusIndicatorHelper.SimpleFocusIndicatorHelper;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.recyclerview.widget.RecyclerView.ItemDecoration;
+import androidx.recyclerview.widget.RecyclerView.State;
+
/**
* {@link ItemDecoration} for drawing and animating focused view background.
*/
diff --git a/src/com/android/launcher3/logging/UserEventDispatcher.java b/src/com/android/launcher3/logging/UserEventDispatcher.java
index 7087fdb..a318dc0 100644
--- a/src/com/android/launcher3/logging/UserEventDispatcher.java
+++ b/src/com/android/launcher3/logging/UserEventDispatcher.java
@@ -32,7 +32,6 @@
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.SystemClock;
-import android.support.annotation.Nullable;
import android.util.Log;
import android.view.View;
import android.view.ViewParent;
@@ -55,6 +54,8 @@
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.
diff --git a/src/com/android/launcher3/model/GridSizeMigrationTask.java b/src/com/android/launcher3/model/GridSizeMigrationTask.java
index d9b1a3f..12daea5 100644
--- a/src/com/android/launcher3/model/GridSizeMigrationTask.java
+++ b/src/com/android/launcher3/model/GridSizeMigrationTask.java
@@ -138,10 +138,7 @@
*/
protected boolean migrateHotseat() throws Exception {
ArrayList<DbEntry> items = loadHotseatEntries();
-
- int requiredCount = FeatureFlags.NO_ALL_APPS_ICON ? mDestHotseatSize : mDestHotseatSize - 1;
-
- while (items.size() > requiredCount) {
+ while (items.size() > mDestHotseatSize) {
// Pick the center item by default.
DbEntry toRemove = items.get(items.size() / 2);
@@ -171,9 +168,6 @@
}
newScreenId++;
- if (!FeatureFlags.NO_ALL_APPS_ICON && mIdp.isAllAppsButtonRank(newScreenId)) {
- newScreenId++;
- }
}
return applyOperations();
diff --git a/src/com/android/launcher3/model/LoaderCursor.java b/src/com/android/launcher3/model/LoaderCursor.java
index 6378ea1..744e98a 100644
--- a/src/com/android/launcher3/model/LoaderCursor.java
+++ b/src/com/android/launcher3/model/LoaderCursor.java
@@ -24,7 +24,6 @@
import android.content.pm.LauncherActivityInfo;
import android.database.Cursor;
import android.database.CursorWrapper;
-import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.UserHandle;
import android.provider.BaseColumns;
@@ -387,15 +386,6 @@
protected boolean checkItemPlacement(ItemInfo item, ArrayList<Long> workspaceScreens) {
long containerIndex = item.screenId;
if (item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
- // Return early if we detect that an item is under the hotseat button
- if (!FeatureFlags.NO_ALL_APPS_ICON &&
- mIDP.isAllAppsButtonRank((int) item.screenId)) {
- Log.e(TAG, "Error loading shortcut into hotseat " + item
- + " into position (" + item.screenId + ":" + item.cellX + ","
- + item.cellY + ") occupied by all apps");
- return false;
- }
-
final GridOccupancy hotseatOccupancy =
occupied.get((long) LauncherSettings.Favorites.CONTAINER_HOTSEAT);
diff --git a/src/com/android/launcher3/model/ModelPreload.java b/src/com/android/launcher3/model/ModelPreload.java
index f186e95..b353810 100644
--- a/src/com/android/launcher3/model/ModelPreload.java
+++ b/src/com/android/launcher3/model/ModelPreload.java
@@ -16,7 +16,6 @@
package com.android.launcher3.model;
import android.content.Context;
-import android.support.annotation.WorkerThread;
import android.util.Log;
import com.android.launcher3.AllAppsList;
@@ -26,6 +25,8 @@
import java.util.concurrent.Executor;
+import androidx.annotation.WorkerThread;
+
/**
* Utility class to preload LauncherModel
*/
diff --git a/src/com/android/launcher3/model/WidgetsModel.java b/src/com/android/launcher3/model/WidgetsModel.java
index 9f8f263..448ff6c 100644
--- a/src/com/android/launcher3/model/WidgetsModel.java
+++ b/src/com/android/launcher3/model/WidgetsModel.java
@@ -8,7 +8,6 @@
import android.content.pm.PackageManager;
import android.os.Process;
import android.os.UserHandle;
-import android.support.annotation.Nullable;
import android.util.Log;
import com.android.launcher3.AppFilter;
@@ -34,6 +33,8 @@
import java.util.Iterator;
import java.util.Map;
+import androidx.annotation.Nullable;
+
/**
* Widgets data model that is used by the adapters of the widget views and controllers.
*
diff --git a/src/com/android/launcher3/notification/NotificationFooterLayout.java b/src/com/android/launcher3/notification/NotificationFooterLayout.java
index 1216a27..c7de5b0 100644
--- a/src/com/android/launcher3/notification/NotificationFooterLayout.java
+++ b/src/com/android/launcher3/notification/NotificationFooterLayout.java
@@ -29,7 +29,6 @@
import android.widget.FrameLayout;
import android.widget.LinearLayout;
-import com.android.launcher3.LauncherAnimUtils;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.PropertyListBuilder;
@@ -151,15 +150,16 @@
public void animateFirstNotificationTo(Rect toBounds,
final IconAnimationEndListener callback) {
- AnimatorSet animation = LauncherAnimUtils.createAnimatorSet();
+ AnimatorSet animation = new AnimatorSet();
final View firstNotification = mIconRow.getChildAt(mIconRow.getChildCount() - 1);
Rect fromBounds = sTempRect;
firstNotification.getGlobalVisibleRect(fromBounds);
float scale = (float) toBounds.height() / fromBounds.height();
- Animator moveAndScaleIcon = LauncherAnimUtils.ofPropertyValuesHolder(firstNotification,
- new PropertyListBuilder().scale(scale).translationY(toBounds.top - fromBounds.top
- + (fromBounds.height() * scale - fromBounds.height()) / 2).build());
+ Animator moveAndScaleIcon = new PropertyListBuilder().scale(scale)
+ .translationY(toBounds.top - fromBounds.top
+ + (fromBounds.height() * scale - fromBounds.height()) / 2)
+ .build(firstNotification);
moveAndScaleIcon.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
diff --git a/src/com/android/launcher3/notification/NotificationKeyData.java b/src/com/android/launcher3/notification/NotificationKeyData.java
index bf7ae1a..508cf87 100644
--- a/src/com/android/launcher3/notification/NotificationKeyData.java
+++ b/src/com/android/launcher3/notification/NotificationKeyData.java
@@ -18,11 +18,12 @@
import android.app.Notification;
import android.service.notification.StatusBarNotification;
-import android.support.annotation.NonNull;
import java.util.ArrayList;
import java.util.List;
+import androidx.annotation.NonNull;
+
/**
* The key data associated with the notification, used to determine what to include
* in badges and dummy popup views before they are populated.
diff --git a/src/com/android/launcher3/notification/NotificationListener.java b/src/com/android/launcher3/notification/NotificationListener.java
index ac5aaf8..4c85c8b 100644
--- a/src/com/android/launcher3/notification/NotificationListener.java
+++ b/src/com/android/launcher3/notification/NotificationListener.java
@@ -27,7 +27,6 @@
import android.os.Message;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
-import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
@@ -45,6 +44,8 @@
import java.util.Map;
import java.util.Set;
+import androidx.annotation.Nullable;
+
/**
* A {@link NotificationListenerService} that sends updates to its
* {@link NotificationsChangedListener} when notifications are posted or canceled,
diff --git a/src/com/android/launcher3/popup/ArrowPopup.java b/src/com/android/launcher3/popup/ArrowPopup.java
index e157482..3bf8bef 100644
--- a/src/com/android/launcher3/popup/ArrowPopup.java
+++ b/src/com/android/launcher3/popup/ArrowPopup.java
@@ -340,7 +340,7 @@
private void animateOpen() {
setVisibility(View.VISIBLE);
- final AnimatorSet openAnim = LauncherAnimUtils.createAnimatorSet();
+ final AnimatorSet openAnim = new AnimatorSet();
final Resources res = getResources();
final long revealDuration = (long) res.getInteger(R.integer.config_popupOpenCloseDuration);
final TimeInterpolator revealInterpolator = new AccelerateDecelerateInterpolator();
@@ -388,7 +388,7 @@
}
mIsOpen = false;
- final AnimatorSet closeAnim = LauncherAnimUtils.createAnimatorSet();
+ final AnimatorSet closeAnim = new AnimatorSet();
// Hide the arrow
closeAnim.play(ObjectAnimator.ofFloat(mArrow, LauncherAnimUtils.SCALE_PROPERTY, 0));
closeAnim.play(ObjectAnimator.ofFloat(mArrow, ALPHA, 0));
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index 635e043..10be925 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -84,7 +84,7 @@
private final List<DeepShortcutView> mShortcuts = new ArrayList<>();
private final PointF mInterceptTouchDown = new PointF();
- private final Point mIconLastTouchPos = new Point();
+ protected final Point mIconLastTouchPos = new Point();
private final int mStartDragThreshold;
private final LauncherAccessibilityDelegate mAccessibilityDelegate;
diff --git a/src/com/android/launcher3/popup/PopupDataProvider.java b/src/com/android/launcher3/popup/PopupDataProvider.java
index f1b8ec0..3faec44 100644
--- a/src/com/android/launcher3/popup/PopupDataProvider.java
+++ b/src/com/android/launcher3/popup/PopupDataProvider.java
@@ -18,7 +18,6 @@
import android.content.ComponentName;
import android.service.notification.StatusBarNotification;
-import android.support.annotation.NonNull;
import android.util.Log;
import com.android.launcher3.ItemInfo;
@@ -41,6 +40,8 @@
import java.util.List;
import java.util.Map;
+import androidx.annotation.NonNull;
+
/**
* Provides data for the popup menu that appears after long-clicking on apps.
*/
diff --git a/src/com/android/launcher3/popup/PopupPopulator.java b/src/com/android/launcher3/popup/PopupPopulator.java
index b295bb2..4500629 100644
--- a/src/com/android/launcher3/popup/PopupPopulator.java
+++ b/src/com/android/launcher3/popup/PopupPopulator.java
@@ -20,8 +20,6 @@
import android.os.Handler;
import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
-import android.support.annotation.Nullable;
-import android.support.annotation.VisibleForTesting;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.Launcher;
@@ -40,6 +38,9 @@
import java.util.Iterator;
import java.util.List;
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
+
/**
* Contains logic relevant to populating a {@link PopupContainerWithArrow}. In particular,
* this class determines which items appear in the container, and in what order.
diff --git a/src/com/android/launcher3/popup/SystemShortcut.java b/src/com/android/launcher3/popup/SystemShortcut.java
index 3c1cc90..693e532 100644
--- a/src/com/android/launcher3/popup/SystemShortcut.java
+++ b/src/com/android/launcher3/popup/SystemShortcut.java
@@ -75,6 +75,7 @@
public View.OnClickListener getOnClickListener(
BaseDraggingActivity activity, ItemInfo itemInfo) {
return (view) -> {
+ dismissTaskMenuView(activity);
Rect sourceBounds = activity.getViewBounds(view);
Bundle opts = activity.getActivityLaunchOptionsAsBundle(view);
new PackageManagerHelper(activity).startDetailsActivityForInfo(
@@ -117,4 +118,9 @@
};
}
}
+
+ protected static void dismissTaskMenuView(BaseDraggingActivity activity) {
+ AbstractFloatingView.closeOpenViews(activity, true,
+ AbstractFloatingView.TYPE_ALL & ~AbstractFloatingView.TYPE_REBIND_SAFE);
+ }
}
diff --git a/src/com/android/launcher3/provider/ImportDataTask.java b/src/com/android/launcher3/provider/ImportDataTask.java
index b1dd003..16c7417 100644
--- a/src/com/android/launcher3/provider/ImportDataTask.java
+++ b/src/com/android/launcher3/provider/ImportDataTask.java
@@ -308,9 +308,6 @@
LongArrayMap<Object> hotseatItems = GridSizeMigrationTask.removeBrokenHotseatItems(mContext);
int myHotseatCount = LauncherAppState.getIDP(mContext).numHotseatIcons;
- if (!FeatureFlags.NO_ALL_APPS_ICON) {
- myHotseatCount--;
- }
if (hotseatItems.size() < myHotseatCount) {
// Insufficient hotseat items. Add a few more.
HotseatParserCallback parserCallback = new HotseatParserCallback(
diff --git a/src/com/android/launcher3/shortcuts/DeepShortcutView.java b/src/com/android/launcher3/shortcuts/DeepShortcutView.java
index 7d0ea7b..c856cdb 100644
--- a/src/com/android/launcher3/shortcuts/DeepShortcutView.java
+++ b/src/com/android/launcher3/shortcuts/DeepShortcutView.java
@@ -141,4 +141,8 @@
public View getIconView() {
return mIconView;
}
+
+ public ShortcutInfoCompat getDetail() {
+ return mDetail;
+ }
}
diff --git a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
index 55f850c..fd9157e 100644
--- a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
+++ b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
@@ -39,10 +39,12 @@
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;
import com.android.launcher3.anim.AnimatorSetBuilder;
+import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
@@ -515,6 +517,9 @@
logReachedState(logAction, targetState);
}
mLauncher.getStateManager().goToState(targetState, false /* animated */);
+
+ AccessibilityManagerCompat.sendEventToTest(
+ mLauncher, TestProtocol.SWITCHED_TO_STATE_MESSAGE);
}
}
diff --git a/src/com/android/launcher3/touch/ItemClickHandler.java b/src/com/android/launcher3/touch/ItemClickHandler.java
index 97f836f..52fef9f 100644
--- a/src/com/android/launcher3/touch/ItemClickHandler.java
+++ b/src/com/android/launcher3/touch/ItemClickHandler.java
@@ -218,7 +218,7 @@
if (item instanceof ShortcutInfo) {
ShortcutInfo si = (ShortcutInfo) item;
if (si.hasStatusFlag(ShortcutInfo.FLAG_SUPPORTS_WEB_UI)
- && intent.getAction() == Intent.ACTION_VIEW) {
+ && Intent.ACTION_VIEW.equals(intent.getAction())) {
// make a copy of the intent that has the package set to null
// we do this because the platform sometimes disables instant
// apps temporarily (triggered by the user) and fallbacks to the
diff --git a/src/com/android/launcher3/touch/OverScroll.java b/src/com/android/launcher3/touch/OverScroll.java
index dc801ec..bf895ad 100644
--- a/src/com/android/launcher3/touch/OverScroll.java
+++ b/src/com/android/launcher3/touch/OverScroll.java
@@ -20,7 +20,7 @@
*/
public class OverScroll {
- private static final float OVERSCROLL_DAMP_FACTOR = 0.07f;
+ public static final float OVERSCROLL_DAMP_FACTOR = 0.07f;
/**
* This curve determines how the effect of scrolling over the limits of the page diminishes
diff --git a/src/com/android/launcher3/touch/SwipeDetector.java b/src/com/android/launcher3/touch/SwipeDetector.java
index 703e4fd..6ffc0ef 100644
--- a/src/com/android/launcher3/touch/SwipeDetector.java
+++ b/src/com/android/launcher3/touch/SwipeDetector.java
@@ -19,12 +19,13 @@
import android.content.Context;
import android.graphics.PointF;
-import android.support.annotation.NonNull;
-import android.support.annotation.VisibleForTesting;
import android.util.Log;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
+import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
+
/**
* One dimensional scroll/drag/swipe gesture detector.
*
diff --git a/src/com/android/launcher3/touch/WorkspaceTouchListener.java b/src/com/android/launcher3/touch/WorkspaceTouchListener.java
index f59f14e..6688927 100644
--- a/src/com/android/launcher3/touch/WorkspaceTouchListener.java
+++ b/src/com/android/launcher3/touch/WorkspaceTouchListener.java
@@ -125,7 +125,7 @@
}
if (action == ACTION_UP || action == ACTION_POINTER_UP) {
- if (!mWorkspace.isTouchActive()) {
+ if (!mWorkspace.isHandlingTouch()) {
final CellLayout currentPage =
(CellLayout) mWorkspace.getChildAt(mWorkspace.getCurrentPage());
if (currentPage != null) {
diff --git a/src/com/android/launcher3/util/FocusLogic.java b/src/com/android/launcher3/util/FocusLogic.java
index b793f54..4f4cccd 100644
--- a/src/com/android/launcher3/util/FocusLogic.java
+++ b/src/com/android/launcher3/util/FocusLogic.java
@@ -201,10 +201,6 @@
ViewGroup hotseatParent = hotseatLayout.getShortcutsAndWidgets();
boolean isHotseatHorizontal = !dp.isVerticalBarLayout();
- boolean moreIconsInHotseatThanWorkspace = !FeatureFlags.NO_ALL_APPS_ICON &&
- (isHotseatHorizontal
- ? hotseatLayout.getCountX() > iconLayout.getCountX()
- : hotseatLayout.getCountY() > iconLayout.getCountY());
int m, n;
if (isHotseatHorizontal) {
@@ -215,19 +211,7 @@
n = hotseatLayout.getCountY();
}
int[][] matrix = createFullMatrix(m, n);
- if (moreIconsInHotseatThanWorkspace) {
- int allappsiconRank = dp.inv.getAllAppsButtonRank();
- if (isHotseatHorizontal) {
- for (int j = 0; j < n; j++) {
- matrix[allappsiconRank][j] = ALL_APPS_COLUMN;
- }
- } else {
- for (int j = 0; j < m; j++) {
- matrix[j][allappsiconRank] = ALL_APPS_COLUMN;
- }
- }
- }
- // Iterate thru the children of the workspace.
+ // Iterate through the children of the workspace.
for (int i = 0; i < iconParent.getChildCount(); i++) {
View cell = iconParent.getChildAt(i);
if (!cell.isFocusable()) {
@@ -235,17 +219,6 @@
}
int cx = ((CellLayout.LayoutParams) cell.getLayoutParams()).cellX;
int cy = ((CellLayout.LayoutParams) cell.getLayoutParams()).cellY;
- if (moreIconsInHotseatThanWorkspace) {
- int allappsiconRank = dp.inv.getAllAppsButtonRank();
- if (isHotseatHorizontal && cx >= allappsiconRank) {
- // Add 1 to account for the All Apps button.
- cx++;
- }
- if (!isHotseatHorizontal && cy >= allappsiconRank) {
- // Add 1 to account for the All Apps button.
- cy++;
- }
- }
matrix[cx][cy] = i;
}
diff --git a/src/com/android/launcher3/util/ListViewHighlighter.java b/src/com/android/launcher3/util/ListViewHighlighter.java
index ecad2af..360546e 100644
--- a/src/com/android/launcher3/util/ListViewHighlighter.java
+++ b/src/com/android/launcher3/util/ListViewHighlighter.java
@@ -21,7 +21,6 @@
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
-import android.support.v4.graphics.ColorUtils;
import android.view.View;
import android.view.View.OnLayoutChangeListener;
import android.widget.AbsListView;
@@ -31,6 +30,8 @@
import com.android.launcher3.R;
+import androidx.core.graphics.ColorUtils;
+
/**
* Utility class to scroll and highlight a list view item
*/
diff --git a/src/com/android/launcher3/util/OverScroller.java b/src/com/android/launcher3/util/OverScroller.java
new file mode 100644
index 0000000..d697ece
--- /dev/null
+++ b/src/com/android/launcher3/util/OverScroller.java
@@ -0,0 +1,779 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.util;
+
+import static com.android.launcher3.anim.Interpolators.SCROLL;
+
+import android.animation.TimeInterpolator;
+import android.content.Context;
+import android.hardware.SensorManager;
+import android.util.Log;
+import android.view.ViewConfiguration;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
+
+/**
+ * Based on {@link android.widget.OverScroller} supporting only 1-d scrolling and with more
+ * customization options.
+ */
+public class OverScroller {
+ private int mMode;
+
+ private final SplineOverScroller mScroller;
+
+ private TimeInterpolator mInterpolator;
+
+ private final boolean mFlywheel;
+
+ private static final int DEFAULT_DURATION = 250;
+ private static final int SCROLL_MODE = 0;
+ private static final int FLING_MODE = 1;
+
+ /**
+ * Creates an OverScroller with a viscous fluid scroll interpolator and flywheel.
+ * @param context
+ */
+ public OverScroller(Context context) {
+ this(context, null);
+ }
+
+ /**
+ * Creates an OverScroller with flywheel enabled.
+ * @param context The context of this application.
+ * @param interpolator The scroll interpolator. If null, a default (viscous) interpolator will
+ * be used.
+ */
+ public OverScroller(Context context, Interpolator interpolator) {
+ this(context, interpolator, true);
+ }
+
+ /**
+ * Creates an OverScroller.
+ * @param context The context of this application.
+ * @param interpolator The scroll interpolator. If null, a default (viscous) interpolator will
+ * be used.
+ * @param flywheel If true, successive fling motions will keep on increasing scroll speed.
+ */
+ public OverScroller(Context context, Interpolator interpolator, boolean flywheel) {
+ if (interpolator == null) {
+ mInterpolator = SCROLL;
+ } else {
+ mInterpolator = interpolator;
+ }
+ mFlywheel = flywheel;
+ mScroller = new SplineOverScroller(context);
+ }
+
+ public void setInterpolator(TimeInterpolator interpolator) {
+ if (interpolator == null) {
+ mInterpolator = SCROLL;
+ } else {
+ mInterpolator = interpolator;
+ }
+ }
+
+ /**
+ * The amount of friction applied to flings. The default value
+ * is {@link ViewConfiguration#getScrollFriction}.
+ *
+ * @param friction A scalar dimension-less value representing the coefficient of
+ * friction.
+ */
+ public final void setFriction(float friction) {
+ mScroller.setFriction(friction);
+ }
+
+ /**
+ *
+ * Returns whether the scroller has finished scrolling.
+ *
+ * @return True if the scroller has finished scrolling, false otherwise.
+ */
+ public final boolean isFinished() {
+ return mScroller.mFinished;
+ }
+
+ /**
+ * Force the finished field to a particular value. Contrary to
+ * {@link #abortAnimation()}, forcing the animation to finished
+ * does NOT cause the scroller to move to the final x and y
+ * position.
+ *
+ * @param finished The new finished value.
+ */
+ public final void forceFinished(boolean finished) {
+ mScroller.mFinished = finished;
+ }
+
+ /**
+ * Returns the current offset in the scroll.
+ *
+ * @return The new offset as an absolute distance from the origin.
+ */
+ public final int getCurrPos() {
+ return mScroller.mCurrentPosition;
+ }
+
+ /**
+ * Returns the absolute value of the current velocity.
+ *
+ * @return The original velocity less the deceleration, norm of the X and Y velocity vector.
+ */
+ public float getCurrVelocity() {
+ return mScroller.mCurrVelocity;
+ }
+
+ /**
+ * Returns the start offset in the scroll.
+ *
+ * @return The start offset as an absolute distance from the origin.
+ */
+ public final int getStartPos() {
+ return mScroller.mStart;
+ }
+
+ /**
+ * Returns where the scroll will end. Valid only for "fling" scrolls.
+ *
+ * @return The final offset as an absolute distance from the origin.
+ */
+ public final int getFinalPos() {
+ return mScroller.mFinal;
+ }
+
+ /**
+ * Returns how long the scroll event will take, in milliseconds.
+ *
+ * @return The duration of the scroll in milliseconds.
+ */
+ public final int getDuration() {
+ return mScroller.mDuration;
+ }
+
+ /**
+ * Extend the scroll animation. This allows a running animation to scroll
+ * further and longer, when used with {@link #setFinalPos(int)}.
+ *
+ * @param extend Additional time to scroll in milliseconds.
+ * @see #setFinalPos(int)
+ */
+ public void extendDuration(int extend) {
+ mScroller.extendDuration(extend);
+ }
+
+ /**
+ * Sets the final position for this scroller.
+ *
+ * @param newPos The new offset as an absolute distance from the origin.
+ * @see #extendDuration(int)
+ */
+ public void setFinalPos(int newPos) {
+ mScroller.setFinalPosition(newPos);
+ }
+
+ /**
+ * Call this when you want to know the new location. If it returns true, the
+ * animation is not yet finished.
+ */
+ public boolean computeScrollOffset() {
+ if (isFinished()) {
+ return false;
+ }
+
+ switch (mMode) {
+ case SCROLL_MODE:
+ long time = AnimationUtils.currentAnimationTimeMillis();
+ // Any scroller can be used for time, since they were started
+ // together in scroll mode. We use X here.
+ final long elapsedTime = time - mScroller.mStartTime;
+
+ final int duration = mScroller.mDuration;
+ if (elapsedTime < duration) {
+ final float q = mInterpolator.getInterpolation(elapsedTime / (float) duration);
+ mScroller.updateScroll(q);
+ } else {
+ abortAnimation();
+ }
+ break;
+
+ case FLING_MODE:
+ if (!mScroller.mFinished) {
+ if (!mScroller.update()) {
+ if (!mScroller.continueWhenFinished()) {
+ mScroller.finish();
+ }
+ }
+ }
+
+ break;
+ }
+
+ return true;
+ }
+
+ /**
+ * Start scrolling by providing a starting point and the distance to travel.
+ * The scroll will use the default value of 250 milliseconds for the
+ * duration.
+ *
+ * @param start Starting horizontal scroll offset in pixels. Positive
+ * numbers will scroll the content to the left.
+ * @param delta Distance to travel. Positive numbers will scroll the
+ * content to the left.
+ */
+ public void startScroll(int start, int delta) {
+ startScroll(start, delta, DEFAULT_DURATION);
+ }
+
+ /**
+ * Start scrolling by providing a starting point and the distance to travel.
+ *
+ * @param start Starting scroll offset in pixels. Positive
+ * numbers will scroll the content to the left.
+ * @param delta Distance to travel. Positive numbers will scroll the
+ * content to the left.
+ * @param duration Duration of the scroll in milliseconds.
+ */
+ public void startScroll(int start, int delta, int duration) {
+ mMode = SCROLL_MODE;
+ mScroller.startScroll(start, delta, duration);
+ }
+
+ /**
+ * Call this when you want to 'spring back' into a valid coordinate range.
+ *
+ * @param start Starting X coordinate
+ * @param min Minimum valid X value
+ * @param max Maximum valid X value
+ * @return true if a springback was initiated, false if startX and startY were
+ * already within the valid range.
+ */
+ public boolean springBack(int start, int min, int max) {
+ mMode = FLING_MODE;
+ return mScroller.springback(start, min, max);
+ }
+
+ public void fling(int start, int velocity, int min, int max) {
+ fling(start, velocity, min, max, 0);
+ }
+
+ /**
+ * Start scrolling based on a fling gesture. The distance traveled will
+ * depend on the initial velocity of the fling.
+ * @param start Starting point of the scroll (X)
+ * @param velocity Initial velocity of the fling (X) measured in pixels per
+ * second.
+ * @param min Minimum X value. The scroller will not scroll past this point
+ * unless overX > 0. If overfling is allowed, it will use minX as
+ * a springback boundary.
+ * @param max Maximum X value. The scroller will not scroll past this point
+* unless overX > 0. If overfling is allowed, it will use maxX as
+* a springback boundary.
+ * @param over Overfling range. If > 0, horizontal overfling in either
+* direction will be possible.
+ */
+ public void fling(int start, int velocity, int min, int max, int over) {
+ // Continue a scroll or fling in progress
+ if (mFlywheel && !isFinished()) {
+ float oldVelocityX = mScroller.mCurrVelocity;
+ if (Math.signum(velocity) == Math.signum(oldVelocityX)) {
+ velocity += oldVelocityX;
+ }
+ }
+
+ mMode = FLING_MODE;
+ mScroller.fling(start, velocity, min, max, over);
+ }
+
+ /**
+ * Notify the scroller that we've reached a horizontal boundary.
+ * Normally the information to handle this will already be known
+ * when the animation is started, such as in a call to one of the
+ * fling functions. However there are cases where this cannot be known
+ * in advance. This function will transition the current motion and
+ * animate from startX to finalX as appropriate.
+ * @param start Starting/current X position
+ * @param finalPos Desired final X position
+ * @param over Magnitude of overscroll allowed. This should be the maximum
+ */
+ public void notifyEdgeReached(int start, int finalPos, int over) {
+ mScroller.notifyEdgeReached(start, finalPos, over);
+ }
+
+ /**
+ * Returns whether the current Scroller is currently returning to a valid position.
+ * Valid bounds were provided by the
+ * {@link #fling(int, int, int, int, int)} method.
+ *
+ * One should check this value before calling
+ * {@link #startScroll(int, int)} as the interpolation currently in progress
+ * to restore a valid position will then be stopped. The caller has to take into account
+ * the fact that the started scroll will start from an overscrolled position.
+ *
+ * @return true when the current position is overscrolled and in the process of
+ * interpolating back to a valid value.
+ */
+ public boolean isOverScrolled() {
+ return (!mScroller.mFinished && mScroller.mState != SplineOverScroller.SPLINE);
+ }
+
+ /**
+ * Stops the animation. Contrary to {@link #forceFinished(boolean)},
+ * aborting the animating causes the scroller to move to the final x and y
+ * positions.
+ *
+ * @see #forceFinished(boolean)
+ */
+ public void abortAnimation() {
+ mScroller.finish();
+ }
+
+ /**
+ * Returns the time elapsed since the beginning of the scrolling.
+ *
+ * @return The elapsed time in milliseconds.
+ *
+ * @hide
+ */
+ public int timePassed() {
+ final long time = AnimationUtils.currentAnimationTimeMillis();
+ return (int) (time - mScroller.mStartTime);
+ }
+
+ static class SplineOverScroller {
+ // Initial position
+ private int mStart;
+
+ // Current position
+ private int mCurrentPosition;
+
+ // Final position
+ private int mFinal;
+
+ // Initial velocity
+ private int mVelocity;
+
+ // Current velocity
+ private float mCurrVelocity;
+
+ // Constant current deceleration
+ private float mDeceleration;
+
+ // Animation starting time, in system milliseconds
+ private long mStartTime;
+
+ // Animation duration, in milliseconds
+ private int mDuration;
+
+ // Duration to complete spline component of animation
+ private int mSplineDuration;
+
+ // Distance to travel along spline animation
+ private int mSplineDistance;
+
+ // Whether the animation is currently in progress
+ private boolean mFinished;
+
+ // The allowed overshot distance before boundary is reached.
+ private int mOver;
+
+ // Fling friction
+ private float mFlingFriction = ViewConfiguration.getScrollFriction();
+
+ // Current state of the animation.
+ private int mState = SPLINE;
+
+ // Constant gravity value, used in the deceleration phase.
+ private static final float GRAVITY = 2000.0f;
+
+ // A context-specific coefficient adjusted to physical values.
+ private float mPhysicalCoeff;
+
+ private static float DECELERATION_RATE = (float) (Math.log(0.78) / Math.log(0.9));
+ private static final float INFLEXION = 0.35f; // Tension lines cross at (INFLEXION, 1)
+ private static final float START_TENSION = 0.5f;
+ private static final float END_TENSION = 1.0f;
+ private static final float P1 = START_TENSION * INFLEXION;
+ private static final float P2 = 1.0f - END_TENSION * (1.0f - INFLEXION);
+
+ private static final int NB_SAMPLES = 100;
+ private static final float[] SPLINE_POSITION = new float[NB_SAMPLES + 1];
+ private static final float[] SPLINE_TIME = new float[NB_SAMPLES + 1];
+
+ private static final int SPLINE = 0;
+ private static final int CUBIC = 1;
+ private static final int BALLISTIC = 2;
+
+ static {
+ float x_min = 0.0f;
+ float y_min = 0.0f;
+ for (int i = 0; i < NB_SAMPLES; i++) {
+ final float alpha = (float) i / NB_SAMPLES;
+
+ float x_max = 1.0f;
+ float x, tx, coef;
+ while (true) {
+ x = x_min + (x_max - x_min) / 2.0f;
+ coef = 3.0f * x * (1.0f - x);
+ tx = coef * ((1.0f - x) * P1 + x * P2) + x * x * x;
+ if (Math.abs(tx - alpha) < 1E-5) break;
+ if (tx > alpha) x_max = x;
+ else x_min = x;
+ }
+ SPLINE_POSITION[i] = coef * ((1.0f - x) * START_TENSION + x) + x * x * x;
+
+ float y_max = 1.0f;
+ float y, dy;
+ while (true) {
+ y = y_min + (y_max - y_min) / 2.0f;
+ coef = 3.0f * y * (1.0f - y);
+ dy = coef * ((1.0f - y) * START_TENSION + y) + y * y * y;
+ if (Math.abs(dy - alpha) < 1E-5) break;
+ if (dy > alpha) y_max = y;
+ else y_min = y;
+ }
+ SPLINE_TIME[i] = coef * ((1.0f - y) * P1 + y * P2) + y * y * y;
+ }
+ SPLINE_POSITION[NB_SAMPLES] = SPLINE_TIME[NB_SAMPLES] = 1.0f;
+ }
+
+ void setFriction(float friction) {
+ mFlingFriction = friction;
+ }
+
+ SplineOverScroller(Context context) {
+ mFinished = true;
+ final float ppi = context.getResources().getDisplayMetrics().density * 160.0f;
+ mPhysicalCoeff = SensorManager.GRAVITY_EARTH // g (m/s^2)
+ * 39.37f // inch/meter
+ * ppi
+ * 0.84f; // look and feel tuning
+ }
+
+ void updateScroll(float q) {
+ mCurrentPosition = mStart + Math.round(q * (mFinal - mStart));
+ }
+
+ /*
+ * Get a signed deceleration that will reduce the velocity.
+ */
+ static private float getDeceleration(int velocity) {
+ return velocity > 0 ? -GRAVITY : GRAVITY;
+ }
+
+ /*
+ * Modifies mDuration to the duration it takes to get from start to newFinal using the
+ * spline interpolation. The previous duration was needed to get to oldFinal.
+ */
+ private void adjustDuration(int start, int oldFinal, int newFinal) {
+ final int oldDistance = oldFinal - start;
+ final int newDistance = newFinal - start;
+ final float x = Math.abs((float) newDistance / oldDistance);
+ final int index = (int) (NB_SAMPLES * x);
+ if (index < NB_SAMPLES) {
+ final float x_inf = (float) index / NB_SAMPLES;
+ final float x_sup = (float) (index + 1) / NB_SAMPLES;
+ final float t_inf = SPLINE_TIME[index];
+ final float t_sup = SPLINE_TIME[index + 1];
+ final float timeCoef = t_inf + (x - x_inf) / (x_sup - x_inf) * (t_sup - t_inf);
+ mDuration *= timeCoef;
+ }
+ }
+
+ void startScroll(int start, int distance, int duration) {
+ mFinished = false;
+
+ mCurrentPosition = mStart = start;
+ mFinal = start + distance;
+
+ mStartTime = AnimationUtils.currentAnimationTimeMillis();
+ mDuration = duration;
+
+ // Unused
+ mDeceleration = 0.0f;
+ mVelocity = 0;
+ }
+
+ void finish() {
+ mCurrentPosition = mFinal;
+ // Not reset since WebView relies on this value for fast fling.
+ // TODO: restore when WebView uses the fast fling implemented in this class.
+ // mCurrVelocity = 0.0f;
+ mFinished = true;
+ }
+
+ void setFinalPosition(int position) {
+ mFinal = position;
+ mSplineDistance = mFinal - mStart;
+ mFinished = false;
+ }
+
+ void extendDuration(int extend) {
+ final long time = AnimationUtils.currentAnimationTimeMillis();
+ final int elapsedTime = (int) (time - mStartTime);
+ mDuration = mSplineDuration = elapsedTime + extend;
+ mFinished = false;
+ }
+
+ boolean springback(int start, int min, int max) {
+ mFinished = true;
+
+ mCurrentPosition = mStart = mFinal = start;
+ mVelocity = 0;
+
+ mStartTime = AnimationUtils.currentAnimationTimeMillis();
+ mDuration = 0;
+
+ if (start < min) {
+ startSpringback(start, min, 0);
+ } else if (start > max) {
+ startSpringback(start, max, 0);
+ }
+
+ return !mFinished;
+ }
+
+ private void startSpringback(int start, int end, int velocity) {
+ // mStartTime has been set
+ mFinished = false;
+ mState = CUBIC;
+ mCurrentPosition = mStart = start;
+ mFinal = end;
+ final int delta = start - end;
+ mDeceleration = getDeceleration(delta);
+ // TODO take velocity into account
+ mVelocity = -delta; // only sign is used
+ mOver = Math.abs(delta);
+ mDuration = (int) (1000.0 * Math.sqrt(-2.0 * delta / mDeceleration));
+ }
+
+ void fling(int start, int velocity, int min, int max, int over) {
+ mOver = over;
+ mFinished = false;
+ mCurrVelocity = mVelocity = velocity;
+ mDuration = mSplineDuration = 0;
+ mStartTime = AnimationUtils.currentAnimationTimeMillis();
+ mCurrentPosition = mStart = start;
+
+ if (start > max || start < min) {
+ startAfterEdge(start, min, max, velocity);
+ return;
+ }
+
+ mState = SPLINE;
+ double totalDistance = 0.0;
+
+ if (velocity != 0) {
+ mDuration = mSplineDuration = getSplineFlingDuration(velocity);
+ totalDistance = getSplineFlingDistance(velocity);
+ }
+
+ mSplineDistance = (int) (totalDistance * Math.signum(velocity));
+ mFinal = start + mSplineDistance;
+
+ // Clamp to a valid final position
+ if (mFinal < min) {
+ adjustDuration(mStart, mFinal, min);
+ mFinal = min;
+ }
+
+ if (mFinal > max) {
+ adjustDuration(mStart, mFinal, max);
+ mFinal = max;
+ }
+ }
+
+ private double getSplineDeceleration(int velocity) {
+ return Math.log(INFLEXION * Math.abs(velocity) / (mFlingFriction * mPhysicalCoeff));
+ }
+
+ private double getSplineFlingDistance(int velocity) {
+ final double l = getSplineDeceleration(velocity);
+ final double decelMinusOne = DECELERATION_RATE - 1.0;
+ return mFlingFriction * mPhysicalCoeff * Math.exp(DECELERATION_RATE / decelMinusOne * l);
+ }
+
+ /* Returns the duration, expressed in milliseconds */
+ private int getSplineFlingDuration(int velocity) {
+ final double l = getSplineDeceleration(velocity);
+ final double decelMinusOne = DECELERATION_RATE - 1.0;
+ return (int) (1000.0 * Math.exp(l / decelMinusOne));
+ }
+
+ private void fitOnBounceCurve(int start, int end, int velocity) {
+ // Simulate a bounce that started from edge
+ final float durationToApex = - velocity / mDeceleration;
+ // The float cast below is necessary to avoid integer overflow.
+ final float velocitySquared = (float) velocity * velocity;
+ final float distanceToApex = velocitySquared / 2.0f / Math.abs(mDeceleration);
+ final float distanceToEdge = Math.abs(end - start);
+ final float totalDuration = (float) Math.sqrt(
+ 2.0 * (distanceToApex + distanceToEdge) / Math.abs(mDeceleration));
+ mStartTime -= (int) (1000.0f * (totalDuration - durationToApex));
+ mCurrentPosition = mStart = end;
+ mVelocity = (int) (- mDeceleration * totalDuration);
+ }
+
+ private void startBounceAfterEdge(int start, int end, int velocity) {
+ mDeceleration = getDeceleration(velocity == 0 ? start - end : velocity);
+ fitOnBounceCurve(start, end, velocity);
+ onEdgeReached();
+ }
+
+ private void startAfterEdge(int start, int min, int max, int velocity) {
+ if (start > min && start < max) {
+ Log.e("OverScroller", "startAfterEdge called from a valid position");
+ mFinished = true;
+ return;
+ }
+ final boolean positive = start > max;
+ final int edge = positive ? max : min;
+ final int overDistance = start - edge;
+ boolean keepIncreasing = overDistance * velocity >= 0;
+ if (keepIncreasing) {
+ // Will result in a bounce or a to_boundary depending on velocity.
+ startBounceAfterEdge(start, edge, velocity);
+ } else {
+ final double totalDistance = getSplineFlingDistance(velocity);
+ if (totalDistance > Math.abs(overDistance)) {
+ fling(start, velocity, positive ? min : start, positive ? start : max, mOver);
+ } else {
+ startSpringback(start, edge, velocity);
+ }
+ }
+ }
+
+ void notifyEdgeReached(int start, int end, int over) {
+ // mState is used to detect successive notifications
+ if (mState == SPLINE) {
+ mOver = over;
+ mStartTime = AnimationUtils.currentAnimationTimeMillis();
+ // We were in fling/scroll mode before: current velocity is such that distance to
+ // edge is increasing. This ensures that startAfterEdge will not start a new fling.
+ startAfterEdge(start, end, end, (int) mCurrVelocity);
+ }
+ }
+
+ private void onEdgeReached() {
+ // mStart, mVelocity and mStartTime were adjusted to their values when edge was reached.
+ // The float cast below is necessary to avoid integer overflow.
+ final float velocitySquared = (float) mVelocity * mVelocity;
+ float distance = velocitySquared / (2.0f * Math.abs(mDeceleration));
+ final float sign = Math.signum(mVelocity);
+
+ if (distance > mOver) {
+ // Default deceleration is not sufficient to slow us down before boundary
+ mDeceleration = - sign * velocitySquared / (2.0f * mOver);
+ distance = mOver;
+ }
+
+ mOver = (int) distance;
+ mState = BALLISTIC;
+ mFinal = mStart + (int) (mVelocity > 0 ? distance : -distance);
+ mDuration = - (int) (1000.0f * mVelocity / mDeceleration);
+ }
+
+ boolean continueWhenFinished() {
+ switch (mState) {
+ case SPLINE:
+ // Duration from start to null velocity
+ if (mDuration < mSplineDuration) {
+ // If the animation was clamped, we reached the edge
+ mCurrentPosition = mStart = mFinal;
+ // TODO Better compute speed when edge was reached
+ mVelocity = (int) mCurrVelocity;
+ mDeceleration = getDeceleration(mVelocity);
+ mStartTime += mDuration;
+ onEdgeReached();
+ } else {
+ // Normal stop, no need to continue
+ return false;
+ }
+ break;
+ case BALLISTIC:
+ mStartTime += mDuration;
+ startSpringback(mFinal, mStart, 0);
+ break;
+ case CUBIC:
+ return false;
+ }
+
+ update();
+ return true;
+ }
+
+ /*
+ * Update the current position and velocity for current time. Returns
+ * true if update has been done and false if animation duration has been
+ * reached.
+ */
+ boolean update() {
+ final long time = AnimationUtils.currentAnimationTimeMillis();
+ final long currentTime = time - mStartTime;
+
+ if (currentTime == 0) {
+ // Skip work but report that we're still going if we have a nonzero duration.
+ return mDuration > 0;
+ }
+ if (currentTime > mDuration) {
+ return false;
+ }
+
+ double distance = 0.0;
+ switch (mState) {
+ case SPLINE: {
+ final float t = (float) currentTime / mSplineDuration;
+ final int index = (int) (NB_SAMPLES * t);
+ float distanceCoef = 1.f;
+ float velocityCoef = 0.f;
+ if (index < NB_SAMPLES) {
+ final float t_inf = (float) index / NB_SAMPLES;
+ final float t_sup = (float) (index + 1) / NB_SAMPLES;
+ final float d_inf = SPLINE_POSITION[index];
+ final float d_sup = SPLINE_POSITION[index + 1];
+ velocityCoef = (d_sup - d_inf) / (t_sup - t_inf);
+ distanceCoef = d_inf + (t - t_inf) * velocityCoef;
+ }
+
+ distance = distanceCoef * mSplineDistance;
+ mCurrVelocity = velocityCoef * mSplineDistance / mSplineDuration * 1000.0f;
+ break;
+ }
+
+ case BALLISTIC: {
+ final float t = currentTime / 1000.0f;
+ mCurrVelocity = mVelocity + mDeceleration * t;
+ distance = mVelocity * t + mDeceleration * t * t / 2.0f;
+ break;
+ }
+
+ case CUBIC: {
+ final float t = (float) (currentTime) / mDuration;
+ final float t2 = t * t;
+ final float sign = Math.signum(mVelocity);
+ distance = sign * mOver * (3.0f * t2 - 2.0f * t * t2);
+ mCurrVelocity = sign * mOver * 6.0f * (- t + t2);
+ break;
+ }
+ }
+
+ mCurrentPosition = mStart + (int) Math.round(distance);
+
+ return true;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/launcher3/views/AbstractSlideInView.java b/src/com/android/launcher3/views/AbstractSlideInView.java
index c8d1457..59bea48 100644
--- a/src/com/android/launcher3/views/AbstractSlideInView.java
+++ b/src/com/android/launcher3/views/AbstractSlideInView.java
@@ -30,7 +30,6 @@
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherAnimUtils;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.touch.SwipeDetector;
@@ -76,7 +75,7 @@
mScrollInterpolator = Interpolators.SCROLL_CUBIC;
mSwipeDetector = new SwipeDetector(context, this, SwipeDetector.VERTICAL);
- mOpenCloseAnimator = LauncherAnimUtils.ofPropertyValuesHolder(this);
+ mOpenCloseAnimator = ObjectAnimator.ofPropertyValuesHolder(this);
mOpenCloseAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
@@ -103,7 +102,7 @@
directionsToDetectScroll, false);
mSwipeDetector.onTouchEvent(ev);
return mSwipeDetector.isDraggingOrSettling()
- || !mLauncher.getDragLayer().isEventOverView(mContent, ev);
+ || !getPopupContainer().isEventOverView(mContent, ev);
}
@Override
@@ -111,7 +110,7 @@
mSwipeDetector.onTouchEvent(ev);
if (ev.getAction() == MotionEvent.ACTION_UP && mSwipeDetector.isIdleState()) {
// If we got ACTION_UP without ever starting swipe, close the panel.
- if (!mLauncher.getDragLayer().isEventOverView(mContent, ev)) {
+ if (!getPopupContainer().isEventOverView(mContent, ev)) {
close(true);
}
}
@@ -178,6 +177,10 @@
protected void onCloseComplete() {
mIsOpen = false;
- mLauncher.getDragLayer().removeView(this);
+ getPopupContainer().removeView(this);
+ }
+
+ protected BaseDragLayer getPopupContainer() {
+ return mLauncher.getDragLayer();
}
}
diff --git a/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java b/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java
index a11a8c5..64e166e 100644
--- a/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java
+++ b/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java
@@ -20,13 +20,14 @@
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
-import android.support.v4.graphics.ColorUtils;
import android.util.AttributeSet;
import android.widget.TextView;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.R;
+import androidx.core.graphics.ColorUtils;
+
/**
* Extension of {@link BubbleTextView} which draws two shadows on the text (ambient and key shadows}
*/
diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java
index 5046639..3e58ea6 100644
--- a/src/com/android/launcher3/views/OptionsPopupView.java
+++ b/src/com/android/launcher3/views/OptionsPopupView.java
@@ -43,6 +43,8 @@
import java.util.ArrayList;
import java.util.List;
+import androidx.annotation.VisibleForTesting;
+
/**
* Popup shown on long pressing an empty space in launcher
*/
@@ -133,6 +135,11 @@
popup.reorderAndShow(popup.getChildCount());
}
+ @VisibleForTesting
+ public static OptionsPopupView getOptionsPopup(Launcher launcher) {
+ return launcher.findViewById(R.id.deep_shortcuts_container);
+ }
+
public static void showDefaultOptions(Launcher launcher, float x, float y) {
float halfSize = launcher.getResources().getDimension(R.dimen.options_menu_thumb_size) / 2;
if (x < 0 || y < 0) {
diff --git a/src/com/android/launcher3/views/RecyclerViewFastScroller.java b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
index 05bab8b..f0d6de2 100644
--- a/src/com/android/launcher3/views/RecyclerViewFastScroller.java
+++ b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
@@ -24,7 +24,6 @@
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect;
-import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.util.Property;
import android.view.MotionEvent;
@@ -35,10 +34,11 @@
import com.android.launcher3.BaseRecyclerView;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.graphics.FastScrollThumbDrawable;
import com.android.launcher3.util.Themes;
+import androidx.recyclerview.widget.RecyclerView;
+
/**
* The track and scrollbar that shows when you scroll the list.
*/
@@ -224,8 +224,7 @@
}
if (isNearThumb(x, y)) {
mTouchOffsetY = mDownY - mThumbOffsetY;
- } else if (FeatureFlags.LAUNCHER3_DIRECT_SCROLL
- && mRv.supportsFastScrolling()
+ } else if (mRv.supportsFastScrolling()
&& isNearScrollBar(mDownX)) {
calcTouchOffsetAndPrepToFastScroll(mDownY, mLastY);
updateFastScrollSectionNameAndThumbOffset(mLastY, y);
diff --git a/src/com/android/launcher3/views/ScrimView.java b/src/com/android/launcher3/views/ScrimView.java
index 7066980..6fd84db 100644
--- a/src/com/android/launcher3/views/ScrimView.java
+++ b/src/com/android/launcher3/views/ScrimView.java
@@ -16,8 +16,6 @@
package com.android.launcher3.views;
import static android.content.Context.ACCESSIBILITY_SERVICE;
-import static android.support.v4.graphics.ColorUtils.compositeColors;
-import static android.support.v4.graphics.ColorUtils.setAlphaComponent;
import static android.view.MotionEvent.ACTION_DOWN;
import static com.android.launcher3.LauncherState.ALL_APPS;
@@ -25,6 +23,9 @@
import static com.android.launcher3.anim.Interpolators.ACCEL;
import static com.android.launcher3.anim.Interpolators.DEACCEL;
+import static androidx.core.graphics.ColorUtils.compositeColors;
+import static androidx.core.graphics.ColorUtils.setAlphaComponent;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.Keyframe;
@@ -38,12 +39,6 @@
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v4.view.ViewCompat;
-import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
-import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat;
-import android.support.v4.widget.ExploreByTouchHelper;
import android.util.AttributeSet;
import android.util.Property;
import android.view.KeyEvent;
@@ -68,6 +63,13 @@
import java.util.List;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.core.view.ViewCompat;
+import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
+import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat;
+import androidx.customview.widget.ExploreByTouchHelper;
+
/**
* Simple scrim which draws a flat color
*/
diff --git a/src/com/android/launcher3/views/SpringRelativeLayout.java b/src/com/android/launcher3/views/SpringRelativeLayout.java
index b0313ce..d0ec9d7 100644
--- a/src/com/android/launcher3/views/SpringRelativeLayout.java
+++ b/src/com/android/launcher3/views/SpringRelativeLayout.java
@@ -15,24 +15,25 @@
*/
package com.android.launcher3.views;
+import static androidx.dynamicanimation.animation.SpringForce.DAMPING_RATIO_MEDIUM_BOUNCY;
+import static androidx.dynamicanimation.animation.SpringForce.STIFFNESS_LOW;
+import static androidx.dynamicanimation.animation.SpringForce.STIFFNESS_MEDIUM;
+
import android.content.Context;
import android.graphics.Canvas;
-import android.support.animation.DynamicAnimation;
-import android.support.animation.FloatPropertyCompat;
-import android.support.animation.SpringAnimation;
-import android.support.animation.SpringForce;
-import android.support.annotation.NonNull;
-import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.RecyclerView.EdgeEffectFactory;
import android.util.AttributeSet;
import android.util.SparseBooleanArray;
import android.view.View;
import android.widget.EdgeEffect;
import android.widget.RelativeLayout;
-import static android.support.animation.SpringForce.DAMPING_RATIO_MEDIUM_BOUNCY;
-import static android.support.animation.SpringForce.STIFFNESS_LOW;
-import static android.support.animation.SpringForce.STIFFNESS_MEDIUM;
+import androidx.annotation.NonNull;
+import androidx.dynamicanimation.animation.DynamicAnimation;
+import androidx.dynamicanimation.animation.FloatPropertyCompat;
+import androidx.dynamicanimation.animation.SpringAnimation;
+import androidx.dynamicanimation.animation.SpringForce;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.recyclerview.widget.RecyclerView.EdgeEffectFactory;
public class SpringRelativeLayout extends RelativeLayout {
diff --git a/src/com/android/launcher3/widget/BaseWidgetSheet.java b/src/com/android/launcher3/widget/BaseWidgetSheet.java
index 10708d6..20c8876 100644
--- a/src/com/android/launcher3/widget/BaseWidgetSheet.java
+++ b/src/com/android/launcher3/widget/BaseWidgetSheet.java
@@ -71,7 +71,7 @@
}
@Override
- public final boolean onLongClick(View v) {
+ public boolean onLongClick(View v) {
if (!ItemLongClickListener.canStartDrag(mLauncher)) return false;
if (v instanceof WidgetCell) {
@@ -96,7 +96,7 @@
}
int[] loc = new int[2];
- mLauncher.getDragLayer().getLocationInDragLayer(image, loc);
+ getPopupContainer().getLocationInDragLayer(image, loc);
new PendingItemDragHelper(v).startDrag(
image.getBitmapBounds(), image.getBitmap().getWidth(), image.getWidth(),
@@ -119,13 +119,13 @@
}
protected void clearNavBarColor() {
- mLauncher.getSystemUiController().updateUiState(
+ getSystemUiController().updateUiState(
SystemUiController.UI_STATE_WIDGET_BOTTOM_SHEET, 0);
}
protected void setupNavBarColor() {
- boolean isSheetDark = Themes.getAttrBoolean(mLauncher, R.attr.isMainColorDark);
- mLauncher.getSystemUiController().updateUiState(
+ boolean isSheetDark = Themes.getAttrBoolean(getContext(), R.attr.isMainColorDark);
+ getSystemUiController().updateUiState(
SystemUiController.UI_STATE_WIDGET_BOTTOM_SHEET,
isSheetDark ? SystemUiController.FLAG_DARK_NAV : SystemUiController.FLAG_LIGHT_NAV);
}
@@ -145,4 +145,7 @@
protected abstract int getElementsRowCount();
+ protected SystemUiController getSystemUiController() {
+ return mLauncher.getSystemUiController();
+ }
}
diff --git a/src/com/android/launcher3/widget/WidgetsBottomSheet.java b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
index 5ce7e04..4ba6b5b 100644
--- a/src/com/android/launcher3/widget/WidgetsBottomSheet.java
+++ b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
@@ -71,7 +71,7 @@
onWidgetsBound();
- mLauncher.getDragLayer().addView(this);
+ getPopupContainer().addView(this);
mIsOpen = false;
animateOpen();
}
@@ -118,7 +118,7 @@
LayoutInflater.from(getContext()).inflate(R.layout.widget_list_divider, parent, true);
}
- private WidgetCell addItemCell(ViewGroup parent) {
+ protected WidgetCell addItemCell(ViewGroup parent) {
WidgetCell widget = (WidgetCell) LayoutInflater.from(getContext()).inflate(
R.layout.widget_cell, parent, false);
diff --git a/src/com/android/launcher3/widget/WidgetsDiffReporter.java b/src/com/android/launcher3/widget/WidgetsDiffReporter.java
index d67f403..2ba672d 100644
--- a/src/com/android/launcher3/widget/WidgetsDiffReporter.java
+++ b/src/com/android/launcher3/widget/WidgetsDiffReporter.java
@@ -16,7 +16,6 @@
package com.android.launcher3.widget;
-import android.support.v7.widget.RecyclerView;
import android.util.Log;
import com.android.launcher3.IconCache;
@@ -26,6 +25,8 @@
import java.util.ArrayList;
import java.util.Iterator;
+import androidx.recyclerview.widget.RecyclerView;
+
/**
* Do diff on widget's tray list items and call the {@link RecyclerView.Adapter}
* methods accordingly.
diff --git a/src/com/android/launcher3/widget/WidgetsFullSheet.java b/src/com/android/launcher3/widget/WidgetsFullSheet.java
index e94d81d..f7ff69a 100644
--- a/src/com/android/launcher3/widget/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/WidgetsFullSheet.java
@@ -35,6 +35,8 @@
import com.android.launcher3.views.RecyclerViewFastScroller;
import com.android.launcher3.views.TopRoundedCornerView;
+import androidx.annotation.VisibleForTesting;
+
/**
* Popup for showing the full list of available widgets
*/
@@ -159,7 +161,7 @@
private void open(boolean animate) {
if (animate) {
- if (mLauncher.getDragLayer().getInsets().bottom > 0) {
+ if (getPopupContainer().getInsets().bottom > 0) {
mContent.setAlpha(0);
setTranslationShift(VERTICAL_START_POSITION);
}
@@ -206,10 +208,10 @@
mNoIntercept = false;
RecyclerViewFastScroller scroller = mRecyclerView.getScrollbar();
if (scroller.getThumbOffsetY() >= 0 &&
- mLauncher.getDragLayer().isEventOverView(scroller, ev)) {
+ getPopupContainer().isEventOverView(scroller, ev)) {
mNoIntercept = true;
- } else if (mLauncher.getDragLayer().isEventOverView(mContent, ev)) {
- mNoIntercept = !mRecyclerView.shouldContainerScroll(ev, mLauncher.getDragLayer());
+ } else if (getPopupContainer().isEventOverView(mContent, ev)) {
+ mNoIntercept = !mRecyclerView.shouldContainerScroll(ev, getPopupContainer());
}
}
return super.onControllerInterceptTouchEvent(ev);
@@ -219,11 +221,16 @@
WidgetsFullSheet sheet = (WidgetsFullSheet) launcher.getLayoutInflater()
.inflate(R.layout.widgets_full_sheet, launcher.getDragLayer(), false);
sheet.mIsOpen = true;
- launcher.getDragLayer().addView(sheet);
+ sheet.getPopupContainer().addView(sheet);
sheet.open(animate);
return sheet;
}
+ @VisibleForTesting
+ public static WidgetsRecyclerView getWidgetsView(Launcher launcher) {
+ return launcher.findViewById(R.id.widgets_list_view);
+ }
+
@Override
protected int getElementsRowCount() {
return mAdapter.getItemCount();
diff --git a/src/com/android/launcher3/widget/WidgetsListAdapter.java b/src/com/android/launcher3/widget/WidgetsListAdapter.java
index 0147ea4..1016d04 100644
--- a/src/com/android/launcher3/widget/WidgetsListAdapter.java
+++ b/src/com/android/launcher3/widget/WidgetsListAdapter.java
@@ -16,8 +16,6 @@
package com.android.launcher3.widget;
import android.content.Context;
-import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.RecyclerView.Adapter;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
@@ -30,14 +28,15 @@
import com.android.launcher3.WidgetPreviewLoader;
import com.android.launcher3.model.WidgetItem;
import com.android.launcher3.util.LabelComparator;
-import com.android.launcher3.util.PackageUserKey;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
-import java.util.Iterator;
import java.util.List;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.recyclerview.widget.RecyclerView.Adapter;
+
/**
* List view adapter for the widget tray.
*
diff --git a/src/com/android/launcher3/widget/WidgetsRecyclerView.java b/src/com/android/launcher3/widget/WidgetsRecyclerView.java
index 124058e..641183a 100644
--- a/src/com/android/launcher3/widget/WidgetsRecyclerView.java
+++ b/src/com/android/launcher3/widget/WidgetsRecyclerView.java
@@ -18,9 +18,6 @@
import android.content.Context;
import android.graphics.Point;
-import android.support.v7.widget.LinearLayoutManager;
-import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.RecyclerView.OnItemTouchListener;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
@@ -28,6 +25,10 @@
import com.android.launcher3.BaseRecyclerView;
import com.android.launcher3.R;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.recyclerview.widget.RecyclerView.OnItemTouchListener;
+
/**
* The widgets recycler view.
*/
diff --git a/src/com/android/launcher3/widget/WidgetsRowViewHolder.java b/src/com/android/launcher3/widget/WidgetsRowViewHolder.java
index 8f269a6..d26edb6 100644
--- a/src/com/android/launcher3/widget/WidgetsRowViewHolder.java
+++ b/src/com/android/launcher3/widget/WidgetsRowViewHolder.java
@@ -15,12 +15,13 @@
*/
package com.android.launcher3.widget;
-import android.support.v7.widget.RecyclerView.ViewHolder;
import android.view.ViewGroup;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.R;
+import androidx.recyclerview.widget.RecyclerView.ViewHolder;
+
public class WidgetsRowViewHolder extends ViewHolder {
public final ViewGroup cellContainer;
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java b/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java
index 5a7e50f..0d727fd 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java
@@ -48,6 +48,8 @@
public static void onStart(Launcher launcher) { }
+ public static void onEnterAnimationComplete(Context context) {}
+
public static void onLauncherStateOrResumeChanged(Launcher launcher) { }
public static void onTrimMemory(Launcher launcher, int level) { }
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/ColorExtractionAlgorithm.java b/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/ColorExtractionAlgorithm.java
index 21b324f..5a1f9ca 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/ColorExtractionAlgorithm.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/ColorExtractionAlgorithm.java
@@ -17,9 +17,6 @@
package com.android.launcher3.uioverrides.dynamicui;
import android.graphics.Color;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v4.graphics.ColorUtils;
import android.util.Log;
import android.util.Pair;
import android.util.Range;
@@ -30,6 +27,10 @@
import java.util.LinkedList;
import java.util.List;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.core.graphics.ColorUtils;
+
/**
* Implementation of tonal color extraction
**/
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/WallpaperManagerCompat.java b/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/WallpaperManagerCompat.java
index 5c533ff..0fd0a35 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/WallpaperManagerCompat.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/WallpaperManagerCompat.java
@@ -17,10 +17,11 @@
package com.android.launcher3.uioverrides.dynamicui;
import android.content.Context;
-import android.support.annotation.Nullable;
import com.android.launcher3.Utilities;
+import androidx.annotation.Nullable;
+
public abstract class WallpaperManagerCompat {
private static final Object sInstanceLock = new Object();
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/WallpaperManagerCompatVL.java b/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/WallpaperManagerCompatVL.java
index 4a8bbbd..7883442 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/WallpaperManagerCompatVL.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/WallpaperManagerCompatVL.java
@@ -18,7 +18,6 @@
import static android.app.WallpaperManager.FLAG_SYSTEM;
import static com.android.launcher3.Utilities.getDevicePrefs;
-import static com.android.launcher3.graphics.ColorExtractor.findDominantColorByHue;
import android.app.WallpaperInfo;
import android.app.WallpaperManager;
@@ -42,15 +41,17 @@
import android.os.Handler;
import android.os.HandlerThread;
import android.os.ParcelFileDescriptor;
-import android.support.annotation.Nullable;
import android.util.Log;
import android.util.Pair;
import com.android.launcher3.Utilities;
+import com.android.launcher3.graphics.ColorExtractor;
import java.io.IOException;
import java.util.ArrayList;
+import androidx.annotation.Nullable;
+
public class WallpaperManagerCompatVL extends WallpaperManagerCompat {
private static final String TAG = "WMCompatVL";
@@ -169,6 +170,7 @@
private HandlerThread mWorkerThread;
private Handler mWorkerHandler;
+ private ColorExtractor mColorExtractor;
@Override
public void onCreate() {
@@ -176,6 +178,7 @@
mWorkerThread = new HandlerThread("ColorExtractionService");
mWorkerThread.start();
mWorkerHandler = new Handler(mWorkerThread.getLooper());
+ mColorExtractor = new ColorExtractor();
}
@Override
@@ -258,7 +261,8 @@
String value = VERSION_PREFIX + wallpaperId;
if (bitmap != null) {
- int color = findDominantColorByHue(bitmap, MAX_WALLPAPER_EXTRACTION_AREA);
+ int color = mColorExtractor.findDominantColorByHue(bitmap,
+ MAX_WALLPAPER_EXTRACTION_AREA);
value += "," + color;
}
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/WallpaperManagerCompatVOMR1.java b/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/WallpaperManagerCompatVOMR1.java
index 4509e05..f34497d 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/WallpaperManagerCompatVOMR1.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/WallpaperManagerCompatVOMR1.java
@@ -21,11 +21,12 @@
import android.app.WallpaperManager.OnColorsChangedListener;
import android.content.Context;
import android.graphics.Color;
-import android.support.annotation.Nullable;
import android.util.Log;
import java.lang.reflect.Method;
+import androidx.annotation.Nullable;
+
@TargetApi(27)
public class WallpaperManagerCompatVOMR1 extends WallpaperManagerCompat {
diff --git a/tests/Android.mk b/tests/Android.mk
index f6f02fe..03cb154 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -17,7 +17,11 @@
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := tests
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test ub-uiautomator mockito-target-minus-junit4
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ android-support-test \
+ ub-uiautomator \
+ mockito-target-minus-junit4 \
+ ub-launcher-aosp-tapl
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_FULL_LIBS_MANIFEST_FILES := $(LOCAL_PATH)/AndroidManifest-common.xml
@@ -30,3 +34,22 @@
LOCAL_INSTRUMENTATION_FOR := Launcher3
include $(BUILD_PACKAGE)
+
+#
+# Build rule for Tapl library.
+#
+include $(CLEAR_VARS)
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ androidx.annotation_annotation \
+ android-support-test \
+ ub-uiautomator \
+ libSharedSystemUI
+
+LOCAL_SRC_FILES := $(call all-java-files-under, tapl) \
+ ../quickstep/src/com/android/quickstep/SwipeUpSetting.java \
+ ../src/com/android/launcher3/TestProtocol.java
+
+LOCAL_SDK_VERSION := current
+LOCAL_MODULE := ub-launcher-aosp-tapl
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/tests/AndroidManifest-common.xml b/tests/AndroidManifest-common.xml
index af8b15c..89ca7f3 100644
--- a/tests/AndroidManifest-common.xml
+++ b/tests/AndroidManifest-common.xml
@@ -31,7 +31,6 @@
android:resource="@xml/appwidget_no_config" />
</receiver>
-
<receiver
android:name="com.android.launcher3.testcomponent.AppWdigetHidden"
android:label="Hidden widget">
diff --git a/tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java b/tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java
index b217847..5d5af4f 100644
--- a/tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java
+++ b/tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java
@@ -18,7 +18,6 @@
import android.graphics.Color;
import android.os.Process;
import android.os.UserHandle;
-import android.support.annotation.NonNull;
import android.support.test.InstrumentationRegistry;
import android.support.test.rule.provider.ProviderTestRule;
@@ -49,6 +48,8 @@
import java.util.List;
import java.util.concurrent.Executor;
+import androidx.annotation.NonNull;
+
/**
* Base class for writing tests for Model update tasks.
*/
diff --git a/tests/src/com/android/launcher3/model/GridSizeMigrationTaskTest.java b/tests/src/com/android/launcher3/model/GridSizeMigrationTaskTest.java
index b92f612..031909f 100644
--- a/tests/src/com/android/launcher3/model/GridSizeMigrationTaskTest.java
+++ b/tests/src/com/android/launcher3/model/GridSizeMigrationTaskTest.java
@@ -16,7 +16,6 @@
import com.android.launcher3.LauncherModel;
import com.android.launcher3.LauncherProvider;
import com.android.launcher3.LauncherSettings;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.GridSizeMigrationTask.MultiStepMigrationTask;
import com.android.launcher3.util.TestLauncherProvider;
@@ -87,13 +86,8 @@
mIdp.numHotseatIcons = 3;
new GridSizeMigrationTask(mContext, mIdp, mValidPackages, 5, 3)
.migrateHotseat();
- if (FeatureFlags.NO_ALL_APPS_ICON) {
- // First item is dropped as it has the least weight.
- verifyHotseat(hotseatItems[1], hotseatItems[3], hotseatItems[4]);
- } else {
- // First & last items are dropped as they have the least weight.
- verifyHotseat(hotseatItems[1], -1, hotseatItems[3]);
- }
+ // First item is dropped as it has the least weight.
+ verifyHotseat(hotseatItems[1], hotseatItems[3], hotseatItems[4]);
}
@Test
@@ -109,13 +103,8 @@
mIdp.numHotseatIcons = 3;
new GridSizeMigrationTask(mContext, mIdp, mValidPackages, 5, 3)
.migrateHotseat();
- if (FeatureFlags.NO_ALL_APPS_ICON) {
- // First item is dropped as it has the least weight.
- verifyHotseat(hotseatItems[1], hotseatItems[3], hotseatItems[4]);
- } else {
- // First & third items are dropped as they have the least weight.
- verifyHotseat(hotseatItems[1], -1, hotseatItems[4]);
- }
+ // First item is dropped as it has the least weight.
+ verifyHotseat(hotseatItems[1], hotseatItems[3], hotseatItems[4]);
}
private void verifyHotseat(long... sortedIds) {
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index f16f514..46a6446 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -15,6 +15,9 @@
*/
package com.android.launcher3.ui;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
import android.app.Instrumentation;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -36,26 +39,30 @@
import android.util.Log;
import android.view.MotionEvent;
+import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.LauncherSettings;
+import com.android.launcher3.LauncherState;
import com.android.launcher3.MainThreadExecutor;
import com.android.launcher3.R;
import com.android.launcher3.compat.AppWidgetManagerCompat;
import com.android.launcher3.compat.LauncherAppsCompat;
-import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.tapl.LauncherInstrumentation;
import com.android.launcher3.testcomponent.AppWidgetNoConfig;
import com.android.launcher3.testcomponent.AppWidgetWithConfig;
+import com.android.launcher3.util.Condition;
+import com.android.launcher3.util.Wait;
+import com.android.launcher3.util.rule.LauncherActivityRule;
import org.junit.Before;
+import org.junit.Rule;
-import java.util.Locale;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
-
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
+import java.util.function.Consumer;
+import java.util.function.Function;
/**
* Base class for all instrumentation tests providing various utility methods.
@@ -67,19 +74,23 @@
public static final long SHORT_UI_TIMEOUT= 300;
public static final long DEFAULT_UI_TIMEOUT = 3000;
- public static final long LARGE_UI_TIMEOUT = 10000;
public static final long DEFAULT_WORKER_TIMEOUT_SECS = 5;
protected MainThreadExecutor mMainThreadExecutor = new MainThreadExecutor();
protected UiDevice mDevice;
+ protected LauncherInstrumentation mLauncher;
protected Context mTargetContext;
protected String mTargetPackage;
private static final String TAG = "AbstractLauncherUiTest";
+ @Rule
+ public LauncherActivityRule mActivityMonitor = new LauncherActivityRule();
+
@Before
public void setUp() throws Exception {
mDevice = UiDevice.getInstance(getInstrumentation());
+ mLauncher = new LauncherInstrumentation(mDevice);
mTargetContext = InstrumentationRegistry.getTargetContext();
mTargetPackage = mTargetContext.getPackageName();
}
@@ -101,19 +112,12 @@
*/
protected UiObject2 openAllApps() {
mDevice.waitForIdle();
- if (FeatureFlags.NO_ALL_APPS_ICON) {
- UiObject2 hotseat = mDevice.wait(
- Until.findObject(getSelectorForId(R.id.hotseat)), 2500);
- Point start = hotseat.getVisibleCenter();
- int endY = (int) (mDevice.getDisplayHeight() * 0.1f);
- // 100 px/step
- mDevice.swipe(start.x, start.y, start.x, endY, (start.y - endY) / 100);
-
- } else {
- mDevice.wait(Until.findObject(
- By.desc(mTargetContext.getString(R.string.all_apps_button_label))),
- DEFAULT_UI_TIMEOUT).click();
- }
+ UiObject2 hotseat = mDevice.wait(
+ Until.findObject(getSelectorForId(R.id.hotseat)), 2500);
+ Point start = hotseat.getVisibleCenter();
+ int endY = (int) (mDevice.getDisplayHeight() * 0.1f);
+ // 100 px/step
+ mDevice.swipe(start.x, start.y, start.x, endY, (start.y - endY) / 100);
return findViewById(R.id.apps_list_view);
}
@@ -245,6 +249,33 @@
}
}
+ protected <T> T getFromLauncher(Function<Launcher, T> f) {
+ return getOnUiThread(() -> f.apply(mActivityMonitor.getActivity()));
+ }
+
+ protected void executeOnLauncher(Consumer<Launcher> f) {
+ getFromLauncher(launcher -> {
+ f.accept(launcher);
+ return null;
+ });
+ }
+
+ // Cannot be used between a Tapl call injecting a gesture and a tapl call expecting the
+ // results of that gesture because the wait can hide flakeness.
+ protected boolean waitForState(LauncherState state) {
+ return waitForLauncherCondition(launcher -> launcher.getStateManager().getState() == state);
+ }
+
+ // Cannot be used after injecting any gesture using Tapl because this can hide flakiness.
+ protected boolean waitForLauncherCondition(Function<Launcher, Boolean> condition) {
+ return Wait.atMost(new Condition() {
+ @Override
+ public boolean isTrue() {
+ return getFromLauncher(condition);
+ }
+ }, DEFAULT_ACTIVITY_TIMEOUT);
+ }
+
/**
* Finds a widget provider which can fit on the home screen.
* @param hasConfigureScreen if true, a provider with a config screen is returned.
diff --git a/tests/src/com/android/launcher3/ui/AllAppsAppLaunchTest.java b/tests/src/com/android/launcher3/ui/AllAppsAppLaunchTest.java
deleted file mode 100644
index b95a850..0000000
--- a/tests/src/com/android/launcher3/ui/AllAppsAppLaunchTest.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package com.android.launcher3.ui;
-
-import android.content.pm.LauncherActivityInfo;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.test.uiautomator.By;
-import android.support.test.uiautomator.UiObject2;
-import android.support.test.uiautomator.Until;
-
-import com.android.launcher3.util.Condition;
-import com.android.launcher3.util.Wait;
-import com.android.launcher3.util.rule.LauncherActivityRule;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import static org.junit.Assert.assertTrue;
-
-/**
- * Test for verifying apps is launched from all-apps
- */
-@LargeTest
-@RunWith(AndroidJUnit4.class)
-public class AllAppsAppLaunchTest extends AbstractLauncherUiTest {
-
- @Rule public LauncherActivityRule mActivityMonitor = new LauncherActivityRule();
-
- @Test
- public void testAppLauncher_portrait() throws Exception {
- lockRotation(true);
- performTest();
- }
-
- @Test
- public void testAppLauncher_landscape() throws Exception {
- lockRotation(false);
- performTest();
- }
-
- private void performTest() throws Exception {
- mActivityMonitor.startLauncher();
-
- LauncherActivityInfo testApp = getChromeApp();
-
- // Open all apps and wait for load complete
- final UiObject2 appsContainer = openAllApps();
- assertTrue(Wait.atMost(Condition.minChildCount(appsContainer, 2), DEFAULT_UI_TIMEOUT));
-
- // Open app and verify app launched
- scrollAndFind(appsContainer, By.text(testApp.getLabel().toString())).click();
- assertTrue(mDevice.wait(Until.hasObject(By.pkg(
- testApp.getComponentName().getPackageName()).depth(0)), DEFAULT_UI_TIMEOUT));
- }
-}
diff --git a/tests/src/com/android/launcher3/ui/AllAppsIconToHomeTest.java b/tests/src/com/android/launcher3/ui/AllAppsIconToHomeTest.java
index 00f30ad..8b9c584 100644
--- a/tests/src/com/android/launcher3/ui/AllAppsIconToHomeTest.java
+++ b/tests/src/com/android/launcher3/ui/AllAppsIconToHomeTest.java
@@ -1,5 +1,7 @@
package com.android.launcher3.ui;
+import static org.junit.Assert.assertTrue;
+
import android.content.pm.LauncherActivityInfo;
import android.support.test.filters.LargeTest;
import android.support.test.runner.AndroidJUnit4;
@@ -9,15 +11,12 @@
import com.android.launcher3.util.Condition;
import com.android.launcher3.util.Wait;
-import com.android.launcher3.util.rule.LauncherActivityRule;
import com.android.launcher3.util.rule.ShellCommandRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import static org.junit.Assert.assertTrue;
-
/**
* Test for dragging an icon from all-apps to homescreen.
*/
@@ -25,7 +24,6 @@
@RunWith(AndroidJUnit4.class)
public class AllAppsIconToHomeTest extends AbstractLauncherUiTest {
- @Rule public LauncherActivityRule mActivityMonitor = new LauncherActivityRule();
@Rule public ShellCommandRule mDefaultLauncherRule = ShellCommandRule.setDefaultLauncher();
@Test
diff --git a/tests/src/com/android/launcher3/ui/ShortcutsLaunchTest.java b/tests/src/com/android/launcher3/ui/ShortcutsLaunchTest.java
index 69f6c87..f913470 100644
--- a/tests/src/com/android/launcher3/ui/ShortcutsLaunchTest.java
+++ b/tests/src/com/android/launcher3/ui/ShortcutsLaunchTest.java
@@ -1,5 +1,8 @@
package com.android.launcher3.ui;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
import android.content.pm.LauncherActivityInfo;
import android.graphics.Point;
import android.support.test.filters.LargeTest;
@@ -12,16 +15,12 @@
import com.android.launcher3.R;
import com.android.launcher3.util.Condition;
import com.android.launcher3.util.Wait;
-import com.android.launcher3.util.rule.LauncherActivityRule;
import com.android.launcher3.util.rule.ShellCommandRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
/**
* Test for verifying that shortcuts are shown and can be launched after long pressing an app
*/
@@ -29,7 +28,6 @@
@RunWith(AndroidJUnit4.class)
public class ShortcutsLaunchTest extends AbstractLauncherUiTest {
- @Rule public LauncherActivityRule mActivityMonitor = new LauncherActivityRule();
@Rule public ShellCommandRule mDefaultLauncherRule = ShellCommandRule.setDefaultLauncher();
@Test
diff --git a/tests/src/com/android/launcher3/ui/ShortcutsToHomeTest.java b/tests/src/com/android/launcher3/ui/ShortcutsToHomeTest.java
index fad06a6..4f5c113 100644
--- a/tests/src/com/android/launcher3/ui/ShortcutsToHomeTest.java
+++ b/tests/src/com/android/launcher3/ui/ShortcutsToHomeTest.java
@@ -1,5 +1,8 @@
package com.android.launcher3.ui;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
import android.content.pm.LauncherActivityInfo;
import android.graphics.Point;
import android.support.test.filters.LargeTest;
@@ -12,16 +15,12 @@
import com.android.launcher3.R;
import com.android.launcher3.util.Condition;
import com.android.launcher3.util.Wait;
-import com.android.launcher3.util.rule.LauncherActivityRule;
import com.android.launcher3.util.rule.ShellCommandRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
/**
* Test for dragging a deep shortcut to the home screen.
*/
@@ -29,7 +28,6 @@
@RunWith(AndroidJUnit4.class)
public class ShortcutsToHomeTest extends AbstractLauncherUiTest {
- @Rule public LauncherActivityRule mActivityMonitor = new LauncherActivityRule();
@Rule public ShellCommandRule mDefaultLauncherRule = ShellCommandRule.setDefaultLauncher();
@Test
diff --git a/tests/src/com/android/launcher3/ui/WorkTabTest.java b/tests/src/com/android/launcher3/ui/WorkTabTest.java
index 6244434..2f867f3 100644
--- a/tests/src/com/android/launcher3/ui/WorkTabTest.java
+++ b/tests/src/com/android/launcher3/ui/WorkTabTest.java
@@ -15,15 +15,13 @@
*/
package com.android.launcher3.ui;
+import static com.android.launcher3.LauncherState.ALL_APPS;
+
+import static org.junit.Assert.assertTrue;
+
import android.support.test.filters.LargeTest;
import android.support.test.runner.AndroidJUnit4;
-import android.support.test.uiautomator.UiObject2;
-import android.support.test.uiautomator.Until;
-import com.android.launcher3.R;
-import com.android.launcher3.util.Condition;
-import com.android.launcher3.util.Wait;
-import com.android.launcher3.util.rule.LauncherActivityRule;
import com.android.launcher3.util.rule.ShellCommandRule;
import org.junit.After;
@@ -32,14 +30,10 @@
import org.junit.Test;
import org.junit.runner.RunWith;
-import static org.junit.Assert.assertTrue;
-
@LargeTest
@RunWith(AndroidJUnit4.class)
public class WorkTabTest extends AbstractLauncherUiTest {
@Rule
- public LauncherActivityRule mActivityMonitor = new LauncherActivityRule();
- @Rule
public ShellCommandRule mDefaultLauncherRule = ShellCommandRule.setDefaultLauncher();
private int mProfileUserId;
@@ -66,17 +60,13 @@
public void workTabExists() {
mActivityMonitor.startLauncher();
- // Open all apps and wait for load complete
- final UiObject2 appsContainer = openAllApps();
- assertTrue(Wait.atMost(Condition.minChildCount(appsContainer, 2),
- LARGE_UI_TIMEOUT));
+ executeOnLauncher(launcher -> launcher.getStateManager().goToState(ALL_APPS));
/*
- assertTrue("Personal tab is missing",
- mDevice.wait(Until.hasObject(getSelectorForId(R.id.tab_personal)),
- LARGE_UI_TIMEOUT));
- assertTrue("Work tab is missing",
- mDevice.wait(Until.hasObject(getSelectorForId(R.id.tab_work)), LARGE_UI_TIMEOUT));
+ assertTrue("Personal tab is missing", waitForLauncherCondition(
+ launcher -> launcher.getAppsView().isPersonalTabVisible()));
+ assertTrue("Work tab is missing", waitForLauncherCondition(
+ launcher -> launcher.getAppsView().isWorkTabVisible()));
*/
}
}
\ No newline at end of file
diff --git a/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
index a5c2e69..7f6dd44 100644
--- a/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
@@ -15,6 +15,11 @@
*/
package com.android.launcher3.ui.widget;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertTrue;
+
import android.appwidget.AppWidgetManager;
import android.content.Intent;
import android.support.test.filters.LargeTest;
@@ -31,7 +36,6 @@
import com.android.launcher3.ui.AbstractLauncherUiTest;
import com.android.launcher3.util.Condition;
import com.android.launcher3.util.Wait;
-import com.android.launcher3.util.rule.LauncherActivityRule;
import com.android.launcher3.util.rule.ShellCommandRule;
import com.android.launcher3.widget.WidgetCell;
@@ -40,11 +44,6 @@
import org.junit.Test;
import org.junit.runner.RunWith;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNotSame;
-import static org.junit.Assert.assertTrue;
-
/**
* Test to verify widget configuration is properly shown.
*/
@@ -52,7 +51,6 @@
@RunWith(AndroidJUnit4.class)
public class AddConfigWidgetTest extends AbstractLauncherUiTest {
- @Rule public LauncherActivityRule mActivityMonitor = new LauncherActivityRule();
@Rule public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grandWidgetBind();
private LauncherAppWidgetProviderInfo mWidgetInfo;
@@ -126,12 +124,8 @@
assertNotNull(mAppWidgetManager.getAppWidgetInfo(mWidgetId));
} else {
// Verify that the widget id is deleted.
- assertTrue(Wait.atMost(new Condition() {
- @Override
- public boolean isTrue() throws Throwable {
- return mAppWidgetManager.getAppWidgetInfo(mWidgetId) == null;
- }
- }, DEFAULT_ACTIVITY_TIMEOUT));
+ assertTrue(Wait.atMost(() -> mAppWidgetManager.getAppWidgetInfo(mWidgetId) == null,
+ DEFAULT_ACTIVITY_TIMEOUT));
}
}
@@ -145,8 +139,7 @@
/**
* Condition for searching widget id
*/
- private class WidgetSearchCondition extends Condition
- implements Workspace.ItemOperator {
+ private class WidgetSearchCondition implements Condition, Workspace.ItemOperator {
@Override
public boolean isTrue() throws Throwable {
diff --git a/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java
index 19f7db7..d89f26e 100644
--- a/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java
@@ -15,6 +15,8 @@
*/
package com.android.launcher3.ui.widget;
+import static org.junit.Assert.assertTrue;
+
import android.support.test.filters.LargeTest;
import android.support.test.runner.AndroidJUnit4;
import android.support.test.uiautomator.By;
@@ -28,7 +30,6 @@
import com.android.launcher3.ui.AbstractLauncherUiTest;
import com.android.launcher3.util.Condition;
import com.android.launcher3.util.Wait;
-import com.android.launcher3.util.rule.LauncherActivityRule;
import com.android.launcher3.util.rule.ShellCommandRule;
import com.android.launcher3.widget.WidgetCell;
@@ -36,8 +37,6 @@
import org.junit.Test;
import org.junit.runner.RunWith;
-import static org.junit.Assert.assertTrue;
-
/**
* Test to add widget from widget tray
*/
@@ -45,7 +44,6 @@
@RunWith(AndroidJUnit4.class)
public class AddWidgetTest extends AbstractLauncherUiTest {
- @Rule public LauncherActivityRule mActivityMonitor = new LauncherActivityRule();
@Rule public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grandWidgetBind();
@Test
diff --git a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
index b557119..c8c3896 100644
--- a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
@@ -15,6 +15,11 @@
*/
package com.android.launcher3.ui.widget;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
import android.appwidget.AppWidgetHost;
import android.appwidget.AppWidgetManager;
import android.content.ComponentName;
@@ -30,21 +35,20 @@
import android.support.test.uiautomator.UiSelector;
import com.android.launcher3.LauncherAppWidgetHost;
-import com.android.launcher3.widget.LauncherAppWidgetHostView;
import com.android.launcher3.LauncherAppWidgetInfo;
import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.LauncherModel;
import com.android.launcher3.LauncherSettings;
-import com.android.launcher3.widget.PendingAppWidgetHostView;
import com.android.launcher3.Workspace;
import com.android.launcher3.compat.AppWidgetManagerCompat;
import com.android.launcher3.compat.PackageInstallerCompat;
import com.android.launcher3.ui.AbstractLauncherUiTest;
import com.android.launcher3.util.ContentWriter;
import com.android.launcher3.util.LooperExecutor;
-import com.android.launcher3.util.rule.LauncherActivityRule;
import com.android.launcher3.util.rule.ShellCommandRule;
+import com.android.launcher3.widget.LauncherAppWidgetHostView;
import com.android.launcher3.widget.PendingAddWidgetInfo;
+import com.android.launcher3.widget.PendingAppWidgetHostView;
import com.android.launcher3.widget.WidgetHostViewLoader;
import org.junit.After;
@@ -58,11 +62,6 @@
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
/**
* Tests for bind widget flow.
*
@@ -72,7 +71,6 @@
@RunWith(AndroidJUnit4.class)
public class BindWidgetTest extends AbstractLauncherUiTest {
- @Rule public LauncherActivityRule mActivityMonitor = new LauncherActivityRule();
@Rule public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grandWidgetBind();
private ContentResolver mResolver;
diff --git a/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java b/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
index dcb564a..ec0a051 100644
--- a/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
@@ -15,6 +15,10 @@
*/
package com.android.launcher3.ui.widget;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertTrue;
+
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.content.Intent;
@@ -40,7 +44,6 @@
import com.android.launcher3.ui.AbstractLauncherUiTest;
import com.android.launcher3.util.Condition;
import com.android.launcher3.util.Wait;
-import com.android.launcher3.util.rule.LauncherActivityRule;
import com.android.launcher3.util.rule.ShellCommandRule;
import com.android.launcher3.widget.WidgetCell;
@@ -52,10 +55,6 @@
import java.util.UUID;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNotSame;
-import static org.junit.Assert.assertTrue;
-
/**
* Test to verify pin item request flow.
*/
@@ -63,7 +62,6 @@
@RunWith(AndroidJUnit4.class)
public class RequestPinItemTest extends AbstractLauncherUiTest {
- @Rule public LauncherActivityRule mActivityMonitor = new LauncherActivityRule();
@Rule public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grandWidgetBind();
@Rule public ShellCommandRule mDefaultLauncherRule = ShellCommandRule.setDefaultLauncher();
@@ -200,7 +198,7 @@
/**
* Condition for for an item
*/
- private class ItemSearchCondition extends Condition {
+ private class ItemSearchCondition implements Condition {
private final ItemOperator mOp;
diff --git a/tests/src/com/android/launcher3/util/Condition.java b/tests/src/com/android/launcher3/util/Condition.java
index e9ee67c..78c652a 100644
--- a/tests/src/com/android/launcher3/util/Condition.java
+++ b/tests/src/com/android/launcher3/util/Condition.java
@@ -8,47 +8,36 @@
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
-public abstract class Condition {
+public interface Condition {
- public abstract boolean isTrue() throws Throwable;
+ boolean isTrue() throws Throwable;
/**
* Converts the condition to be run on UI thread.
*/
- public static Condition runOnUiThread(final Condition condition) {
+ static Condition runOnUiThread(final Condition condition) {
final MainThreadExecutor executor = new MainThreadExecutor();
- return new Condition() {
- @Override
- public boolean isTrue() throws Throwable {
- final AtomicBoolean value = new AtomicBoolean(false);
- final Throwable[] exceptions = new Throwable[1];
- final CountDownLatch latch = new CountDownLatch(1);
- executor.execute(new Runnable() {
- @Override
- public void run() {
- try {
- value.set(condition.isTrue());
- } catch (Throwable e) {
- exceptions[0] = e;
- }
-
- }
- });
- latch.await(1, TimeUnit.SECONDS);
- if (exceptions[0] != null) {
- throw exceptions[0];
+ return () -> {
+ final AtomicBoolean value = new AtomicBoolean(false);
+ final Throwable[] exceptions = new Throwable[1];
+ final CountDownLatch latch = new CountDownLatch(1);
+ executor.execute(() -> {
+ try {
+ value.set(condition.isTrue());
+ } catch (Throwable e) {
+ exceptions[0] = e;
}
- return value.get();
+
+ });
+ latch.await(1, TimeUnit.SECONDS);
+ if (exceptions[0] != null) {
+ throw exceptions[0];
}
+ return value.get();
};
}
- public static Condition minChildCount(final UiObject2 obj, final int childCount) {
- return new Condition() {
- @Override
- public boolean isTrue() {
- return obj.getChildCount() >= childCount;
- }
- };
+ static Condition minChildCount(final UiObject2 obj, final int childCount) {
+ return () -> obj.getChildCount() >= childCount;
}
}
diff --git a/tests/src/com/android/launcher3/widget/WidgetsListAdapterTest.java b/tests/src/com/android/launcher3/widget/WidgetsListAdapterTest.java
index 0185f13..5befeb9 100644
--- a/tests/src/com/android/launcher3/widget/WidgetsListAdapterTest.java
+++ b/tests/src/com/android/launcher3/widget/WidgetsListAdapterTest.java
@@ -15,6 +15,11 @@
*/
package com.android.launcher3.widget;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.isNull;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
import android.appwidget.AppWidgetProviderInfo;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -22,7 +27,6 @@
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
-import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import com.android.launcher3.IconCache;
@@ -43,10 +47,7 @@
import java.util.ArrayList;
import java.util.Map;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Matchers.isNull;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
+import androidx.recyclerview.widget.RecyclerView;
@SmallTest
@RunWith(AndroidJUnit4.class)
diff --git a/tests/tapl/com/android/launcher3/tapl/AllAppsFromHome.java b/tests/tapl/com/android/launcher3/tapl/AllApps.java
similarity index 64%
rename from tests/tapl/com/android/launcher3/tapl/AllAppsFromHome.java
rename to tests/tapl/com/android/launcher3/tapl/AllApps.java
index 02f8183..c3bc61b 100644
--- a/tests/tapl/com/android/launcher3/tapl/AllAppsFromHome.java
+++ b/tests/tapl/com/android/launcher3/tapl/AllApps.java
@@ -16,36 +16,35 @@
package com.android.launcher3.tapl;
-import android.support.annotation.NonNull;
+import static org.junit.Assert.assertTrue;
+
import android.support.test.uiautomator.BySelector;
import android.support.test.uiautomator.Direction;
import android.support.test.uiautomator.UiObject2;
+import androidx.annotation.NonNull;
+
+import com.android.launcher3.TestProtocol;
+
/**
- * Operations on AllApps opened from Home.
+ * Operations on AllApps opened from Home. Also a parent for All Apps opened from Overview.
*/
-public final class AllAppsFromHome {
+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 final Launcher mLauncher;
private final int mHeight;
- AllAppsFromHome(Launcher launcher) {
- mLauncher = launcher;
- final UiObject2 allAppsContainer = assertState();
+ AllApps(LauncherInstrumentation launcher) {
+ super(launcher);
+ final UiObject2 allAppsContainer = verifyActiveContainer();
mHeight = allAppsContainer.getVisibleBounds().height();
}
- /**
- * Asserts that we are in all apps.
- *
- * @return All apps container.
- */
- @NonNull
- private UiObject2 assertState() {
- return mLauncher.assertState(Launcher.State.ALL_APPS);
+ @Override
+ protected LauncherInstrumentation.ContainerType getContainerType() {
+ return LauncherInstrumentation.ContainerType.ALL_APPS;
}
/**
@@ -57,19 +56,19 @@
*/
@NonNull
public AppIcon getAppIcon(String appName) {
- final UiObject2 allAppsContainer = assertState();
+ final UiObject2 allAppsContainer = verifyActiveContainer();
final BySelector appIconSelector = AppIcon.getAppIconSelector(appName);
if (!allAppsContainer.hasObject(appIconSelector)) {
scrollBackToBeginning();
int attempts = 0;
while (!allAppsContainer.hasObject(appIconSelector) &&
allAppsContainer.scroll(Direction.DOWN, 0.8f)) {
- mLauncher.assertTrue("Exceeded max scroll attempts: " + MAX_SCROLL_ATTEMPTS,
+ assertTrue("Exceeded max scroll attempts: " + MAX_SCROLL_ATTEMPTS,
++attempts <= MAX_SCROLL_ATTEMPTS);
- assertState();
+ verifyActiveContainer();
}
}
- assertState();
+ verifyActiveContainer();
final UiObject2 appIcon = mLauncher.getObjectInContainer(allAppsContainer, appIconSelector);
ensureIconVisible(appIcon, allAppsContainer);
@@ -77,21 +76,30 @@
}
private void scrollBackToBeginning() {
- final UiObject2 allAppsContainer = assertState();
+ final UiObject2 allAppsContainer = verifyActiveContainer();
+ final UiObject2 searchBox =
+ mLauncher.waitForObjectInContainer(allAppsContainer, "search_container_all_apps");
int attempts = 0;
- allAppsContainer.setGestureMargins(5, 500, 5, 5);
+ allAppsContainer.setGestureMargins(0, searchBox.getVisibleBounds().bottom + 1, 0, 5);
- while (allAppsContainer.scroll(Direction.UP, 0.5f)) {
- mLauncher.waitForIdle();
- assertState();
+ for (int scroll = getScroll(allAppsContainer);
+ scroll != 0;
+ scroll = getScroll(allAppsContainer)) {
+ assertTrue("Negative scroll position", scroll > 0);
- mLauncher.assertTrue("Exceeded max scroll attempts: " + MAX_SCROLL_ATTEMPTS,
+ assertTrue("Exceeded max scroll attempts: " + MAX_SCROLL_ATTEMPTS,
++attempts <= MAX_SCROLL_ATTEMPTS);
+
+ allAppsContainer.scroll(Direction.UP, 1);
}
- mLauncher.waitForIdle();
- assertState();
+ verifyActiveContainer();
+ }
+
+ private int getScroll(UiObject2 allAppsContainer) {
+ return mLauncher.getAnswerFromLauncher(allAppsContainer, TestProtocol.GET_SCROLL_MESSAGE).
+ getInt(TestProtocol.SCROLL_Y_FIELD, -1);
}
private void ensureIconVisible(UiObject2 appIcon, UiObject2 allAppsContainer) {
@@ -102,7 +110,7 @@
final float pct = Math.max(((float) (MIN_INTERACT_SIZE - appHeight)) / mHeight, 0.2f);
allAppsContainer.scroll(Direction.DOWN, pct);
mLauncher.waitForIdle();
- assertState();
+ verifyActiveContainer();
}
}
@@ -110,22 +118,22 @@
* Flings forward (down) and waits the fling's end.
*/
public void flingForward() {
- final UiObject2 allAppsContainer = assertState();
+ 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);
- assertState();
+ verifyActiveContainer();
}
/**
* Flings backward (up) and waits the fling's end.
*/
public void flingBackward() {
- final UiObject2 allAppsContainer = assertState();
+ 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);
- assertState();
+ verifyActiveContainer();
}
/**
@@ -137,6 +145,6 @@
@Deprecated
@NonNull
public UiObject2 getObjectDeprecated() {
- return assertState();
+ return verifyActiveContainer();
}
}
diff --git a/tests/tapl/com/android/launcher3/tapl/AllAppsFromOverview.java b/tests/tapl/com/android/launcher3/tapl/AllAppsFromOverview.java
index cba7086..07e73fc 100644
--- a/tests/tapl/com/android/launcher3/tapl/AllAppsFromOverview.java
+++ b/tests/tapl/com/android/launcher3/tapl/AllAppsFromOverview.java
@@ -17,29 +17,18 @@
package com.android.launcher3.tapl;
import android.graphics.Point;
-import android.support.annotation.NonNull;
import android.support.test.uiautomator.UiObject2;
+import androidx.annotation.NonNull;
+
/**
* Operations on AllApps opened from Overview.
- * Scroll gestures that are OK for {@link AllAppsFromHome} may close it, so they are not supported.
*/
-public final class AllAppsFromOverview {
- private final Launcher mLauncher;
+public final class AllAppsFromOverview extends AllApps {
- AllAppsFromOverview(Launcher launcher) {
- mLauncher = launcher;
- assertState();
- }
-
- /**
- * Asserts that we are in all apps.
- *
- * @return All apps container.
- */
- @NonNull
- private UiObject2 assertState() {
- return mLauncher.assertState(Launcher.State.ALL_APPS);
+ AllAppsFromOverview(LauncherInstrumentation launcher) {
+ super(launcher);
+ verifyActiveContainer();
}
/**
@@ -49,13 +38,13 @@
*/
@NonNull
public Overview switchBackToOverview() {
- final UiObject2 allAppsContainer = assertState();
+ 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 endY = (int) (mLauncher.getDevice().getDisplayHeight() * 0.6);
- mLauncher.swipe(start.x, start.y, start.x, endY, (endY - start.y) / 100); // 100 px/step
+ mLauncher.swipe(start.x, start.y, start.x, endY);
return new Overview(mLauncher);
}
diff --git a/tests/tapl/com/android/launcher3/tapl/AppIcon.java b/tests/tapl/com/android/launcher3/tapl/AppIcon.java
index 73a74f2..721f7a8 100644
--- a/tests/tapl/com/android/launcher3/tapl/AppIcon.java
+++ b/tests/tapl/com/android/launcher3/tapl/AppIcon.java
@@ -16,6 +16,8 @@
package com.android.launcher3.tapl;
+import static org.junit.Assert.assertTrue;
+
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.BySelector;
import android.support.test.uiautomator.UiObject2;
@@ -26,25 +28,25 @@
* App icon, whether in all apps or in workspace/
*/
public final class AppIcon {
- private final Launcher mLauncher;
+ private final LauncherInstrumentation mLauncher;
private final UiObject2 mIcon;
- AppIcon(Launcher launcher, UiObject2 icon) {
+ AppIcon(LauncherInstrumentation launcher, UiObject2 icon) {
mLauncher = launcher;
mIcon = icon;
}
static BySelector getAppIconSelector(String appName) {
- return By.clazz(TextView.class).text(appName).pkg(Launcher.LAUNCHER_PKG);
+ return By.clazz(TextView.class).text(appName).pkg(LauncherInstrumentation.LAUNCHER_PKG);
}
/**
* Clicks the icon to launch its app.
*/
- public void launch() {
- mLauncher.assertTrue("Launching an app didn't open a new window: " + mIcon.getText(),
- mIcon.clickAndWait(Until.newWindow(), Launcher.APP_LAUNCH_TIMEOUT_MS));
- mLauncher.assertState(Launcher.State.BACKGROUND);
+ public Background launch() {
+ assertTrue("Launching an app didn't open a new window: " + mIcon.getText(),
+ mIcon.clickAndWait(Until.newWindow(), LauncherInstrumentation.WAIT_TIME_MS));
+ return new Background(mLauncher);
}
UiObject2 getIcon() {
diff --git a/tests/tapl/com/android/launcher3/tapl/Background.java b/tests/tapl/com/android/launcher3/tapl/Background.java
new file mode 100644
index 0000000..1aef979
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/Background.java
@@ -0,0 +1,32 @@
+/*
+ * 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.tapl;
+
+/**
+ * Operations on a state when Launcher is inactive because some other app is active.
+ */
+public final class Background extends Home {
+
+ Background(LauncherInstrumentation launcher) {
+ super(launcher);
+ }
+
+ @Override
+ protected LauncherInstrumentation.ContainerType getContainerType() {
+ return LauncherInstrumentation.ContainerType.BACKGROUND;
+ }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/Home.java b/tests/tapl/com/android/launcher3/tapl/Home.java
index 0ec1a64..786f260 100644
--- a/tests/tapl/com/android/launcher3/tapl/Home.java
+++ b/tests/tapl/com/android/launcher3/tapl/Home.java
@@ -16,38 +16,23 @@
package com.android.launcher3.tapl;
-import static junit.framework.TestCase.assertTrue;
-
-import android.graphics.Point;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.test.uiautomator.Direction;
import android.support.test.uiautomator.UiObject2;
-import android.view.KeyEvent;
+
+import androidx.annotation.NonNull;
/**
* Operations on the home screen.
+ *
+ * Launcher can be invoked both when its activity is in the foreground and when it is in the
+ * background. This class is a parent of the two classes {@link Background} and {@link Workspace}
+ * that essentially represents these two activity states. Any gestures (e.g., switchToOverview) that
+ * can be performed in both of these states can be defined here.
*/
-public final class Home {
+public abstract class Home extends LauncherInstrumentation.VisibleContainer {
- private final Launcher mLauncher;
- private final UiObject2 mHotseat;
- private final int ICON_DRAG_SPEED = 2000;
-
- Home(Launcher launcher) {
- mLauncher = launcher;
- assertState();
- mHotseat = launcher.waitForLauncherObject("hotseat");
- }
-
- /**
- * Asserts that we are in home.
- *
- * @return Workspace.
- */
- @NonNull
- private UiObject2 assertState() {
- return mLauncher.assertState(Launcher.State.HOME);
+ protected Home(LauncherInstrumentation launcher) {
+ super(launcher);
+ verifyActiveContainer();
}
/**
@@ -57,131 +42,19 @@
*/
@NonNull
public Overview switchToOverview() {
- assertState();
+ verifyActiveContainer();
if (mLauncher.isSwipeUpEnabled()) {
final int height = mLauncher.getDevice().getDisplayHeight();
final UiObject2 navBar = mLauncher.getSystemUiObject("navigation_bar_frame");
- // Swipe from nav bar to 2/3rd down the screen.
mLauncher.swipe(
navBar.getVisibleBounds().centerX(), navBar.getVisibleBounds().centerY(),
- navBar.getVisibleBounds().centerX(), height * 2 / 3,
- (navBar.getVisibleBounds().centerY() - height * 2 / 3) / 100); // 100 px/step
+ navBar.getVisibleBounds().centerX(), height - 300
+ );
} else {
mLauncher.getSystemUiObject("recent_apps").click();
}
return new Overview(mLauncher);
}
-
- /**
- * Swipes up to All Apps.
- *
- * @return the App Apps object.
- */
- @NonNull
- public AllAppsFromHome switchToAllApps() {
- assertState();
- if (mLauncher.isSwipeUpEnabled()) {
- int midX = mLauncher.getDevice().getDisplayWidth() / 2;
- int height = mLauncher.getDevice().getDisplayHeight();
- // Swipe from 6/7ths down the screen to 1/7th down the screen.
- mLauncher.swipe(
- midX,
- height * 6 / 7,
- midX,
- height / 7,
- (height * 2 / 3) / 100); // 100 px/step
- } else {
- // Swipe from the hotseat to near the top, e.g. 10% of the screen.
- final UiObject2 hotseat = mHotseat;
- final Point start = hotseat.getVisibleCenter();
- final int endY = (int) (mLauncher.getDevice().getDisplayHeight() * 0.1f);
- mLauncher.swipe(
- start.x,
- start.y,
- start.x,
- endY,
- (start.y - endY) / 100); // 100 px/step
- }
-
- return new AllAppsFromHome(mLauncher);
- }
-
- /**
- * Returns an icon for the app, if currently visible.
- *
- * @param appName name of the app
- * @return app icon, if found, null otherwise.
- */
- @Nullable
- public AppIcon tryGetWorkspaceAppIcon(String appName) {
- final UiObject2 workspace = assertState();
- final UiObject2 icon = workspace.findObject(AppIcon.getAppIconSelector(appName));
- return icon != null ? new AppIcon(mLauncher, icon) : null;
- }
-
- /**
- * Ensures that workspace is scrollable. If it's not, drags an icon icons from hotseat to the
- * second screen.
- */
- public void ensureWorkspaceIsScrollable() {
- final UiObject2 workspace = assertState();
- if (!isWorkspaceScrollable(workspace)) {
- dragIconToNextScreen(getHotseatAppIcon("Messages"), workspace);
- }
- assertTrue("Home screen workspace didn't become scrollable",
- isWorkspaceScrollable(workspace));
- }
-
- private boolean isWorkspaceScrollable(UiObject2 workspace) {
- return workspace.isScrollable();
- }
-
- @NonNull
- private AppIcon getHotseatAppIcon(String appName) {
- return new AppIcon(mLauncher, mLauncher.getObjectInContainer(
- mHotseat, AppIcon.getAppIconSelector(appName)));
- }
-
- private void dragIconToNextScreen(AppIcon app, UiObject2 workspace) {
- final Point dest = new Point(
- mLauncher.getDevice().getDisplayWidth(), workspace.getVisibleBounds().centerY());
- app.getIcon().drag(dest, ICON_DRAG_SPEED);
- assertState();
- }
-
- /**
- * Flings to get to screens on the right. Waits for scrolling and a possible overscroll
- * recoil to complete.
- */
- public void flingForward() {
- final UiObject2 workspace = assertState();
- workspace.fling(Direction.RIGHT);
- mLauncher.waitForIdle();
- assertState();
- }
-
- /**
- * Flings to get to screens on the left. Waits for scrolling and a possible overscroll
- * recoil to complete.
- */
- public void flingBackward() {
- final UiObject2 workspace = assertState();
- workspace.fling(Direction.LEFT);
- mLauncher.waitForIdle();
- assertState();
- }
-
- /**
- * Opens widgets container by pressing Ctrl+W.
- *
- * @return the widgets container.
- */
- @NonNull
- public Widgets openAllWidgets() {
- assertState();
- mLauncher.getDevice().pressKeyCode(KeyEvent.KEYCODE_W, KeyEvent.META_CTRL_ON);
- return new Widgets(mLauncher);
- }
}
\ No newline at end of file
diff --git a/tests/tapl/com/android/launcher3/tapl/Launcher.java b/tests/tapl/com/android/launcher3/tapl/Launcher.java
deleted file mode 100644
index 5201dc8..0000000
--- a/tests/tapl/com/android/launcher3/tapl/Launcher.java
+++ /dev/null
@@ -1,303 +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.tapl;
-
-import static com.android.systemui.shared.system.SettingsCompat.SWIPE_UP_SETTING_NAME;
-
-import android.content.res.Resources;
-import android.os.RemoteException;
-import android.provider.Settings;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.uiautomator.By;
-import android.support.test.uiautomator.BySelector;
-import android.support.test.uiautomator.UiDevice;
-import android.support.test.uiautomator.UiObject2;
-import android.support.test.uiautomator.Until;
-import android.util.Log;
-
-import org.junit.Assert;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-
-/**
- * The main tapl object. The only object that can be explicitly constructed by the using code. It
- * produces all other objects.
- */
-public final class Launcher {
-
- 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";
- private static final String WIDGETS_RES_ID = "widgets_list_view";
-
- enum State {HOME, ALL_APPS, OVERVIEW, WIDGETS, BACKGROUND}
-
- static final String LAUNCHER_PKG = "com.google.android.apps.nexuslauncher";
- static final int APP_LAUNCH_TIMEOUT_MS = 10000;
- private static final int UI_OBJECT_WAIT_TIMEOUT_MS = 10000;
- private static final String SWIPE_UP_SETTING_AVAILABLE_RES_NAME =
- "config_swipe_up_gesture_setting_available";
- private static final String SWIPE_UP_ENABLED_DEFAULT_RES_NAME =
- "config_swipe_up_gesture_default";
- private static final String SYSTEMUI_PACKAGE = "com.android.systemui";
- private static final String TAG = "tapl.Launcher";
- private final UiDevice mDevice;
- private final boolean mSwipeUpEnabled;
-
- /**
- * Constructs the root of TAPL hierarchy. You get all other object from it.
- */
- public Launcher(UiDevice device) {
- mDevice = device;
- final boolean swipeUpEnabledDefault =
- !getSystemBooleanRes(SWIPE_UP_SETTING_AVAILABLE_RES_NAME) ||
- getSystemBooleanRes(SWIPE_UP_ENABLED_DEFAULT_RES_NAME);
- mSwipeUpEnabled = Settings.Secure.getInt(
- InstrumentationRegistry.getTargetContext().getContentResolver(),
- SWIPE_UP_SETTING_NAME,
- swipeUpEnabledDefault ? 1 : 0) == 1;
- }
-
- private boolean getSystemBooleanRes(String resName) {
- final Resources res = Resources.getSystem();
- final int resId = res.getIdentifier(resName, "bool", "android");
- assertTrue("Resource not found: " + resName, resId != 0);
- return res.getBoolean(resId);
- }
-
- private void dumpViewHierarchy() {
- final ByteArrayOutputStream stream = new ByteArrayOutputStream();
- try {
- mDevice.dumpWindowHierarchy(stream);
- stream.flush();
- stream.close();
- for (String line : stream.toString().split("\\r?\\n")) {
- Log.e(TAG, line.trim());
- }
- } catch (IOException e) {
- Log.e(TAG, "error dumping XML to logcat", e);
- }
- }
-
- void fail(String message) {
- dumpViewHierarchy();
- Assert.fail(message);
- }
-
- void assertTrue(String message, boolean condition) {
- if (!condition) {
- fail(message);
- }
- }
-
- void assertNotNull(String message, Object object) {
- assertTrue(message, object != null);
- }
-
- private void failEquals(String message, Object actual) {
- String formatted = "Values should be different. ";
- if (message != null) {
- formatted = message + ". ";
- }
-
- formatted += "Actual: " + actual;
- fail(formatted);
- }
-
- void assertNotEquals(String message, int unexpected, int actual) {
- if (unexpected == actual) {
- failEquals(message, actual);
- }
- }
-
- boolean isSwipeUpEnabled() {
- return mSwipeUpEnabled;
- }
-
- UiObject2 assertState(State state) {
- switch (state) {
- case HOME: {
- //waitUntilGone(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(OVERVIEW_RES_ID);
- waitUntilGone(WORKSPACE_RES_ID);
- waitUntilGone(WIDGETS_RES_ID);
- return waitForLauncherObject(APPS_RES_ID);
- }
- case OVERVIEW: {
- //waitForLauncherObject(APPS_RES_ID);
- waitUntilGone(WORKSPACE_RES_ID);
- waitUntilGone(WIDGETS_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: " + state);
- return null;
- }
- }
-
- /**
- * Presses nav bar home button.
- *
- * @return the Home object.
- */
- public Home pressHome() {
- getSystemUiObject("home").click();
- return getHome();
- }
-
- /**
- * Gets the Home object if the current state is "active home", i.e. workspace. Fails if the
- * launcher is not in that state.
- *
- * @return Home object.
- */
- @NonNull
- public Home getHome() {
- return new Home(this);
- }
-
- /**
- * Gets the Widgets object if the current state is showing all widgets. Fails if the launcher is
- * not in that state.
- *
- * @return Widgets object.
- */
- @NonNull
- public Widgets getAllWidgets() {
- return new Widgets(this);
- }
-
- /**
- * Gets the Overview object if the current state is showing the overview panel. Fails if the
- * launcher is not in that state.
- *
- * @return Overview object.
- */
- @NonNull
- public Overview getOverview() {
- return new Overview(this);
- }
-
- /**
- * Gets the All Apps object if the current state is showing the all apps panel. Fails if the
- * launcher is not in that state.
- *
- * @return All Aps object.
- */
- @NonNull
- public AllAppsFromHome getAllApps() {
- return new AllAppsFromHome(this);
- }
-
- /**
- * Gets the All Apps object if the current state is showing the all apps panel. Returns null if
- * the launcher is not in that state.
- *
- * @return All Aps object or null.
- */
- @Nullable
- public AllAppsFromHome tryGetAllApps() {
- return tryGetLauncherObject(APPS_RES_ID) != null ? getAllApps() : null;
- }
-
- private void waitUntilGone(String resId) {
-// assertTrue("Unexpected launcher object visible: " + resId,
-// mDevice.wait(Until.gone(getLauncherObjectSelector(resId)),
-// UI_OBJECT_WAIT_TIMEOUT_MS));
- }
-
- @NonNull
- UiObject2 getSystemUiObject(String resId) {
- try {
- mDevice.wakeUp();
- } catch (RemoteException e) {
- fail("Failed to wake up the device: " + e);
- }
- final UiObject2 object = mDevice.findObject(By.res(SYSTEMUI_PACKAGE, resId));
- assertNotNull("Can't find a systemui object with id: " + resId, object);
- return object;
- }
-
- @NonNull
- UiObject2 getObjectInContainer(UiObject2 container, BySelector selector) {
- final UiObject2 object = container.findObject(selector);
- assertNotNull("Can't find an object with selector: " + selector, object);
- return object;
- }
-
- @Nullable
- private UiObject2 tryGetLauncherObject(String resName) {
- return mDevice.findObject(getLauncherObjectSelector(resName));
- }
-
- @NonNull
- UiObject2 waitForObjectInContainer(UiObject2 container, String resName) {
- final UiObject2 object = container.wait(
- Until.findObject(getLauncherObjectSelector(resName)),
- UI_OBJECT_WAIT_TIMEOUT_MS);
- assertNotNull("Can find a launcher object id: " + resName + " in container: " +
- container.getResourceName(), object);
- return object;
- }
-
- @NonNull
- UiObject2 waitForLauncherObject(String resName) {
- final UiObject2 object = mDevice.wait(Until.findObject(getLauncherObjectSelector(resName)),
- UI_OBJECT_WAIT_TIMEOUT_MS);
- assertNotNull("Can find a launcher object; id: " + resName, object);
- return object;
- }
-
- static BySelector getLauncherObjectSelector(String resName) {
- return By.res(LAUNCHER_PKG, resName);
- }
-
- @NonNull
- UiDevice getDevice() {
- return mDevice;
- }
-
- void swipe(int startX, int startY, int endX, int endY, int steps) {
- mDevice.swipe(startX, startY, endX, endY, steps);
- waitForIdle();
- }
-
- void waitForIdle() {
- mDevice.waitForIdle();
- }
-}
\ No newline at end of file
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
new file mode 100644
index 0000000..01e76f3
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -0,0 +1,350 @@
+/*
+ * 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.tapl;
+
+import static com.android.systemui.shared.system.SettingsCompat.SWIPE_UP_SETTING_NAME;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.app.ActivityManager;
+import android.app.UiAutomation;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.BySelector;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.UiObject2;
+import android.support.test.uiautomator.Until;
+import android.view.accessibility.AccessibilityEvent;
+
+import com.android.launcher3.TestProtocol;
+import com.android.quickstep.SwipeUpSetting;
+
+import java.lang.ref.WeakReference;
+import java.util.concurrent.TimeoutException;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+/**
+ * The main tapl object. The only object that can be explicitly constructed by the using code. It
+ * produces all other objects.
+ */
+public final class LauncherInstrumentation {
+
+ // Types for launcher containers that the user is interacting with. "Background" is a
+ // pseudo-container corresponding to inactive launcher covered by another app.
+ enum ContainerType {
+ WORKSPACE, ALL_APPS, OVERVIEW, WIDGETS, BACKGROUND
+ }
+
+ // Base class for launcher containers.
+ static abstract class VisibleContainer {
+ protected final LauncherInstrumentation mLauncher;
+
+ protected VisibleContainer(LauncherInstrumentation launcher) {
+ mLauncher = launcher;
+ launcher.setActiveContainer(this);
+ }
+
+ protected abstract ContainerType getContainerType();
+
+ /**
+ * Asserts that the launcher is in the mode matching 'this' object.
+ *
+ * @return UI object for the container.
+ */
+ final UiObject2 verifyActiveContainer() {
+ assertTrue("Attempt to use a stale container", this == sActiveContainer.get());
+ return mLauncher.verifyContainerType(getContainerType());
+ }
+ }
+
+ 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";
+ private static final String WIDGETS_RES_ID = "widgets_list_view";
+ static final String LAUNCHER_PKG = "com.google.android.apps.nexuslauncher";
+ static final int WAIT_TIME_MS = 60000;
+ private static final String SYSTEMUI_PACKAGE = "com.android.systemui";
+
+ private static WeakReference<VisibleContainer> sActiveContainer = new WeakReference<>(null);
+
+ private final UiDevice mDevice;
+ private final boolean mSwipeUpEnabled;
+ private Boolean mSwipeUpEnabledOverride = null;
+
+ /**
+ * Constructs the root of TAPL hierarchy. You get all other objects from it.
+ */
+ public LauncherInstrumentation(UiDevice device) {
+ mDevice = device;
+ final boolean swipeUpEnabledDefault =
+ !SwipeUpSetting.isSwipeUpSettingAvailable() ||
+ SwipeUpSetting.isSwipeUpEnabledDefaultValue();
+ mSwipeUpEnabled = Settings.Secure.getInt(
+ InstrumentationRegistry.getTargetContext().getContentResolver(),
+ SWIPE_UP_SETTING_NAME,
+ swipeUpEnabledDefault ? 1 : 0) == 1;
+ assertTrue("Device must run in a test harness", ActivityManager.isRunningInTestHarness());
+ }
+
+ // Used only by tests.
+ public void overrideSwipeUpEnabled(Boolean swipeUpEnabledOverride) {
+ mSwipeUpEnabledOverride = swipeUpEnabledOverride;
+ }
+
+ void setActiveContainer(VisibleContainer container) {
+ sActiveContainer = new WeakReference<>(container);
+ }
+
+ boolean isSwipeUpEnabled() {
+ return mSwipeUpEnabledOverride != null ? mSwipeUpEnabledOverride : mSwipeUpEnabled;
+ }
+
+ private UiObject2 verifyContainerType(ContainerType containerType) {
+ switch (containerType) {
+ case WORKSPACE: {
+ waitUntilGone(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: {
+ waitForLauncherObject(APPS_RES_ID);
+ waitUntilGone(WORKSPACE_RES_ID);
+ waitUntilGone(WIDGETS_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;
+ }
+ }
+
+ private Bundle executeAndWaitForEvent(Runnable command,
+ UiAutomation.AccessibilityEventFilter eventFilter, String message) {
+ try {
+ final AccessibilityEvent event =
+ InstrumentationRegistry.getInstrumentation().getUiAutomation()
+ .executeAndWaitForEvent(
+ command, eventFilter, WAIT_TIME_MS);
+ assertNotNull("executeAndWaitForEvent returned null (this can't happen)", event);
+ return (Bundle) event.getParcelableData();
+ } catch (TimeoutException e) {
+ fail(message);
+ return null;
+ }
+ }
+
+ Bundle getAnswerFromLauncher(UiObject2 view, String requestTag) {
+ // Send a fake set-text request to Launcher to initiate a response with requested data.
+ final String responseTag = requestTag + TestProtocol.RESPONSE_MESSAGE_POSTFIX;
+ return executeAndWaitForEvent(
+ () -> view.setText(requestTag),
+ event -> responseTag.equals(event.getClassName()),
+ "Launcher didn't respond to request: " + requestTag);
+ }
+
+ /**
+ * Presses nav bar home button.
+ *
+ * @return the Workspace object.
+ */
+ public Workspace pressHome() {
+ // Click home, then wait for any accessibility event, then wait until accessibility events
+ // stop.
+ // We need waiting for any accessibility event generated after pressing Home because
+ // otherwise waitForIdle may return immediately in case when there was a big enough pause in
+ // accessibility events prior to pressing Home.
+ executeAndWaitForEvent(
+ () -> getSystemUiObject("home").click(),
+ event -> true,
+ "Pressing Home didn't produce any events");
+ mDevice.waitForIdle();
+ return getWorkspace();
+ }
+
+ /**
+ * Gets the Workspace object if the current state is "active home", i.e. workspace. Fails if the
+ * launcher is not in that state.
+ *
+ * @return Workspace object.
+ */
+ @NonNull
+ public Workspace getWorkspace() {
+ return new Workspace(this);
+ }
+
+ /**
+ * Gets the Workspace object if the current state is "background home", i.e. some other app is
+ * active. Fails if the launcher is not in that state.
+ *
+ * @return Background object.
+ */
+ @NonNull
+ public Background getBackground() {
+ return new Background(this);
+ }
+
+ /**
+ * Gets the Widgets object if the current state is showing all widgets. Fails if the launcher is
+ * not in that state.
+ *
+ * @return Widgets object.
+ */
+ @NonNull
+ public Widgets getAllWidgets() {
+ return new Widgets(this);
+ }
+
+ /**
+ * Gets the Overview object if the current state is showing the overview panel. Fails if the
+ * launcher is not in that state.
+ *
+ * @return Overview object.
+ */
+ @NonNull
+ public Overview getOverview() {
+ return new Overview(this);
+ }
+
+ /**
+ * Gets the All Apps object if the current state is showing the all apps panel opened by swiping
+ * from workspace. Fails if the launcher is not in that state. Please don't call this method if
+ * App Apps was opened by swiping up from Overview, as it won't fail and will return an
+ * incorrect object.
+ *
+ * @return All Aps object.
+ */
+ @NonNull
+ public AllApps getAllApps() {
+ return new AllApps(this);
+ }
+
+ /**
+ * Gets the All Apps object if the current state is showing the all apps panel opened by swiping
+ * from overview. Fails if the launcher is not in that state. Please don't call this method if
+ * App Apps was opened by swiping up from home, as it won't fail and will return an
+ * incorrect object.
+ *
+ * @return All Aps object.
+ */
+ @NonNull
+ public AllAppsFromOverview getAllAppsFromOverview() {
+ return new AllAppsFromOverview(this);
+ }
+
+ /**
+ * Gets the All Apps object if the current state is showing the all apps panel opened by swiping
+ * from workspace. Returns null if launcher is not in that state. Please don't call this method
+ * if App Apps was opened by swiping up from Overview, as it won't fail and will return an
+ * incorrect object.
+ *
+ * @return All Aps object or null.
+ */
+ @Nullable
+ public AllApps tryGetAllApps() {
+ return tryGetLauncherObject(APPS_RES_ID) != null ? getAllApps() : null;
+ }
+
+ private void waitUntilGone(String resId) {
+ assertTrue("Unexpected launcher object visible: " + resId,
+ mDevice.wait(Until.gone(getLauncherObjectSelector(resId)),
+ WAIT_TIME_MS));
+ }
+
+ @NonNull
+ UiObject2 getSystemUiObject(String resId) {
+ final UiObject2 object = mDevice.findObject(By.res(SYSTEMUI_PACKAGE, resId));
+ assertNotNull("Can't find a systemui object with id: " + resId, object);
+ return object;
+ }
+
+ @NonNull
+ UiObject2 getObjectInContainer(UiObject2 container, BySelector selector) {
+ final UiObject2 object = container.findObject(selector);
+ assertNotNull("Can't find an object with selector: " + selector, object);
+ return object;
+ }
+
+ @Nullable
+ private UiObject2 tryGetLauncherObject(String resName) {
+ return mDevice.findObject(getLauncherObjectSelector(resName));
+ }
+
+ @NonNull
+ UiObject2 waitForObjectInContainer(UiObject2 container, String resName) {
+ final UiObject2 object = container.wait(
+ Until.findObject(getLauncherObjectSelector(resName)),
+ WAIT_TIME_MS);
+ assertNotNull("Can't find a launcher object id: " + resName + " in container: " +
+ container.getResourceName(), object);
+ return object;
+ }
+
+ @NonNull
+ UiObject2 waitForLauncherObject(String resName) {
+ final UiObject2 object = mDevice.wait(Until.findObject(getLauncherObjectSelector(resName)),
+ WAIT_TIME_MS);
+ assertNotNull("Can't find a launcher object; id: " + resName, object);
+ return object;
+ }
+
+ static BySelector getLauncherObjectSelector(String resName) {
+ return By.res(LAUNCHER_PKG, resName);
+ }
+
+ @NonNull
+ UiDevice getDevice() {
+ return mDevice;
+ }
+
+ void swipe(int startX, int startY, int endX, int endY) {
+ executeAndWaitForEvent(
+ () -> mDevice.swipe(startX, startY, endX, endY, 60),
+ event -> TestProtocol.SWITCHED_TO_STATE_MESSAGE.equals(event.getClassName()),
+ "Swipe failed to receive an event for the swipe end: " + startX + ", " + startY
+ + ", " + endX + ", " + endY);
+ }
+
+ void waitForIdle() {
+ mDevice.waitForIdle();
+ }
+}
\ No newline at end of file
diff --git a/tests/tapl/com/android/launcher3/tapl/Overview.java b/tests/tapl/com/android/launcher3/tapl/Overview.java
index 2251655..3c0ae2d 100644
--- a/tests/tapl/com/android/launcher3/tapl/Overview.java
+++ b/tests/tapl/com/android/launcher3/tapl/Overview.java
@@ -16,55 +16,51 @@
package com.android.launcher3.tapl;
+import static org.junit.Assert.assertNotEquals;
+
import android.graphics.Point;
-import android.support.annotation.NonNull;
import android.support.test.uiautomator.Direction;
import android.support.test.uiautomator.UiObject2;
import java.util.Collections;
import java.util.List;
+import androidx.annotation.NonNull;
+
/**
* Overview pane.
*/
-public final class Overview {
+public final class Overview extends LauncherInstrumentation.VisibleContainer {
private static final int DEFAULT_FLING_SPEED = 15000;
- private final Launcher mLauncher;
-
- Overview(Launcher launcher) {
- mLauncher = launcher;
- assertState();
+ Overview(LauncherInstrumentation launcher) {
+ super(launcher);
+ verifyActiveContainer();
}
- /**
- * Asserts that we are in overview.
- *
- * @return Overview panel.
- */
- @NonNull
- private UiObject2 assertState() {
- return mLauncher.assertState(Launcher.State.OVERVIEW);
+ @Override
+ protected LauncherInstrumentation.ContainerType getContainerType() {
+ return LauncherInstrumentation.ContainerType.OVERVIEW;
}
/**
* Flings forward (left) and waits the fling's end.
*/
public void flingForward() {
- final UiObject2 overview = assertState();
+ final UiObject2 overview = verifyActiveContainer();
overview.fling(Direction.LEFT, DEFAULT_FLING_SPEED);
mLauncher.waitForIdle();
- assertState();
+ verifyActiveContainer();
}
/**
* Flings backward (right) and waits the fling's end.
*/
public void flingBackward() {
- final UiObject2 overview = assertState();
+ final UiObject2 overview = verifyActiveContainer();
overview.fling(Direction.RIGHT, DEFAULT_FLING_SPEED);
mLauncher.waitForIdle();
- assertState();
+ verifyActiveContainer();
}
/**
@@ -74,10 +70,10 @@
*/
@NonNull
public OverviewTask getCurrentTask() {
- assertState();
+ verifyActiveContainer();
final List<UiObject2> taskViews = mLauncher.getDevice().findObjects(
- Launcher.getLauncherObjectSelector("snapshot"));
- mLauncher.assertNotEquals("Unable to find a task", 0, taskViews.size());
+ LauncherInstrumentation.getLauncherObjectSelector("snapshot"));
+ 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
@@ -86,7 +82,7 @@
(t1, t2) -> Integer.compare(t1.getVisibleBounds().width(),
t2.getVisibleBounds().width()));
- return new OverviewTask(mLauncher, widestTask);
+ return new OverviewTask(mLauncher, widestTask, this);
}
/**
@@ -96,15 +92,12 @@
*/
@NonNull
public AllAppsFromOverview switchToAllApps() {
- assertState();
+ verifyActiveContainer();
- // Swipe from the hotseat to near the top, e.g. 10% of the screen.
- final UiObject2 predictionRow = mLauncher.waitForLauncherObject(
- "prediction_row");
- final Point start = predictionRow.getVisibleCenter();
- final int endY = (int) (mLauncher.getDevice().getDisplayHeight() * 0.1f);
- mLauncher.swipe(
- start.x, start.y, start.x, endY, (start.y - endY) / 100); // 100 px/step
+ // Swipe from navbar to the top.
+ final UiObject2 navBar = mLauncher.getSystemUiObject("navigation_bar_frame");
+ final Point start = navBar.getVisibleCenter();
+ mLauncher.swipe(start.x, start.y, start.x, 0);
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 68d3082..0b3a264 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
@@ -16,6 +16,8 @@
package com.android.launcher3.tapl;
+import static org.junit.Assert.assertTrue;
+
import android.support.test.uiautomator.Direction;
import android.support.test.uiautomator.UiObject2;
import android.support.test.uiautomator.Until;
@@ -24,29 +26,26 @@
* A recent task in the overview panel carousel.
*/
public final class OverviewTask {
- private final Launcher mLauncher;
+ private final LauncherInstrumentation mLauncher;
private final UiObject2 mTask;
+ private final Overview mOverview;
- OverviewTask(Launcher launcher, UiObject2 task) {
+ OverviewTask(LauncherInstrumentation launcher, UiObject2 task, Overview overview) {
mLauncher = launcher;
- assertState();
mTask = task;
+ mOverview = overview;
+ verifyActiveContainer();
}
- /**
- * Asserts that we are in overview.
- *
- * @return Overview panel.
- */
- private void assertState() {
- mLauncher.assertState(Launcher.State.OVERVIEW);
+ private void verifyActiveContainer() {
+ mOverview.verifyActiveContainer();
}
/**
* Swipes the task up.
*/
public void dismiss() {
- assertState();
+ verifyActiveContainer();
// Dismiss the task via flinging it up.
mTask.fling(Direction.DOWN);
mLauncher.waitForIdle();
@@ -55,11 +54,11 @@
/**
* Clicks at the task.
*/
- public void open() {
- assertState();
- mLauncher.assertTrue("Launching task didn't open a new window: " +
+ public Background open() {
+ verifyActiveContainer();
+ assertTrue("Launching task didn't open a new window: " +
mTask.getParent().getContentDescription(),
- mTask.clickAndWait(Until.newWindow(), Launcher.APP_LAUNCH_TIMEOUT_MS));
- mLauncher.assertState(Launcher.State.BACKGROUND);
+ 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 7a5198a..f67ef4c 100644
--- a/tests/tapl/com/android/launcher3/tapl/Widgets.java
+++ b/tests/tapl/com/android/launcher3/tapl/Widgets.java
@@ -16,50 +16,43 @@
package com.android.launcher3.tapl;
-import android.support.annotation.NonNull;
import android.support.test.uiautomator.Direction;
import android.support.test.uiautomator.UiObject2;
/**
* All widgets container.
*/
-public final class Widgets {
+public final class Widgets extends LauncherInstrumentation.VisibleContainer {
private static final int FLING_SPEED = 12000;
- private final Launcher mLauncher;
-
- Widgets(Launcher launcher) {
- mLauncher = launcher;
- assertState();
+ Widgets(LauncherInstrumentation launcher) {
+ super(launcher);
+ verifyActiveContainer();
}
/**
* Flings forward (down) and waits the fling's end.
*/
public void flingForward() {
- final UiObject2 widgetsContainer = assertState();
+ final UiObject2 widgetsContainer = verifyActiveContainer();
+ widgetsContainer.setGestureMargin(100);
widgetsContainer.fling(Direction.DOWN, FLING_SPEED);
- mLauncher.waitForIdle();
- assertState();
+ verifyActiveContainer();
}
/**
* Flings backward (up) and waits the fling's end.
*/
public void flingBackward() {
- final UiObject2 widgetsContainer = assertState();
+ final UiObject2 widgetsContainer = verifyActiveContainer();
+ widgetsContainer.setGestureMargin(100);
widgetsContainer.fling(Direction.UP, FLING_SPEED);
mLauncher.waitForIdle();
- assertState();
+ verifyActiveContainer();
}
- /**
- * Asserts that we are in widgets.
- *
- * @return Widgets container.
- */
- @NonNull
- private UiObject2 assertState() {
- return mLauncher.assertState(Launcher.State.WIDGETS);
+ @Override
+ protected LauncherInstrumentation.ContainerType getContainerType() {
+ return LauncherInstrumentation.ContainerType.WIDGETS;
}
}
diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java
new file mode 100644
index 0000000..c58c244
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java
@@ -0,0 +1,156 @@
+/*
+ * 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.tapl;
+
+import static junit.framework.TestCase.assertTrue;
+
+import android.graphics.Point;
+import android.support.test.uiautomator.Direction;
+import android.support.test.uiautomator.UiObject2;
+import android.view.KeyEvent;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+/**
+ * Operations on the workspace screen.
+ */
+public final class Workspace extends Home {
+ private final UiObject2 mHotseat;
+ private final int ICON_DRAG_SPEED = 2000;
+
+ Workspace(LauncherInstrumentation launcher) {
+ super(launcher);
+ mHotseat = launcher.waitForLauncherObject("hotseat");
+ }
+
+ @Override
+ protected LauncherInstrumentation.ContainerType getContainerType() {
+ return LauncherInstrumentation.ContainerType.WORKSPACE;
+ }
+
+ /**
+ * Swipes up to All Apps.
+ *
+ * @return the App Apps object.
+ */
+ @NonNull
+ public AllApps switchToAllApps() {
+ verifyActiveContainer();
+ if (mLauncher.isSwipeUpEnabled()) {
+ int midX = mLauncher.getDevice().getDisplayWidth() / 2;
+ int height = mLauncher.getDevice().getDisplayHeight();
+ // Swipe from 6/7ths down the screen to 1/7th down the screen.
+ mLauncher.swipe(
+ midX,
+ height * 6 / 7,
+ midX,
+ height / 7
+ );
+ } else {
+ // Swipe from the hotseat to near the top, e.g. 10% of the screen.
+ final UiObject2 hotseat = mHotseat;
+ final Point start = hotseat.getVisibleCenter();
+ final int endY = (int) (mLauncher.getDevice().getDisplayHeight() * 0.1f);
+ mLauncher.swipe(
+ start.x,
+ start.y,
+ start.x,
+ endY
+ );
+ }
+
+ return new AllApps(mLauncher);
+ }
+
+ /**
+ * Returns an icon for the app, if currently visible.
+ *
+ * @param appName name of the app
+ * @return app icon, if found, null otherwise.
+ */
+ @Nullable
+ public AppIcon tryGetWorkspaceAppIcon(String appName) {
+ final UiObject2 workspace = verifyActiveContainer();
+ final UiObject2 icon = workspace.findObject(AppIcon.getAppIconSelector(appName));
+ return icon != null ? new AppIcon(mLauncher, icon) : null;
+ }
+
+ /**
+ * Ensures that workspace is scrollable. If it's not, drags an icon icons from hotseat to the
+ * second screen.
+ */
+ public void ensureWorkspaceIsScrollable() {
+ final UiObject2 workspace = verifyActiveContainer();
+ if (!isWorkspaceScrollable(workspace)) {
+ dragIconToNextScreen(getHotseatAppIcon("Messages"), workspace);
+ }
+ assertTrue("Home screen workspace didn't become scrollable",
+ isWorkspaceScrollable(workspace));
+ }
+
+ private boolean isWorkspaceScrollable(UiObject2 workspace) {
+ return workspace.isScrollable();
+ }
+
+ @NonNull
+ private AppIcon getHotseatAppIcon(String appName) {
+ return new AppIcon(mLauncher, mLauncher.getObjectInContainer(
+ mHotseat, AppIcon.getAppIconSelector(appName)));
+ }
+
+ private void dragIconToNextScreen(AppIcon app, UiObject2 workspace) {
+ final Point dest = new Point(
+ mLauncher.getDevice().getDisplayWidth(), workspace.getVisibleBounds().centerY());
+ app.getIcon().drag(dest, ICON_DRAG_SPEED);
+ verifyActiveContainer();
+ }
+
+ /**
+ * Flings to get to screens on the right. Waits for scrolling and a possible overscroll
+ * recoil to complete.
+ */
+ public void flingForward() {
+ final UiObject2 workspace = verifyActiveContainer();
+ workspace.fling(Direction.RIGHT);
+ mLauncher.waitForIdle();
+ verifyActiveContainer();
+ }
+
+ /**
+ * Flings to get to screens on the left. Waits for scrolling and a possible overscroll
+ * recoil to complete.
+ */
+ public void flingBackward() {
+ final UiObject2 workspace = verifyActiveContainer();
+ workspace.fling(Direction.LEFT);
+ mLauncher.waitForIdle();
+ verifyActiveContainer();
+ }
+
+ /**
+ * Opens widgets container by pressing Ctrl+W.
+ *
+ * @return the widgets container.
+ */
+ @NonNull
+ public Widgets openAllWidgets() {
+ verifyActiveContainer();
+ mLauncher.getDevice().pressKeyCode(KeyEvent.KEYCODE_W, KeyEvent.META_CTRL_ON);
+ return new Widgets(mLauncher);
+ }
+}
\ No newline at end of file