Merge "Remove preference to flip recents" into ub-launcher3-edmonton
diff --git a/AndroidManifest-common.xml b/AndroidManifest-common.xml
index c24850d..fe8d65e 100644
--- a/AndroidManifest-common.xml
+++ b/AndroidManifest-common.xml
@@ -20,7 +20,6 @@
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.launcher3">
- <uses-sdk android:targetSdkVersion="23" android:minSdkVersion="21"/>
<!--
The manifest defines the common entries that should be present in any derivative of Launcher3.
diff --git a/build.gradle b/build.gradle
index 0030b8b..4ae6600 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,14 +1,16 @@
buildscript {
repositories {
mavenCentral()
- jcenter()
+ google()
}
dependencies {
- classpath 'com.android.tools.build:gradle:2.3.3'
- classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.0'
+ classpath 'com.android.tools.build:gradle:3.2.0-alpha12'
+ classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.3'
}
}
+final String SUPPORT_LIBS_VERSION = '28.0.0-SNAPSHOT'
+
apply plugin: 'com.android.application'
apply plugin: 'com.google.protobuf'
@@ -23,6 +25,7 @@
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+ vectorDrawables.useSupportLibrary = true
}
buildTypes {
debug {
@@ -30,18 +33,28 @@
}
}
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+
+ flavorDimensions "default"
+
productFlavors {
aosp {
+ dimension "default"
applicationId 'com.android.launcher3'
testApplicationId 'com.android.launcher3.tests'
}
l3go {
+ dimension "default"
applicationId 'com.android.launcher3'
testApplicationId 'com.android.launcher3.tests'
}
quickstep {
+ dimension "default"
applicationId 'com.android.launcher3'
testApplicationId 'com.android.launcher3.tests'
}
@@ -98,27 +111,28 @@
}
repositories {
+ maven { url "../../../prebuilts/fullsdk-darwin/extras/android/m2repository" }
+ maven { url "../../../prebuilts/fullsdk-linux/extras/android/m2repository" }
mavenCentral()
- jcenter()
+ google()
}
-final String SUPPORT_LIBS_VERSION = '28.0.0-SNAPSHOT'
dependencies {
- compile "com.android.support:support-v4:${SUPPORT_LIBS_VERSION}"
- compile "com.android.support:support-dynamic-animation:${SUPPORT_LIBS_VERSION}"
- compile "com.android.support:recyclerview-v7:${SUPPORT_LIBS_VERSION}"
- compile 'com.google.protobuf.nano:protobuf-javanano:3.0.0-alpha-7'
+ 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 'com.google.protobuf.nano:protobuf-javanano:3.0.0-alpha-7'
- quickstepCompile fileTree(dir: "quickstep/libs", include: 'sysui_shared.jar')
+ quickstepImplementation fileTree(dir: "quickstep/libs", include: 'sysui_shared.jar')
- testCompile 'junit:junit:4.12'
- androidTestCompile "org.mockito:mockito-core:1.9.5"
- androidTestCompile 'com.google.dexmaker:dexmaker:1.2'
- androidTestCompile 'com.google.dexmaker:dexmaker-mockito:1.2'
- androidTestCompile 'com.android.support.test:runner:1.0.0'
- androidTestCompile 'com.android.support.test:rules:1.0.0'
- androidTestCompile 'com.android.support.test.uiautomator:uiautomator-v18:2.1.2'
- androidTestCompile "com.android.support:support-annotations:${SUPPORT_LIBS_VERSION}"
+ testImplementation 'junit:junit:4.12'
+ androidTestImplementation "org.mockito:mockito-core:1.9.5"
+ androidTestImplementation 'com.google.dexmaker:dexmaker:1.2'
+ androidTestImplementation 'com.google.dexmaker:dexmaker-mockito:1.2'
+ 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}"
}
protobuf {
diff --git a/quickstep/AndroidManifest.xml b/quickstep/AndroidManifest.xml
index f62d1d6..bab2cd7 100644
--- a/quickstep/AndroidManifest.xml
+++ b/quickstep/AndroidManifest.xml
@@ -21,8 +21,6 @@
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.launcher3" >
- <uses-sdk android:targetSdkVersion="23" android:minSdkVersion="21"/>
-
<uses-permission android:name="android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS" />
<application
android:backupAgent="com.android.launcher3.LauncherBackupAgent"
diff --git a/quickstep/libs/sysui_shared.jar b/quickstep/libs/sysui_shared.jar
index 19a9b17..0adc83a 100644
--- a/quickstep/libs/sysui_shared.jar
+++ b/quickstep/libs/sysui_shared.jar
Binary files differ
diff --git a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
index c985354..7d62f52 100644
--- a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
+++ b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
@@ -16,6 +16,7 @@
package com.android.launcher3;
import static com.android.launcher3.Utilities.postAsyncCallback;
+import static com.android.systemui.shared.recents.utilities.Utilities.postAtFrontOfQueueAsynchronously;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -35,20 +36,31 @@
private static final int REFRESH_RATE_MS = 16;
private final Handler mHandler;
+ private final boolean mStartAtFrontOfQueue;
private AnimationResult mAnimationResult;
- public LauncherAnimationRunner(Handler handler) {
+ /**
+ * @param startAtFrontOfQueue If true, the animation start will be posted at the front of the
+ * queue to minimize latency.
+ */
+ public LauncherAnimationRunner(Handler handler, boolean startAtFrontOfQueue) {
mHandler = handler;
+ mStartAtFrontOfQueue = startAtFrontOfQueue;
}
@BinderThread
@Override
public void onAnimationStart(RemoteAnimationTargetCompat[] targetCompats, Runnable runnable) {
- postAsyncCallback(mHandler, () -> {
+ Runnable r = () -> {
finishExistingAnimation();
mAnimationResult = new AnimationResult(runnable);
onCreateAnimation(targetCompats, mAnimationResult);
- });
+ };
+ if (mStartAtFrontOfQueue) {
+ postAtFrontOfQueueAsynchronously(mHandler, r);
+ } else {
+ postAsyncCallback(mHandler, r);
+ }
}
/**
diff --git a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
index 353ed84..ab350e4 100644
--- a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
+++ b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
@@ -162,7 +162,8 @@
@Override
public ActivityOptions getActivityLaunchOptions(Launcher launcher, View v) {
if (hasControlRemoteAppTransitionPermission()) {
- RemoteAnimationRunnerCompat runner = new LauncherAnimationRunner(mHandler) {
+ RemoteAnimationRunnerCompat runner = new LauncherAnimationRunner(mHandler,
+ true /* startAtFrontOfQueue */) {
@Override
public void onCreateAnimation(RemoteAnimationTargetCompat[] targetCompats,
@@ -572,7 +573,7 @@
* ie. pressing home, swiping up from nav bar.
*/
private RemoteAnimationRunnerCompat getWallpaperOpenRunner() {
- return new LauncherAnimationRunner(mHandler) {
+ return new LauncherAnimationRunner(mHandler, false /* startAtFrontOfQueue */) {
@Override
public void onCreateAnimation(RemoteAnimationTargetCompat[] targetCompats,
AnimationResult result) {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java b/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java
index d2f5487..7da50c8 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java
@@ -16,7 +16,7 @@
package com.android.launcher3.uioverrides;
import static com.android.launcher3.LauncherAnimUtils.ALL_APPS_TRANSITION_MS;
-import static com.android.launcher3.allapps.DiscoveryBounce.APPS_VIEW_SHOWN;
+import static com.android.launcher3.allapps.DiscoveryBounce.SHELF_BOUNCE_SEEN;
import static com.android.launcher3.anim.Interpolators.DEACCEL_2;
import android.view.View;
@@ -47,8 +47,8 @@
@Override
public void onStateEnabled(Launcher launcher) {
- if (!launcher.getSharedPrefs().getBoolean(APPS_VIEW_SHOWN, false)) {
- launcher.getSharedPrefs().edit().putBoolean(APPS_VIEW_SHOWN, true).apply();
+ if (!launcher.getSharedPrefs().getBoolean(SHELF_BOUNCE_SEEN, false)) {
+ launcher.getSharedPrefs().edit().putBoolean(SHELF_BOUNCE_SEEN, true).apply();
}
AbstractFloatingView.closeAllOpenViews(launcher);
diff --git a/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
index 026f059..61422e0 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
@@ -16,6 +16,7 @@
package com.android.launcher3.uioverrides;
import static com.android.launcher3.LauncherAnimUtils.OVERVIEW_TRANSITION_MS;
+import static com.android.launcher3.allapps.DiscoveryBounce.HOME_BOUNCE_SEEN;
import static com.android.launcher3.anim.Interpolators.DEACCEL_2;
import static com.android.launcher3.states.RotationHelper.REQUEST_ROTATE;
@@ -25,6 +26,7 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
+import com.android.launcher3.allapps.DiscoveryBounce;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.quickstep.views.RecentsView;
@@ -57,6 +59,10 @@
@Override
public void onStateEnabled(Launcher launcher) {
+ if (!launcher.getSharedPrefs().getBoolean(HOME_BOUNCE_SEEN, false)) {
+ launcher.getSharedPrefs().edit().putBoolean(HOME_BOUNCE_SEEN, true).apply();
+ }
+
RecentsView rv = launcher.getOverviewPanel();
rv.setOverviewStateEnabled(true);
AbstractFloatingView.closeAllOpenViews(launcher);
@@ -71,6 +77,7 @@
@Override
public void onStateTransitionEnd(Launcher launcher) {
launcher.getRotationHelper().setCurrentStateRequest(REQUEST_ROTATE);
+ DiscoveryBounce.showForOverviewIfNeeded(launcher);
}
@Override
diff --git a/quickstep/src/com/android/quickstep/ActivityControlHelper.java b/quickstep/src/com/android/quickstep/ActivityControlHelper.java
index d3b0576..ad11bd3 100644
--- a/quickstep/src/com/android/quickstep/ActivityControlHelper.java
+++ b/quickstep/src/com/android/quickstep/ActivityControlHelper.java
@@ -38,11 +38,13 @@
import com.android.launcher3.LauncherInitListener;
import com.android.launcher3.LauncherState;
import com.android.launcher3.allapps.AllAppsTransitionController;
+import com.android.launcher3.allapps.DiscoveryBounce;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.quickstep.util.LayoutUtils;
import com.android.quickstep.util.RemoteAnimationProvider;
import com.android.quickstep.util.RemoteAnimationTargetSet;
import com.android.quickstep.views.LauncherLayoutListener;
+import com.android.quickstep.views.LauncherRecentsView;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.RecentsViewContainer;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
@@ -65,6 +67,8 @@
*/
boolean onQuickInteractionStart(T activity, boolean activityVisible);
+ float getTranslationYForQuickScrub(T activity);
+
void executeOnWindowAvailable(T activity, Runnable action);
void onTransitionCancelled(T activity, boolean activityVisible);
@@ -118,6 +122,13 @@
}
@Override
+ public float getTranslationYForQuickScrub(Launcher activity) {
+ LauncherRecentsView recentsView = activity.getOverviewPanel();
+ float transYFactor = FAST_OVERVIEW.getOverviewScaleAndTranslationYFactor(activity)[1];
+ return recentsView.computeTranslationYForFactor(transYFactor);
+ }
+
+ @Override
public void executeOnWindowAvailable(Launcher activity, Runnable action) {
if (activity.getWorkspace().runOnOverlayHidden(action)) {
// Notify the activity that qiuckscrub has started
@@ -147,6 +158,7 @@
public void onSwipeUpComplete(Launcher activity) {
// Re apply state in case we did something funky during the transition.
activity.getStateManager().reapplyState();
+ DiscoveryBounce.showForOverviewIfNeeded(activity);
}
@Override
@@ -276,6 +288,11 @@
}
@Override
+ public float getTranslationYForQuickScrub(RecentsActivity activity) {
+ return 0;
+ }
+
+ @Override
public void executeOnWindowAvailable(RecentsActivity activity, Runnable action) {
action.run();
}
diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
index 0185ab9..31bead1 100644
--- a/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -172,7 +172,8 @@
}
final TaskView taskView = (TaskView) v;
- RemoteAnimationRunnerCompat runner = new LauncherAnimationRunner(mUiHandler) {
+ RemoteAnimationRunnerCompat runner = new LauncherAnimationRunner(mUiHandler,
+ true /* startAtFrontOfQueue */) {
@Override
public void onCreateAnimation(RemoteAnimationTargetCompat[] targetCompats,
@@ -226,6 +227,14 @@
}
@Override
+ protected void onStop() {
+ super.onStop();
+
+ // Workaround for b/78520668, explicitly trim memory once UI is hidden
+ UiFactory.onTrimMemory(this, TRIM_MEMORY_UI_HIDDEN);
+ }
+
+ @Override
public void onTrimMemory(int level) {
super.onTrimMemory(level);
UiFactory.onTrimMemory(this, level);
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java b/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java
index ebe2311..4ba9e02 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java
@@ -115,4 +115,15 @@
}
});
}
+
+ public void hideCurrentInputMethod() {
+ BackgroundExecutor.get().submit(() -> {
+ synchronized (this) {
+ TraceHelper.partitionSection("RecentsController", "Hiding currentinput method");
+ if (controller != null) {
+ controller.hideCurrentInputMethod();
+ }
+ }
+ });
+ }
}
diff --git a/quickstep/src/com/android/quickstep/TaskSystemShortcut.java b/quickstep/src/com/android/quickstep/TaskSystemShortcut.java
index e3f6543..a82c679 100644
--- a/quickstep/src/com/android/quickstep/TaskSystemShortcut.java
+++ b/quickstep/src/com/android/quickstep/TaskSystemShortcut.java
@@ -150,15 +150,6 @@
}
};
- final OnPreDrawListener preDrawListener = new OnPreDrawListener() {
- @Override
- public boolean onPreDraw() {
- taskView.getViewTreeObserver().removeOnPreDrawListener(this);
- WindowManagerWrapper.getInstance().endProlongedAnimations();
- return true;
- }
- };
-
AbstractFloatingView.closeOpenViews(activity, true,
AbstractFloatingView.TYPE_ALL & ~AbstractFloatingView.TYPE_REBIND_SAFE);
@@ -182,7 +173,6 @@
// afterwards
recentsView.addIgnoreResetTask(taskView);
taskView.setAlpha(0f);
- taskView.getViewTreeObserver().addOnPreDrawListener(preDrawListener);
};
final int[] position = new int[2];
diff --git a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
index 25539aa..b8be6b8 100644
--- a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
@@ -451,41 +451,24 @@
}
}
- if (mLauncherTransitionController != null) {
- Runnable runOnUi = () -> {
- if (mLauncherTransitionController == null) {
- return;
- }
- mLauncherTransitionController.setPlayFraction(shift);
-
- // Make sure the window follows the first task if it moves, e.g. during quick scrub.
- View firstTask = mRecentsView.getPageAt(0);
- // The first task may be null if we are swiping up from a task that does not
- // appear in the list (ie. the assistant)
- if (firstTask != null) {
- int scrollForFirstTask = mRecentsView.getScrollForPage(0);
- int offsetFromFirstTask = (scrollForFirstTask - mRecentsView.getScrollX());
- mClipAnimationHelper.offsetTarget(firstTask.getScaleX(),
- offsetFromFirstTask + firstTask.getTranslationX(),
- mRecentsView.getTranslationY());
- }
- if (mRecentsAnimationWrapper.controller != null) {
- // TODO: This logic is spartanic!
- boolean passedThreshold = shift > 0.12f;
- mRecentsAnimationWrapper.setAnimationTargetsBehindSystemBars(!passedThreshold);
- if (mActivityControlHelper.shouldMinimizeSplitScreen()) {
- mRecentsAnimationWrapper
- .setSplitScreenMinimizedForTransaction(passedThreshold);
- }
- }
- };
- if (Looper.getMainLooper() == Looper.myLooper()) {
- runOnUi.run();
- } else {
- // The fling operation completed even before the launcher was drawn
- mMainExecutor.execute(runOnUi);
+ if (mRecentsAnimationWrapper.controller != null) {
+ // TODO: This logic is spartanic!
+ boolean passedThreshold = shift > 0.12f;
+ mRecentsAnimationWrapper.setAnimationTargetsBehindSystemBars(!passedThreshold);
+ if (mActivityControlHelper.shouldMinimizeSplitScreen()) {
+ mRecentsAnimationWrapper
+ .setSplitScreenMinimizedForTransaction(passedThreshold);
}
}
+
+ mMainExecutor.execute(this::updateFinalShiftUi);
+ }
+
+ private void updateFinalShiftUi() {
+ if (mLauncherTransitionController == null) {
+ return;
+ }
+ mLauncherTransitionController.setPlayFraction(mCurrentShift.value);
}
public void onRecentsAnimationStart(RecentsAnimationControllerCompat controller,
@@ -532,6 +515,7 @@
notifyGestureStartedAsync();
setStateOnUiThread(STATE_GESTURE_STARTED);
mGestureStarted = true;
+ mRecentsAnimationWrapper.hideCurrentInputMethod();
mRecentsAnimationWrapper.enableInputConsumer();
ActivityManagerWrapper.getInstance().closeSystemWindows(
CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
@@ -694,8 +678,6 @@
// If we haven't posted the transition end runnable, run it now
finishTransitionRunnable.run();
}
- RecentsModel.getInstance(mContext).onOverviewShown(false, TAG);
- doLogGesture(true /* toLauncher */);
}
private void setupLauncherUiAfterSwipeUpAnimation() {
@@ -707,18 +689,40 @@
// Animate the first icon.
mRecentsView.setFirstTaskIconScaledDown(false /* isScaledDown */, true /* animate */);
-
mRecentsView.setSwipeDownShouldLaunchApp(true);
+ RecentsModel.getInstance(mContext).onOverviewShown(false, TAG);
+
+ doLogGesture(true /* toLauncher */);
reset();
}
private void onQuickScrubStart() {
- mActivityControlHelper.onQuickInteractionStart(mActivity, mWasLauncherAlreadyVisible);
+ if (mLauncherTransitionController != null) {
+ mLauncherTransitionController.getAnimationPlayer().end();
+ mLauncherTransitionController = null;
+ }
+
+ mActivityControlHelper.onQuickInteractionStart(mActivity, false);
mQuickScrubController.onQuickScrubStart(false);
// Inform the last progress in case we skipped before.
mQuickScrubController.onQuickScrubProgress(mCurrentQuickScrubProgress);
+
+ // Make sure the window follows the first task if it moves, e.g. during quick scrub.
+ TaskView firstTask = mRecentsView.getPageAt(0);
+ // The first task may be null if we are swiping up from a task that does not
+ // appear in the list (i.e. the assistant)
+ if (firstTask != null) {
+ int scrollForFirstTask = mRecentsView.getScrollForPage(0);
+ int scrollForSecondTask = mRecentsView.getChildCount() > 1
+ ? mRecentsView.getScrollForPage(1) : scrollForFirstTask;
+ int offsetFromFirstTask = scrollForFirstTask - scrollForSecondTask;
+ float interpolation = offsetFromFirstTask / (mRecentsView.getWidth() / 2);
+ mClipAnimationHelper.offsetTarget(
+ firstTask.getCurveScaleForInterpolation(interpolation), offsetFromFirstTask,
+ mActivityControlHelper.getTranslationYForQuickScrub(mActivity));
+ }
}
private void onFinishedTransitionToQuickScrub() {
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
index a4d3a50..fb4aa02 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
@@ -35,7 +35,6 @@
public FallbackRecentsView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setOverviewStateEnabled(true);
- updateEmptyMessage();
}
@Override
diff --git a/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java b/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java
index fb7a850..057e0c4 100644
--- a/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java
+++ b/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java
@@ -15,9 +15,13 @@
*/
package com.android.quickstep.util;
+import static com.android.launcher3.anim.Interpolators.LINEAR;
+import static com.android.launcher3.anim.Interpolators.SCROLL;
+
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Matrix.ScaleToFit;
+import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
@@ -46,8 +50,8 @@
private final RectF mSourceRect = new RectF();
// The bounds of the task view in launcher window coordinates
private final RectF mTargetRect = new RectF();
- // Doesn't change after initialized, used as an anchor when changing mTargetRect
- private final RectF mInitialTargetRect = new RectF();
+ // Set when the final window destination is changed, such as offsetting for quick scrub
+ private final PointF mTargetOffset = new PointF();
// The insets to be used for clipping the app window, which can be larger than mSourceInsets
// if the aspect ratio of the target is smaller than the aspect ratio of the source rect. In
// app window coordinates.
@@ -60,6 +64,9 @@
private final Rect mClipRect = new Rect();
private final RectFEvaluator mRectFEvaluator = new RectFEvaluator();
private final Matrix mTmpMatrix = new Matrix();
+ private final RectF mTmpRectF = new RectF();
+
+ private float mTargetScale = 1f;
public void updateSource(Rect homeStackBounds, RemoteAnimationTargetCompat target) {
mHomeStackBounds.set(homeStackBounds);
@@ -78,8 +85,6 @@
mTargetRect.offset(mHomeStackBounds.left - mSourceStackBounds.left,
mHomeStackBounds.top - mSourceStackBounds.top);
- mInitialTargetRect.set(mTargetRect);
-
// Calculate the clip based on the target rect (since the content insets and the
// launcher insets may differ, so the aspect ratio of the target rect can differ
// from the source rect. The difference between the target rect (scaled to the
@@ -98,10 +103,14 @@
public void applyTransform(RemoteAnimationTargetSet targetSet, float progress) {
RectF currentRect;
- synchronized (mTargetRect) {
- currentRect = mRectFEvaluator.evaluate(progress, mSourceRect, mTargetRect);
+ mTmpRectF.set(mTargetRect);
+ Utilities.scaleRectFAboutCenter(mTmpRectF, mTargetScale);
+ currentRect = mRectFEvaluator.evaluate(progress, mSourceRect, mTmpRectF);
+
+ synchronized (mTargetOffset) {
// Stay lined up with the center of the target, since it moves for quick scrub.
- currentRect.offset(mTargetRect.centerX() - currentRect.centerX(), 0);
+ currentRect.offset(mTargetOffset.x * SCROLL.getInterpolation(progress),
+ mTargetOffset.y * LINEAR.getInterpolation(progress));
}
mClipRect.left = (int) (mSourceWindowClipInsets.left * progress);
@@ -131,10 +140,9 @@
}
public void offsetTarget(float scale, float offsetX, float offsetY) {
- synchronized (mTargetRect) {
- mTargetRect.set(mInitialTargetRect);
- Utilities.scaleRectFAboutCenter(mTargetRect, scale);
- mTargetRect.offset(offsetX, offsetY);
+ synchronized (mTargetOffset) {
+ mTargetScale = scale;
+ mTargetOffset.set(offsetX, offsetY);
}
}
@@ -187,14 +195,11 @@
}
public void drawForProgress(TaskThumbnailView ttv, Canvas canvas, float progress) {
- RectF currentRect;
- synchronized (mTargetRect) {
- currentRect = mRectFEvaluator.evaluate(progress, mSourceRect, mTargetRect);
- }
-
+ RectF currentRect = mRectFEvaluator.evaluate(progress, mSourceRect, mTargetRect);
canvas.translate(mSourceStackBounds.left - mHomeStackBounds.left,
mSourceStackBounds.top - mHomeStackBounds.top);
mTmpMatrix.setRectToRect(mTargetRect, currentRect, ScaleToFit.FILL);
+
canvas.concat(mTmpMatrix);
canvas.translate(mTargetRect.left, mTargetRect.top);
diff --git a/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java b/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java
index 7ee16c1..dfe1984 100644
--- a/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java
+++ b/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java
@@ -31,7 +31,8 @@
AnimatorSet createWindowAnimation(RemoteAnimationTargetCompat[] targets);
default ActivityOptions toActivityOptions(Handler handler, long duration) {
- LauncherAnimationRunner runner = new LauncherAnimationRunner(handler) {
+ LauncherAnimationRunner runner = new LauncherAnimationRunner(handler,
+ false /* startAtFrontOfQueue */) {
@Override
public void onCreateAnimation(RemoteAnimationTargetCompat[] targetCompats,
diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
index 06e5311..d69beb6 100644
--- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -86,7 +86,11 @@
public void setTranslationYFactor(float translationFactor) {
mTranslationYFactor = translationFactor;
- setTranslationY(mTranslationYFactor * (getPaddingBottom() - getPaddingTop()));
+ setTranslationY(computeTranslationYForFactor(mTranslationYFactor));
+ }
+
+ public float computeTranslationYForFactor(float translationYFactor) {
+ return translationYFactor * (getPaddingBottom() - getPaddingTop());
}
@Override
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index a2a93d7..9ab1e04 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -214,6 +214,7 @@
mEmptyMessagePadding = getResources()
.getDimensionPixelSize(R.dimen.recents_empty_message_text_padding);
setWillNotDraw(false);
+ updateEmptyMessage();
}
public boolean isRtl() {
@@ -298,6 +299,56 @@
}
}
+ private float calculateClearAllButtonAlpha() {
+ if (mClearAllButton.getVisibility() != View.VISIBLE || getChildCount() == 0) return 0;
+
+ // Current visible coordinate of the right border of the rightmost task.
+ final int carouselCurrentRight = getChildAt(getChildCount() - 1).getRight() - getScrollX();
+
+ // As the right border (let's call it E aka carouselCurrentRight) of the carousel moves
+ // over Clear all button, the button changes trasparency.
+ // leftOfAlphaChange < rightOfAlphaChange; these are the points of the 100% and 0% alpha
+ // correspondingly. Alpha changes linearly between 100% and 0% as E moves through this
+ // range. It doesn't change outside of the range.
+
+ // Once E hits the left border of the Clear-All button, the whole button is uncovered,
+ // and it should have alpha 100%.
+ final float leftOfAlphaChange = mClearAllButton.getX();
+
+ // The rightmost possible right coordinate of the carousel.
+ final int carouselMotionLimit = getScrollForPage(getChildCount() - 1) + getWidth()
+ - getPaddingRight() - mInsets.right;
+
+ // The carousel might not be able to ever cover a part of the Clear-all button. Then
+ // always show the button as 100%. Technically, this check also prevents dividing by zero
+ // or a negative number when calculating the transparency ratio below.
+ if (carouselMotionLimit <= leftOfAlphaChange) return 1;
+
+ // If the carousel is able to cover the button completely, we make the button completely
+ // transparent when E hits the right border of the button.
+ // Or, the carousel may not be able to move that far to the right so it completely covers
+ // the button. Then we set the rightmost possible position of the carousel as the point
+ // where the button reaches 0 alpha.
+ final float rightOfAlphaChange = Math.min(
+ mClearAllButton.getX() + mClearAllButton.getWidth(), carouselMotionLimit);
+
+ return Utilities.boundToRange(
+ (rightOfAlphaChange - carouselCurrentRight) /
+ (rightOfAlphaChange - leftOfAlphaChange), 0, 1);
+ }
+
+ private void updateClearAllButtonAlpha() {
+ if (mClearAllButton != null) {
+ mClearAllButton.setAlpha(calculateClearAllButtonAlpha() * mContentAlpha);
+ }
+ }
+
+ @Override
+ protected void onScrollChanged(int l, int t, int oldl, int oldt) {
+ super.onScrollChanged(l, t, oldl, oldt);
+ updateClearAllButtonAlpha();
+ }
+
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (DEBUG_SHOW_CLEAR_ALL_BUTTON && ev.getAction() == MotionEvent.ACTION_DOWN
@@ -662,8 +713,23 @@
mIgnoreResetTaskViews.remove(taskView);
}
+ private void addDismissedTaskAnimations(View taskView, AnimatorSet anim, long duration) {
+ addAnim(ObjectAnimator.ofFloat(taskView, ALPHA, 0), duration, ACCEL_2, anim);
+ addAnim(ObjectAnimator.ofFloat(taskView, TRANSLATION_Y, -taskView.getHeight()),
+ duration, LINEAR, anim);
+ }
+
+ private void removeTask(Task task, PendingAnimation.OnEndListener onEndListener) {
+ if (task != null) {
+ ActivityManagerWrapper.getInstance().removeTask(task.key.id);
+ mActivity.getUserEventDispatcher().logTaskLaunchOrDismiss(
+ onEndListener.logAction, Direction.UP,
+ TaskUtils.getComponentKeyForTask(task.key));
+ }
+ }
+
public PendingAnimation createTaskDismissAnimation(TaskView taskView, boolean animateTaskView,
- boolean removeTask, long duration) {
+ boolean shouldRemoveTask, long duration) {
if (FeatureFlags.IS_DOGFOOD_BUILD && mPendingAnimation != null) {
throw new IllegalStateException("Another pending animation is still running");
}
@@ -695,9 +761,7 @@
View child = getChildAt(i);
if (child == taskView) {
if (animateTaskView) {
- addAnim(ObjectAnimator.ofFloat(taskView, ALPHA, 0), duration, ACCEL_2, anim);
- addAnim(ObjectAnimator.ofFloat(taskView, TRANSLATION_Y, -taskView.getHeight()),
- duration, LINEAR, anim);
+ addDismissedTaskAnimations(taskView, anim, duration);
}
} else {
// If we just take newScroll - oldScroll, everything to the right of dragged task
@@ -742,14 +806,8 @@
mPendingAnimation = pendingAnimation;
mPendingAnimation.addEndListener((onEndListener) -> {
if (onEndListener.isSuccess) {
- if (removeTask) {
- Task task = taskView.getTask();
- if (task != null) {
- ActivityManagerWrapper.getInstance().removeTask(task.key.id);
- mActivity.getUserEventDispatcher().logTaskLaunchOrDismiss(
- onEndListener.logAction, Direction.UP,
- TaskUtils.getComponentKeyForTask(task.key));
- }
+ if (shouldRemoveTask) {
+ removeTask(taskView.getTask(), onEndListener);
}
int pageToSnapTo = mCurrentPage;
if (draggedIndex < pageToSnapTo) {
@@ -768,6 +826,33 @@
return pendingAnimation;
}
+ public PendingAnimation createAllTasksDismissAnimation(long duration) {
+ if (FeatureFlags.IS_DOGFOOD_BUILD && mPendingAnimation != null) {
+ throw new IllegalStateException("Another pending animation is still running");
+ }
+ AnimatorSet anim = new AnimatorSet();
+ PendingAnimation pendingAnimation = new PendingAnimation(anim);
+
+ int count = getChildCount();
+ for (int i = 0; i < count; i++) {
+ addDismissedTaskAnimations(getChildAt(i), anim, duration);
+ }
+
+ mPendingAnimation = pendingAnimation;
+ mPendingAnimation.addEndListener((onEndListener) -> {
+ if (onEndListener.isSuccess) {
+ while (getChildCount() != 0) {
+ TaskView taskView = getPageAt(getChildCount() - 1);
+ removeTask(taskView.getTask(), onEndListener);
+ removeView(taskView);
+ }
+ onAllTasksRemoved();
+ }
+ mPendingAnimation = null;
+ });
+ return pendingAnimation;
+ }
+
private static void addAnim(ObjectAnimator anim, long duration,
TimeInterpolator interpolator, AnimatorSet set) {
anim.setDuration(duration).setInterpolator(interpolator);
@@ -791,9 +876,7 @@
}
}
- public void dismissTask(TaskView taskView, boolean animateTaskView, boolean removeTask) {
- PendingAnimation pendingAnim = createTaskDismissAnimation(taskView, animateTaskView,
- removeTask, DISMISS_TASK_DURATION);
+ private void runDismissAnimation(PendingAnimation pendingAnim) {
AnimatorPlaybackController controller = AnimatorPlaybackController.wrap(
pendingAnim.anim, DISMISS_TASK_DURATION);
controller.dispatchOnStart();
@@ -802,6 +885,15 @@
controller.start();
}
+ public void dismissTask(TaskView taskView, boolean animateTaskView, boolean removeTask) {
+ runDismissAnimation(createTaskDismissAnimation(taskView, animateTaskView, removeTask,
+ DISMISS_TASK_DURATION));
+ }
+
+ public void dismissAllTasks() {
+ runDismissAnimation(createAllTasksDismissAnimation(DISMISS_TASK_DURATION));
+ }
+
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
@@ -852,6 +944,7 @@
int alphaInt = Math.round(alpha * 255);
mEmptyMessagePaint.setAlpha(alphaInt);
mEmptyIcon.setAlpha(alphaInt);
+ updateClearAllButtonAlpha();
}
public void setAdjacentScale(float adjacentScale) {
@@ -936,6 +1029,7 @@
mEmptyTextLayout = null;
mLastMeasureSize.set(getWidth(), getHeight());
}
+ updateClearAllButtonVisibility();
if (!mShowEmptyMessage) return;
@@ -1106,16 +1200,6 @@
return "";
}
- public void dismissAllTasks() {
- for (int i = 0; i < getChildCount(); ++i) {
- Task task = getPageAt(i).getTask();
- if (task != null) {
- ActivityManagerWrapper.getInstance().removeTask(task.key.id);
- }
- }
- onAllTasksRemoved();
- }
-
@Override
protected int computeMaxScrollX() {
if (!DEBUG_SHOW_CLEAR_ALL_BUTTON || getChildCount() == 0) {
@@ -1128,8 +1212,10 @@
}
private void updateClearAllButtonVisibility() {
+ if (mClearAllButton == null) return;
mClearAllButton.setVisibility(
!DEBUG_SHOW_CLEAR_ALL_BUTTON || mShowEmptyMessage ? GONE : VISIBLE);
+ updateClearAllButtonAlpha();
}
public void setClearAllButton(View clearAllButton) {
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index b32d8dd..8c1076a 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -219,11 +219,20 @@
mSnapshotView.setDimAlpha(mCurveDimAlpha);
}
- mCurveScale = 1 - curveInterpolation * EDGE_SCALE_DOWN_FACTOR;
+ mCurveScale = getCurveScaleForCurveInterpolation(curveInterpolation);
setScaleX(mCurveScale);
setScaleY(mCurveScale);
}
+ public float getCurveScaleForInterpolation(float linearInterpolation) {
+ float curveInterpolation = CURVE_INTERPOLATOR.getInterpolation(linearInterpolation);
+ return getCurveScaleForCurveInterpolation(curveInterpolation);
+ }
+
+ private float getCurveScaleForCurveInterpolation(float curveInterpolation) {
+ return 1 - curveInterpolation * EDGE_SCALE_DOWN_FACTOR;
+ }
+
public float getCurveScale() {
return mCurveScale;
}
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 5e06d92..1285a2b 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -737,6 +737,8 @@
NotificationListener.removeNotificationsChangedListener();
getStateManager().moveToRestState();
+ // Workaround for b/78520668, explicitly trim memory once UI is hidden
+ UiFactory.onTrimMemory(this, TRIM_MEMORY_UI_HIDDEN);
}
@Override
@@ -787,7 +789,7 @@
// Refresh shortcuts if the permission changed.
mModel.refreshShortcutsIfRequired();
- DiscoveryBounce.showIfNeeded(this);
+ DiscoveryBounce.showForHomeIfNeeded(this);
if (mLauncherCallbacks != null) {
mLauncherCallbacks.onResume();
}
@@ -1278,7 +1280,7 @@
}
if (mLauncherCallbacks != null) {
- mLauncherCallbacks.onHomeIntent();
+ mLauncherCallbacks.onHomeIntent(internalStateHandled);
}
}
diff --git a/src/com/android/launcher3/LauncherCallbacks.java b/src/com/android/launcher3/LauncherCallbacks.java
index 35faaea..6aef658 100644
--- a/src/com/android/launcher3/LauncherCallbacks.java
+++ b/src/com/android/launcher3/LauncherCallbacks.java
@@ -50,7 +50,7 @@
void onAttachedToWindow();
void onDetachedFromWindow();
void dump(String prefix, FileDescriptor fd, PrintWriter w, String[] args);
- void onHomeIntent();
+ void onHomeIntent(boolean internalStateHandled);
boolean handleBackPressed();
void onTrimMemory(int level);
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 7ecafdb..d2a126f 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -477,7 +477,7 @@
super.onViewAdded(child);
}
- boolean isTouchActive() {
+ public boolean isTouchActive() {
return mTouchState != TOUCH_STATE_REST;
}
@@ -974,19 +974,9 @@
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
- switch (ev.getAction() & MotionEvent.ACTION_MASK) {
- case MotionEvent.ACTION_DOWN:
+ if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
mXDown = ev.getX();
mYDown = ev.getY();
- break;
- case MotionEvent.ACTION_POINTER_UP:
- case MotionEvent.ACTION_UP:
- if (mTouchState == TOUCH_STATE_REST) {
- final CellLayout currentPage = (CellLayout) getChildAt(mCurrentPage);
- if (currentPage != null) {
- onWallpaperTap(ev);
- }
- }
}
return super.onInterceptTouchEvent(ev);
}
@@ -1443,7 +1433,7 @@
}
}
- protected void onWallpaperTap(MotionEvent ev) {
+ public void onWallpaperTap(MotionEvent ev) {
final int[] position = mTempXY;
getLocationOnScreen(position);
diff --git a/src/com/android/launcher3/allapps/DiscoveryBounce.java b/src/com/android/launcher3/allapps/DiscoveryBounce.java
index fddafb2..f73916c 100644
--- a/src/com/android/launcher3/allapps/DiscoveryBounce.java
+++ b/src/com/android/launcher3/allapps/DiscoveryBounce.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * 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.
@@ -17,35 +17,44 @@
package com.android.launcher3.allapps;
import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.LauncherState.OVERVIEW;
import android.animation.Animator;
import android.animation.AnimatorInflater;
import android.animation.AnimatorListenerAdapter;
+import android.animation.Keyframe;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.animation.TimeInterpolator;
import android.app.ActivityManager;
-import android.content.Context;
+import android.os.Handler;
import android.view.MotionEvent;
+import android.view.animation.PathInterpolator;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.compat.UserManagerCompat;
+import com.android.launcher3.states.InternalStateHandler;
/**
- * Floating view responsible for showing discovery bounce animation
+ * Abstract base class of floating view responsible for showing discovery bounce animation
*/
public class DiscoveryBounce extends AbstractFloatingView {
- public static final String APPS_VIEW_SHOWN = "launcher.apps_view_shown";
+ private static final long DELAY_MS = 200;
+
+ public static final String HOME_BOUNCE_SEEN = "launcher.apps_view_shown";
+ public static final String SHELF_BOUNCE_SEEN = "launcher.shelf_bounce_seen";
private final Launcher mLauncher;
private final Animator mDiscoBounceAnimation;
- public DiscoveryBounce(Launcher launcher) {
+ public DiscoveryBounce(Launcher launcher, Animator animator) {
super(launcher, null);
mLauncher = launcher;
- mDiscoBounceAnimation = AnimatorInflater.loadAnimator(mLauncher,
- R.animator.discovery_bounce);
+ mDiscoBounceAnimation = animator;
AllAppsTransitionController controller = mLauncher.getAllAppsController();
mDiscoBounceAnimation.setTarget(controller);
mDiscoBounceAnimation.addListener(controller.getProgressAnimatorListener());
@@ -96,16 +105,72 @@
return (type & TYPE_ON_BOARD_POPUP) != 0;
}
- public static void showIfNeeded(Launcher launcher) {
+ public static void showForHomeIfNeeded(Launcher launcher) {
+ showForHomeIfNeeded(launcher, true);
+ }
+
+ private static void showForHomeIfNeeded(Launcher launcher, boolean withDelay) {
if (!launcher.isInState(NORMAL)
- || launcher.getSharedPrefs().getBoolean(APPS_VIEW_SHOWN, false)
+ || launcher.getSharedPrefs().getBoolean(HOME_BOUNCE_SEEN, false)
|| AbstractFloatingView.getTopOpenView(launcher) != null
|| UserManagerCompat.getInstance(launcher).isDemoUser()
|| ActivityManager.isRunningInTestHarness()) {
return;
}
- DiscoveryBounce view = new DiscoveryBounce(launcher);
+ if (withDelay) {
+ new Handler().postDelayed(() -> showForHomeIfNeeded(launcher, false), DELAY_MS);
+ return;
+ }
+
+ DiscoveryBounce view = new DiscoveryBounce(launcher,
+ AnimatorInflater.loadAnimator(launcher, R.animator.discovery_bounce));
+ view.mIsOpen = true;
+ launcher.getDragLayer().addView(view);
+ }
+
+ public static void showForOverviewIfNeeded(Launcher launcher) {
+ showForOverviewIfNeeded(launcher, true);
+ }
+
+ private static void showForOverviewIfNeeded(Launcher launcher, boolean withDelay) {
+ if (!launcher.isInState(OVERVIEW)
+ || !launcher.hasBeenResumed()
+ || launcher.isForceInvisible()
+ || launcher.getDeviceProfile().isVerticalBarLayout()
+ || launcher.getSharedPrefs().getBoolean(SHELF_BOUNCE_SEEN, false)
+ || UserManagerCompat.getInstance(launcher).isDemoUser()
+ || ActivityManager.isRunningInTestHarness()) {
+ return;
+ }
+
+ if (withDelay) {
+ new Handler().postDelayed(() -> showForOverviewIfNeeded(launcher, false), DELAY_MS);
+ return;
+ } else if (InternalStateHandler.hasPending()
+ || AbstractFloatingView.getTopOpenView(launcher) != null) {
+ // TODO: Move these checks to the top and call this method after invalidate handler.
+ return;
+ }
+
+ float verticalProgress = OVERVIEW.getVerticalProgress(launcher);
+
+ TimeInterpolator pathInterpolator = new PathInterpolator(0.35f, 0, 0.5f, 1);
+ Keyframe keyframe3 = Keyframe.ofFloat(0.423f, verticalProgress - (1 - 0.9438f));
+ keyframe3.setInterpolator(pathInterpolator);
+ Keyframe keyframe4 = Keyframe.ofFloat(0.654f, verticalProgress);
+ keyframe4.setInterpolator(pathInterpolator);
+
+ PropertyValuesHolder propertyValuesHolder = PropertyValuesHolder.ofKeyframe("progress",
+ Keyframe.ofFloat(0, verticalProgress),
+ Keyframe.ofFloat(0.346f, verticalProgress), keyframe3, keyframe4,
+ Keyframe.ofFloat(1f, verticalProgress));
+ ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(null,
+ new PropertyValuesHolder[]{propertyValuesHolder});
+ animator.setDuration(2166);
+ animator.setRepeatCount(5);
+
+ DiscoveryBounce view = new DiscoveryBounce(launcher, animator);
view.mIsOpen = true;
launcher.getDragLayer().addView(view);
}
diff --git a/src/com/android/launcher3/states/InternalStateHandler.java b/src/com/android/launcher3/states/InternalStateHandler.java
index 0a2c3e4..cf7c6ba 100644
--- a/src/com/android/launcher3/states/InternalStateHandler.java
+++ b/src/com/android/launcher3/states/InternalStateHandler.java
@@ -60,6 +60,10 @@
return sScheduler.clearReference(this);
}
+ public static boolean hasPending() {
+ return sScheduler.hasPending();
+ }
+
public static boolean handleCreate(Launcher launcher, Intent intent) {
return handleIntent(launcher, intent, false, false);
}
@@ -132,5 +136,9 @@
}
return false;
}
+
+ public boolean hasPending() {
+ return mPendingHandler.get() != null;
+ }
}
}
\ No newline at end of file
diff --git a/src/com/android/launcher3/touch/WorkspaceTouchListener.java b/src/com/android/launcher3/touch/WorkspaceTouchListener.java
index 23f55aa..f59f14e 100644
--- a/src/com/android/launcher3/touch/WorkspaceTouchListener.java
+++ b/src/com/android/launcher3/touch/WorkspaceTouchListener.java
@@ -17,6 +17,7 @@
import static android.view.MotionEvent.ACTION_CANCEL;
import static android.view.MotionEvent.ACTION_DOWN;
+import static android.view.MotionEvent.ACTION_POINTER_UP;
import static android.view.MotionEvent.ACTION_UP;
import static android.view.ViewConfiguration.getLongPressTimeout;
@@ -30,6 +31,7 @@
import android.view.View.OnTouchListener;
import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.CellLayout;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.Workspace;
@@ -71,8 +73,7 @@
int action = ev.getActionMasked();
if (action == ACTION_DOWN) {
// Check if we can handle long press.
- boolean handleLongPress = AbstractFloatingView.getTopOpenView(mLauncher) == null
- && mLauncher.isInState(NORMAL);
+ boolean handleLongPress = canHandleLongPress();
if (handleLongPress) {
// Check if the event is not near the edges
@@ -122,12 +123,28 @@
// We don't want to handle touch, let workspace handle it as usual.
result = false;
}
+
+ if (action == ACTION_UP || action == ACTION_POINTER_UP) {
+ if (!mWorkspace.isTouchActive()) {
+ final CellLayout currentPage =
+ (CellLayout) mWorkspace.getChildAt(mWorkspace.getCurrentPage());
+ if (currentPage != null) {
+ mWorkspace.onWallpaperTap(ev);
+ }
+ }
+ }
+
if (action == ACTION_UP || action == ACTION_CANCEL) {
cancelLongPress();
}
return result;
}
+ private boolean canHandleLongPress() {
+ return AbstractFloatingView.getTopOpenView(mLauncher) == null
+ && mLauncher.isInState(NORMAL);
+ }
+
private void cancelLongPress() {
mWorkspace.removeCallbacks(this);
mLongPressState = STATE_CANCELLED;
@@ -136,15 +153,19 @@
@Override
public void run() {
if (mLongPressState == STATE_REQUESTED) {
- mLongPressState = STATE_PENDING_PARENT_INFORM;
- mWorkspace.getParent().requestDisallowInterceptTouchEvent(true);
+ if (canHandleLongPress()) {
+ mLongPressState = STATE_PENDING_PARENT_INFORM;
+ mWorkspace.getParent().requestDisallowInterceptTouchEvent(true);
- mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,
- HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
- mLauncher.getUserEventDispatcher().logActionOnContainer(Action.Touch.LONGPRESS,
- Action.Direction.NONE, ContainerType.WORKSPACE,
- mWorkspace.getCurrentPage());
- OptionsPopupView.showDefaultOptions(mLauncher, mTouchDownPoint.x, mTouchDownPoint.y);
+ mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,
+ HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
+ mLauncher.getUserEventDispatcher().logActionOnContainer(Action.Touch.LONGPRESS,
+ Action.Direction.NONE, ContainerType.WORKSPACE,
+ mWorkspace.getCurrentPage());
+ OptionsPopupView.showDefaultOptions(mLauncher, mTouchDownPoint.x, mTouchDownPoint.y);
+ } else {
+ cancelLongPress();
+ }
}
}
}
diff --git a/src/com/android/launcher3/views/SpringRelativeLayout.java b/src/com/android/launcher3/views/SpringRelativeLayout.java
index 090b3e6..a508191 100644
--- a/src/com/android/launcher3/views/SpringRelativeLayout.java
+++ b/src/com/android/launcher3/views/SpringRelativeLayout.java
@@ -24,7 +24,6 @@
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.EdgeEffectFactory;
import android.util.AttributeSet;
-import android.util.Log;
import android.util.SparseBooleanArray;
import android.view.View;
import android.widget.EdgeEffect;
@@ -58,6 +57,7 @@
private final SpringAnimation mSpring;
private float mDampedScrollShift = 0;
+ private SpringEdgeEffect mActiveEdge;
public SpringRelativeLayout(Context context) {
this(context, null);
@@ -90,6 +90,13 @@
return super.drawChild(canvas, child, drawingTime);
}
+ private void setActiveEdge(SpringEdgeEffect edge) {
+ if (mActiveEdge != edge && mActiveEdge != null) {
+ mActiveEdge.mDistance = 0;
+ }
+ mActiveEdge = edge;
+ }
+
private void setDampedScrollShift(float shift) {
if (shift != mDampedScrollShift) {
mDampedScrollShift = shift;
@@ -144,6 +151,7 @@
@Override
public void onPull(float deltaDistance, float displacement) {
+ setActiveEdge(this);
mDistance += deltaDistance * (mVelocityMultiplier / 3f);
setDampedScrollShift(mDistance * getHeight());
}
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsState.java b/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsState.java
index 49a9dc7..6366b2d 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsState.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsState.java
@@ -16,7 +16,7 @@
package com.android.launcher3.uioverrides;
import static com.android.launcher3.LauncherAnimUtils.ALL_APPS_TRANSITION_MS;
-import static com.android.launcher3.allapps.DiscoveryBounce.APPS_VIEW_SHOWN;
+import static com.android.launcher3.allapps.DiscoveryBounce.HOME_BOUNCE_SEEN;
import static com.android.launcher3.anim.Interpolators.DEACCEL_2;
import android.view.View;
@@ -49,8 +49,8 @@
@Override
public void onStateEnabled(Launcher launcher) {
- if (!launcher.getSharedPrefs().getBoolean(APPS_VIEW_SHOWN, false)) {
- launcher.getSharedPrefs().edit().putBoolean(APPS_VIEW_SHOWN, true).apply();
+ if (!launcher.getSharedPrefs().getBoolean(HOME_BOUNCE_SEEN, false)) {
+ launcher.getSharedPrefs().edit().putBoolean(HOME_BOUNCE_SEEN, true).apply();
}
AbstractFloatingView.closeAllOpenViews(launcher);
diff --git a/tests/AndroidManifest-common.xml b/tests/AndroidManifest-common.xml
index a54268a..af8b15c 100644
--- a/tests/AndroidManifest-common.xml
+++ b/tests/AndroidManifest-common.xml
@@ -18,8 +18,6 @@
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.launcher3.tests">
- <uses-sdk android:targetSdkVersion="25" android:minSdkVersion="21"/>
-
<application android:debuggable="true">
<uses-library android:name="android.test.runner" />