Merge "Fix issue with black flash when swiping up" into ub-launcher3-master
diff --git a/AndroidManifest-common.xml b/AndroidManifest-common.xml
index d7c16e6..979096c 100644
--- a/AndroidManifest-common.xml
+++ b/AndroidManifest-common.xml
@@ -153,6 +153,15 @@
android:readPermission="${packageName}.permission.READ_SETTINGS" />
<!--
+ The content provider for exposing various launcher grid options.
+ TODO: Add proper permissions
+ -->
+ <provider
+ android:name="com.android.launcher3.graphics.GridOptionsProvider"
+ android:authorities="${packageName}.grid_control"
+ android:exported="true" />
+
+ <!--
The settings activity. To extend point settings_fragment_name to appropriate fragment class
-->
<activity
diff --git a/go/quickstep/src/com/android/launcher3/uioverrides/RecentsUiFactory.java b/go/quickstep/src/com/android/launcher3/uioverrides/RecentsUiFactory.java
new file mode 100644
index 0000000..f2c9455
--- /dev/null
+++ b/go/quickstep/src/com/android/launcher3/uioverrides/RecentsUiFactory.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.uioverrides;
+
+import static android.view.View.VISIBLE;
+
+import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
+
+import android.view.View;
+
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherStateManager;
+import com.android.launcher3.LauncherStateManager.StateHandler;
+import com.android.launcher3.uioverrides.RecentsViewStateController;
+import com.android.launcher3.util.TouchController;
+
+/**
+ * Provides recents-related {@link UiFactory} logic and classes.
+ */
+public final class RecentsUiFactory {
+
+ // Scale recents takes before animating in
+ private static final float RECENTS_PREPARE_SCALE = 1.33f;
+
+ private RecentsUiFactory() {}
+
+ /**
+ * Creates and returns a touch controller for swiping recents tasks.
+ *
+ * @param launcher the launcher activity
+ * @return the touch controller for recents tasks
+ */
+ public static TouchController createTaskSwipeController(Launcher launcher) {
+ // We leave all input handling to the view itself.
+ return null;
+ }
+
+ /**
+ * Creates and returns the controller responsible for recents view state transitions.
+ *
+ * @param launcher the launcher activity
+ * @return state handler for recents
+ */
+ public static StateHandler createRecentsViewStateController(Launcher launcher) {
+ //TODO Override RecentsViewStateController on low RAM.
+ return new RecentsViewStateController(launcher);
+ }
+
+ /**
+ * Prepare the recents view to animate in.
+ *
+ * @param launcher the launcher activity
+ */
+ public static void prepareToShowRecents(Launcher launcher) {
+ View overview = launcher.getOverviewPanel();
+ if (overview.getVisibility() != VISIBLE) {
+ SCALE_PROPERTY.set(overview, RECENTS_PREPARE_SCALE);
+ }
+ }
+
+ /**
+ * Clean-up logic that occurs when recents is no longer in use/visible.
+ *
+ * @param launcher the launcher activity
+ */
+ public static void resetRecents(Launcher launcher) {}
+
+ /**
+ * Recents logic that triggers when launcher state changes or launcher activity stops/resumes.
+ *
+ * @param launcher the launcher activity
+ */
+ public static void onLauncherStateOrResumeChanged(Launcher launcher) {}
+}
diff --git a/quickstep/recents_ui_overrides/src/.keep b/quickstep/recents_ui_overrides/src/.keep
deleted file mode 100644
index e69de29..0000000
--- a/quickstep/recents_ui_overrides/src/.keep
+++ /dev/null
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java
new file mode 100644
index 0000000..f18f43c
--- /dev/null
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.uioverrides;
+
+import static android.view.View.VISIBLE;
+
+import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
+import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.LauncherState.OVERVIEW;
+
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherState;
+import com.android.launcher3.LauncherStateManager.StateHandler;
+import com.android.launcher3.anim.AnimatorPlaybackController;
+import com.android.launcher3.util.TouchController;
+import com.android.quickstep.views.RecentsView;
+
+/**
+ * Provides recents-related {@link UiFactory} logic and classes.
+ */
+public final class RecentsUiFactory {
+
+ // Scale recents takes before animating in
+ private static final float RECENTS_PREPARE_SCALE = 1.33f;
+
+ private RecentsUiFactory() {}
+
+ /**
+ * Creates and returns a touch controller for swiping recents tasks.
+ *
+ * @param launcher the launcher activity
+ * @return the touch controller for recents tasks
+ */
+ public static TouchController createTaskSwipeController(Launcher launcher) {
+ return new LauncherTaskViewController(launcher);
+ }
+
+ /**
+ * Creates and returns the controller responsible for recents view state transitions.
+ *
+ * @param launcher the launcher activity
+ * @return state handler for recents
+ */
+ public static StateHandler createRecentsViewStateController(Launcher launcher) {
+ return new RecentsViewStateController(launcher);
+ }
+
+ /**
+ * Prepare the recents view to animate in.
+ *
+ * @param launcher the launcher activity
+ */
+ public static void prepareToShowRecents(Launcher launcher) {
+ RecentsView overview = launcher.getOverviewPanel();
+ if (overview.getVisibility() != VISIBLE || overview.getContentAlpha() == 0) {
+ SCALE_PROPERTY.set(overview, RECENTS_PREPARE_SCALE);
+ }
+ }
+
+ /**
+ * Clean-up logic that occurs when recents is no longer in use/visible.
+ *
+ * @param launcher the launcher activity
+ */
+ public static void resetRecents(Launcher launcher) {
+ RecentsView recents = launcher.getOverviewPanel();
+ recents.reset();
+ }
+
+ /**
+ * Recents logic that triggers when launcher state changes or launcher activity stops/resumes.
+ *
+ * @param launcher the launcher activity
+ */
+ public static void onLauncherStateOrResumeChanged(Launcher launcher) {
+ LauncherState state = launcher.getStateManager().getState();
+ if (state == NORMAL) {
+ launcher.<RecentsView>getOverviewPanel().setSwipeDownShouldLaunchApp(false);
+ }
+ }
+
+ private static final class LauncherTaskViewController extends
+ TaskViewTouchController<Launcher> {
+
+ LauncherTaskViewController(Launcher activity) {
+ super(activity);
+ }
+
+ @Override
+ protected boolean isRecentsInteractive() {
+ return mActivity.isInState(OVERVIEW);
+ }
+
+ @Override
+ protected void onUserControlledAnimationCreated(AnimatorPlaybackController animController) {
+ mActivity.getStateManager().setCurrentUserControlledAnimation(animController);
+ }
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
index 0ef67c4..3aa6482 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
@@ -16,10 +16,8 @@
package com.android.launcher3.uioverrides;
-import static android.view.View.VISIBLE;
import static com.android.launcher3.AbstractFloatingView.TYPE_ALL;
import static com.android.launcher3.AbstractFloatingView.TYPE_HIDE_BACK_BUTTON;
-import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
@@ -41,7 +39,6 @@
import com.android.launcher3.LauncherStateManager;
import com.android.launcher3.LauncherStateManager.StateHandler;
import com.android.launcher3.Utilities;
-import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.TouchController;
import com.android.launcher3.util.UiThreadHelper;
@@ -49,7 +46,6 @@
import com.android.quickstep.OverviewInteractionState;
import com.android.quickstep.RecentsModel;
import com.android.quickstep.util.RemoteFadeOutAnimationListener;
-import com.android.quickstep.views.RecentsView;
import com.android.systemui.shared.system.ActivityCompat;
import com.android.systemui.shared.system.WindowManagerWrapper;
@@ -83,7 +79,11 @@
&& !launcher.getDeviceProfile().isVerticalBarLayout()) {
list.add(new StatusBarTouchController(launcher));
}
- list.add(new LauncherTaskViewController(launcher));
+ TouchController taskSwipeController =
+ RecentsUiFactory.createTaskSwipeController(launcher);
+ if (taskSwipeController != null) {
+ list.add(taskSwipeController);
+ }
return list.toArray(new TouchController[list.size()]);
}
@@ -93,7 +93,8 @@
public static StateHandler[] getStateHandler(Launcher launcher) {
return new StateHandler[] {launcher.getAllAppsController(), launcher.getWorkspace(),
- new RecentsViewStateController(launcher), new BackButtonAlphaHandler(launcher)};
+ RecentsUiFactory.createRecentsViewStateController(launcher),
+ new BackButtonAlphaHandler(launcher)};
}
/**
@@ -113,8 +114,7 @@
}
public static void resetOverview(Launcher launcher) {
- RecentsView recents = launcher.getOverviewPanel();
- recents.reset();
+ RecentsUiFactory.resetRecents(launcher);
}
public static void onCreate(Launcher launcher) {
@@ -186,9 +186,7 @@
visible ? 1 : 0, profile.hotseatBarSizePx);
}
- if (state == NORMAL) {
- launcher.<RecentsView>getOverviewPanel().setSwipeDownShouldLaunchApp(false);
- }
+ RecentsUiFactory.onLauncherStateOrResumeChanged(launcher);
}
public static void onTrimMemory(Context context, int level) {
@@ -242,26 +240,6 @@
}
public static void prepareToShowOverview(Launcher launcher) {
- RecentsView overview = launcher.getOverviewPanel();
- if (overview.getVisibility() != VISIBLE || overview.getContentAlpha() == 0) {
- SCALE_PROPERTY.set(overview, 1.33f);
- }
- }
-
- private static class LauncherTaskViewController extends TaskViewTouchController<Launcher> {
-
- public LauncherTaskViewController(Launcher activity) {
- super(activity);
- }
-
- @Override
- protected boolean isRecentsInteractive() {
- return mActivity.isInState(OVERVIEW);
- }
-
- @Override
- protected void onUserControlledAnimationCreated(AnimatorPlaybackController animController) {
- mActivity.getStateManager().setCurrentUserControlledAnimation(animController);
- }
+ RecentsUiFactory.prepareToShowRecents(launcher);
}
}
diff --git a/quickstep/src/com/android/quickstep/ActivityControlHelper.java b/quickstep/src/com/android/quickstep/ActivityControlHelper.java
index 20aabae..8293083 100644
--- a/quickstep/src/com/android/quickstep/ActivityControlHelper.java
+++ b/quickstep/src/com/android/quickstep/ActivityControlHelper.java
@@ -154,7 +154,7 @@
@Override
public LayoutListener createLayoutListener(Launcher activity) {
- return new LauncherLayoutListener(activity);
+ return LauncherLayoutListener.resetAndGet(activity);
}
@Override
diff --git a/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java b/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
index e27af2a..93f1ee6 100644
--- a/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
+++ b/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
@@ -99,7 +99,7 @@
private VelocityTracker mVelocityTracker;
private MotionEventQueue mEventQueue;
- private boolean mIsGoingToHome;
+ private boolean mIsGoingToLauncher;
public OtherActivityTouchConsumer(Context base, RunningTaskInfo runningTaskInfo,
RecentsModel recentsModel, Intent homeIntent, ActivityControlHelper activityControl,
@@ -333,7 +333,7 @@
if (mInteractionHandler != null) {
final WindowTransformSwipeHandler handler = mInteractionHandler;
mInteractionHandler = null;
- mIsGoingToHome = handler.mIsGoingToHome;
+ mIsGoingToLauncher = handler.mIsGoingToRecents;
mMainThreadExecutor.execute(handler::reset);
}
}
@@ -417,7 +417,7 @@
@Override
public boolean forceToLauncherConsumer() {
- return mIsGoingToHome;
+ return mIsGoingToLauncher;
}
@Override
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java b/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java
index 042afea..60bd9fb 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java
@@ -100,8 +100,8 @@
* @param onFinishComplete A callback that runs on the main thread after the animation
* controller has finished on the background thread.
*/
- public void finish(boolean toHome, Runnable onFinishComplete) {
- if (!toHome) {
+ public void finish(boolean toRecents, Runnable onFinishComplete) {
+ if (!toRecents) {
mExecutorService.submit(() -> finishBg(false, onFinishComplete));
return;
}
@@ -119,13 +119,14 @@
});
}
- protected void finishBg(boolean toHome, Runnable onFinishComplete) {
+ protected void finishBg(boolean toRecents, Runnable onFinishComplete) {
RecentsAnimationControllerCompat controller = mController;
mController = null;
- TraceHelper.endSection("RecentsController", "Finish " + controller + ", toHome=" + toHome);
+ TraceHelper.endSection("RecentsController", "Finish " + controller
+ + ", toRecents=" + toRecents);
if (controller != null) {
controller.setInputConsumerEnabled(false);
- controller.finish(toHome);
+ controller.finish(toRecents);
if (onFinishComplete != null) {
mMainThreadExecutor.execute(onFinishComplete);
diff --git a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
index 9d48ec6..d7720ee 100644
--- a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
@@ -187,7 +187,7 @@
private final ClipAnimationHelper.TransformParams mTransformParams;
protected Runnable mGestureEndCallback;
- protected boolean mIsGoingToHome;
+ protected boolean mIsGoingToRecents;
private DeviceProfile mDp;
private int mTransitionDragLength;
@@ -319,7 +319,7 @@
mStateCallback.addCallback(STATE_SCREENSHOT_CAPTURED | STATE_GESTURE_COMPLETED
| STATE_SCALED_CONTROLLER_RECENTS,
- this::finishCurrentTransitionToHome);
+ this::finishCurrentTransitionToRecents);
mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_APP_CONTROLLER_RECEIVED
| STATE_ACTIVITY_MULTIPLIER_COMPLETE | STATE_SCALED_CONTROLLER_RECENTS
@@ -812,7 +812,7 @@
float velocityXPxPerMs = velocityX / 1000;
long duration = MAX_SWIPE_DURATION;
float currentShift = mCurrentShift.value;
- final boolean goingToHome;
+ final boolean goingToRecents;
float endShift;
final float startShift;
Interpolator interpolator = DEACCEL;
@@ -821,24 +821,24 @@
boolean goingToNewTask = mRecentsView != null && nextPage != runningTaskIndex;
final boolean reachedOverviewThreshold = currentShift >= MIN_PROGRESS_FOR_OVERVIEW;
if (!isFling) {
- goingToHome = reachedOverviewThreshold && mGestureStarted;
- endShift = goingToHome ? 1 : 0;
+ goingToRecents = reachedOverviewThreshold && mGestureStarted;
+ endShift = goingToRecents ? 1 : 0;
long expectedDuration = Math.abs(Math.round((endShift - currentShift)
* MAX_SWIPE_DURATION * SWIPE_DURATION_MULTIPLIER));
duration = Math.min(MAX_SWIPE_DURATION, expectedDuration);
startShift = currentShift;
- interpolator = goingToHome ? OVERSHOOT_1_2 : DEACCEL;
+ interpolator = goingToRecents ? OVERSHOOT_1_2 : DEACCEL;
} else {
- // If user scrolled to a new task, only go to home (overview) if they already passed
+ // If user scrolled to a new task, only go to recents if they already passed
// the overview threshold. Otherwise, we'll snap to the new task and launch it.
- goingToHome = endVelocity < 0 && (!goingToNewTask || reachedOverviewThreshold);
- endShift = goingToHome ? 1 : 0;
+ goingToRecents = endVelocity < 0 && (!goingToNewTask || reachedOverviewThreshold);
+ endShift = goingToRecents ? 1 : 0;
startShift = Utilities.boundToRange(currentShift - velocityPxPerMs
* SINGLE_FRAME_MS / mTransitionDragLength, 0, 1);
float minFlingVelocity = mContext.getResources()
.getDimension(R.dimen.quickstep_fling_min_velocity);
if (Math.abs(endVelocity) > minFlingVelocity && mTransitionDragLength > 0) {
- if (goingToHome) {
+ if (goingToRecents) {
Interpolators.OvershootParams overshoot = new Interpolators.OvershootParams(
startShift, endShift, endShift, velocityPxPerMs, mTransitionDragLength);
endShift = overshoot.end;
@@ -856,10 +856,10 @@
}
}
}
- if (goingToHome) {
+ if (goingToRecents) {
mRecentsAnimationWrapper.enableTouchProxy();
} else if (goingToNewTask) {
- // We aren't goingToHome, and user scrolled/flung to a new task; snap to the closest
+ // We aren't goingToRecents, and user scrolled/flung to a new task; snap to the closest
// task in that direction and launch it (in startNewTask()).
int taskToLaunch = runningTaskIndex + (nextPage > runningTaskIndex ? 1 : - 1);
if (taskToLaunch >= mRecentsView.getTaskViewCount()) {
@@ -879,7 +879,7 @@
}
}
- animateToProgress(startShift, endShift, duration, interpolator, goingToHome,
+ animateToProgress(startShift, endShift, duration, interpolator, goingToRecents,
goingToNewTask, velocityPxPerMs);
}
@@ -906,15 +906,15 @@
/** Animates to the given progress, where 0 is the current app and 1 is overview. */
private void animateToProgress(float start, float end, long duration, Interpolator interpolator,
- boolean goingToHome, boolean goingToNewTask, float velocityPxPerMs) {
+ boolean goingToRecents, boolean goingToNewTask, float velocityPxPerMs) {
mRecentsAnimationWrapper.runOnInit(() -> animateToProgressInternal(start, end, duration,
- interpolator, goingToHome, goingToNewTask, velocityPxPerMs));
+ interpolator, goingToRecents, goingToNewTask, velocityPxPerMs));
}
private void animateToProgressInternal(float start, float end, long duration,
- Interpolator interpolator, boolean goingToHome, boolean goingToNewTask,
+ Interpolator interpolator, boolean goingToRecents, boolean goingToNewTask,
float velocityPxPerMs) {
- mIsGoingToHome = goingToHome;
+ mIsGoingToRecents = goingToRecents;
ObjectAnimator anim = mCurrentShift.animateToValue(start, end).setDuration(duration);
anim.setInterpolator(interpolator);
anim.addListener(new AnimationSuccessListener() {
@@ -922,7 +922,7 @@
public void onAnimationSuccess(Animator animator) {
int recentsState = STATE_SCALED_CONTROLLER_RECENTS | STATE_CAPTURE_SCREENSHOT
| STATE_SCREENSHOT_VIEW_SHOWN;
- setStateOnUiThread(mIsGoingToHome
+ setStateOnUiThread(mIsGoingToRecents
? recentsState
: goingToNewTask
? STATE_START_NEW_TASK
@@ -970,14 +970,14 @@
@UiThread
private void resumeLastTask() {
- mRecentsAnimationWrapper.finish(false /* toHome */, null);
+ mRecentsAnimationWrapper.finish(false /* toRecents */, null);
mTouchInteractionLog.finishRecentsAnimation(false);
}
@UiThread
private void startNewTask() {
// Launch the task user scrolled to (mRecentsView.getNextPage()).
- mRecentsAnimationWrapper.finish(true /* toHome */, () -> {
+ mRecentsAnimationWrapper.finish(true /* toRecents */, () -> {
mRecentsView.getTaskViewAt(mRecentsView.getNextPage()).launchTask(false,
result -> setStateOnUiThread(STATE_HANDLER_INVALIDATED),
mMainThreadHandler);
@@ -1083,12 +1083,12 @@
}
}
- private void finishCurrentTransitionToHome() {
+ private void finishCurrentTransitionToRecents() {
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
setStateOnUiThread(STATE_CURRENT_TASK_FINISHED);
} else {
synchronized (mRecentsAnimationWrapper) {
- mRecentsAnimationWrapper.finish(true /* toHome */,
+ mRecentsAnimationWrapper.finish(true /* toRecents */,
() -> setStateOnUiThread(STATE_CURRENT_TASK_FINISHED));
}
}
@@ -1126,7 +1126,7 @@
long duration = FeatureFlags.QUICK_SWITCH.get()
? QUICK_SWITCH_FROM_APP_START_DURATION
: QUICK_SCRUB_FROM_APP_START_DURATION;
- animateToProgress(mCurrentShift.value, 1f, duration, LINEAR, true /* goingToHome */,
+ animateToProgress(mCurrentShift.value, 1f, duration, LINEAR, true /* goingToRecents */,
false /* goingToNewTask */, 1f);
}
@@ -1289,7 +1289,7 @@
return;
}
mUiLongSwipeMode = false;
- finishCurrentTransitionToHome();
+ finishCurrentTransitionToRecents();
mLongSwipeController.end(velocity, isFling,
() -> setStateOnUiThread(STATE_HANDLER_INVALIDATED));
diff --git a/quickstep/src/com/android/quickstep/views/LauncherLayoutListener.java b/quickstep/src/com/android/quickstep/views/LauncherLayoutListener.java
index 1e5ea5f..a8205cd 100644
--- a/quickstep/src/com/android/quickstep/views/LauncherLayoutListener.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherLayoutListener.java
@@ -40,17 +40,35 @@
public class LauncherLayoutListener extends AbstractFloatingView
implements Insettable, LayoutListener {
+ public static LauncherLayoutListener resetAndGet(Launcher launcher) {
+ LauncherRecentsView lrv = launcher.getOverviewPanel();
+ LauncherLayoutListener listener = lrv.mLauncherLayoutListener;
+ if (listener.isOpen()) {
+ listener.close(false);
+ }
+ listener.setHandler(null);
+ return listener;
+ }
+
private final Launcher mLauncher;
private final Paint mPaint = new Paint();
private WindowTransformSwipeHandler mHandler;
private RectF mCurrentRect;
private float mCornerRadius;
- public LauncherLayoutListener(Launcher launcher) {
+ private boolean mWillNotDraw;
+
+ /**
+ * package private
+ */
+ LauncherLayoutListener(Launcher launcher) {
super(launcher, null);
mLauncher = launcher;
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
setLayoutParams(new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
+
+ mWillNotDraw = willNotDraw();
+ super.setWillNotDraw(false);
}
@Override
@@ -71,6 +89,12 @@
}
@Override
+ public void setWillNotDraw(boolean willNotDraw) {
+ // Prevent super call as that causes additional relayout.
+ mWillNotDraw = willNotDraw;
+ }
+
+ @Override
public void setHandler(WindowTransformSwipeHandler handler) {
mHandler = handler;
}
@@ -127,6 +151,8 @@
@Override
protected void onDraw(Canvas canvas) {
- canvas.drawRoundRect(mCurrentRect, mCornerRadius, mCornerRadius, mPaint);
+ if (!mWillNotDraw) {
+ canvas.drawRoundRect(mCurrentRect, mCornerRadius, mCornerRadius, mPaint);
+ }
}
}
diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
index 6396d1a..7389d65 100644
--- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -35,6 +35,7 @@
import android.view.ViewDebug;
import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.BaseActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
@@ -70,6 +71,7 @@
private float mTranslationYFactor;
private final TransformParams mTransformParams = new TransformParams();
+ final LauncherLayoutListener mLauncherLayoutListener;
public LauncherRecentsView(Context context) {
this(context, null);
@@ -82,6 +84,7 @@
public LauncherRecentsView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setContentAlpha(0);
+ mLauncherLayoutListener = new LauncherLayoutListener(BaseActivity.fromContext(context));
}
@Override
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index 3c0ef79..45bdea8 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -139,6 +139,13 @@
APPLY_CONFIG_AT_RUNTIME.get() ? this::onConfigChanged : this::killProcess);
}
+ public InvariantDeviceProfile(Context context, String gridName) {
+ String newName = initGrid(context, gridName);
+ if (newName == null || !newName.equals(gridName)) {
+ throw new IllegalArgumentException("Unknown grid name");
+ }
+ }
+
/**
* Retrieve system defined or RRO overriden icon shape.
*/
@@ -150,7 +157,7 @@
return context.getResources().getString(CONFIG_ICON_MASK_RES_ID);
}
- private void initGrid(Context context, String gridName) {
+ private String initGrid(Context context, String gridName) {
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
DisplayMetrics dm = new DisplayMetrics();
@@ -218,6 +225,7 @@
} else {
defaultWallpaperSize = new Point(Math.max(smallSide * 2, largeSide), largeSide);
}
+ return closestProfile.name;
}
@Nullable
@@ -441,11 +449,11 @@
}
- private static final class GridOption {
+ public static final class GridOption {
- private final String name;
- private final int numRows;
- private final int numColumns;
+ public final String name;
+ public final int numRows;
+ public final int numColumns;
private final int numFolderRows;
private final int numFolderColumns;
@@ -457,7 +465,7 @@
private final SparseArray<TypedValue> extraAttrs;
- GridOption(Context context, AttributeSet attrs) {
+ public GridOption(Context context, AttributeSet attrs) {
TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.GridDisplayOption);
name = a.getString(R.styleable.GridDisplayOption_name);
diff --git a/src/com/android/launcher3/graphics/GridOptionsProvider.java b/src/com/android/launcher3/graphics/GridOptionsProvider.java
new file mode 100644
index 0000000..9b907ba
--- /dev/null
+++ b/src/com/android/launcher3/graphics/GridOptionsProvider.java
@@ -0,0 +1,157 @@
+package com.android.launcher3.graphics;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.content.res.XmlResourceParser;
+import android.database.Cursor;
+import android.database.MatrixCursor;
+import android.graphics.Bitmap;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
+import android.os.ParcelFileDescriptor.AutoCloseOutputStream;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.Xml;
+
+import com.android.launcher3.InvariantDeviceProfile;
+import com.android.launcher3.InvariantDeviceProfile.GridOption;
+import com.android.launcher3.R;
+import com.android.launcher3.util.LooperExecutor;
+import com.android.launcher3.util.UiThreadHelper;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.List;
+import java.util.concurrent.Future;
+
+/**
+ * Exposes various launcher grid options and allows the caller to change them.
+ * APIs:
+ * /list_options: List the various available grip options, has following columns
+ * name: name of the grid
+ * rows: number of rows in the grid
+ * cols: number of columns in the grid
+ * preview_count: number of previews available for this grid option. The preview uri
+ * looks like /preview/<grid-name>/<preview index starting with 0>
+ * is_default: true if this grid is currently active
+ *
+ * /preview: Opens a file stream for the grid preview
+ */
+public class GridOptionsProvider extends ContentProvider {
+
+ private static final String TAG = "GridOptionsProvider";
+
+ private static final String KEY_NAME = "name";
+ private static final String KEY_ROWS = "rows";
+ private static final String KEY_COLS = "cols";
+ private static final String KEY_PREVIEW_COUNT = "preview_count";
+ private static final String KEY_IS_DEFAULT = "is_default";
+
+ private static final String KEY_PREVIEW = "preview";
+ private static final String MIME_TYPE_PNG = "image/png";
+
+ public static final PipeDataWriter<Future<Bitmap>> BITMAP_WRITER =
+ new PipeDataWriter<Future<Bitmap>>() {
+ @Override
+ public void writeDataToPipe(ParcelFileDescriptor output, Uri uri, String s,
+ Bundle bundle, Future<Bitmap> bitmap) {
+ try (AutoCloseOutputStream os = new AutoCloseOutputStream(output)) {
+ bitmap.get().compress(Bitmap.CompressFormat.PNG, 100, os);
+ } catch (Exception e) {
+ Log.w(TAG, "fail to write to pipe", e);
+ }
+ }
+ };
+
+ @Override
+ public boolean onCreate() {
+ return true;
+ }
+
+ @Override
+ public Cursor query(Uri uri, String[] projection, String selection,
+ String[] selectionArgs, String sortOrder) {
+ // TODO: Validate the query uri
+ MatrixCursor cursor = new MatrixCursor(new String[] {
+ KEY_NAME, KEY_ROWS, KEY_COLS, KEY_PREVIEW_COUNT, KEY_IS_DEFAULT});
+ InvariantDeviceProfile idp = InvariantDeviceProfile.INSTANCE.get(getContext());
+ try (XmlResourceParser parser = getContext().getResources().getXml(R.xml.device_profiles)) {
+ final int depth = parser.getDepth();
+ int type;
+ while (((type = parser.next()) != XmlPullParser.END_TAG ||
+ parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
+ if ((type == XmlPullParser.START_TAG) && "grid-option".equals(parser.getName())) {
+ GridOption gridOption = new GridOption(
+ getContext(), Xml.asAttributeSet(parser));
+
+ cursor.newRow()
+ .add(KEY_NAME, gridOption.name)
+ .add(KEY_ROWS, gridOption.numRows)
+ .add(KEY_COLS, gridOption.numColumns)
+ .add(KEY_PREVIEW_COUNT, 1)
+ .add(KEY_IS_DEFAULT, idp.numColumns == gridOption.numColumns
+ && idp.numRows == gridOption.numRows);
+ }
+ }
+ } catch (IOException | XmlPullParserException e) {
+ Log.e(TAG, "Error parsing device profile", e);
+ }
+
+ return cursor;
+ }
+
+ @Override
+ public String getType(Uri uri) {
+ List<String> segments = uri.getPathSegments();
+ if (segments.size() > 0 && KEY_PREVIEW.equals(segments.get(0))) {
+ return MIME_TYPE_PNG;
+ }
+ return "vnd.android.cursor.dir/launcher_grid";
+ }
+
+ @Override
+ public Uri insert(Uri uri, ContentValues initialValues) {
+ return null;
+ }
+
+ @Override
+ public int delete(Uri uri, String selection, String[] selectionArgs) {
+ return 0;
+ }
+
+ @Override
+ public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+ return 0;
+ }
+
+ @Override
+ public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
+ List<String> segments = uri.getPathSegments();
+ if (segments.size() < 2 || !KEY_PREVIEW.equals(segments.get(0))) {
+ throw new FileNotFoundException("Invalid preview url");
+ }
+ String profileName = segments.get(1);
+ if (TextUtils.isEmpty(profileName)) {
+ throw new FileNotFoundException("Invalid preview url");
+ }
+
+ InvariantDeviceProfile idp;
+ try {
+ idp = new InvariantDeviceProfile(getContext(), profileName);
+ } catch (Exception e) {
+ throw new FileNotFoundException(e.getMessage());
+ }
+
+ LooperExecutor executor = new LooperExecutor(UiThreadHelper.getBackgroundLooper());
+ try {
+ return openPipeHelper(uri, MIME_TYPE_PNG, null,
+ executor.submit(new LauncherPreviewRenderer(getContext(), idp)), BITMAP_WRITER);
+ } catch (Exception e) {
+ throw new FileNotFoundException(e.getMessage());
+ }
+ }
+}
diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
index dc6f50f..e52fe66 100644
--- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
+++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
@@ -61,6 +61,7 @@
import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.views.BaseDragLayer;
+import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
/**
@@ -72,7 +73,7 @@
* 4) Measure and draw the view on a canvas
*/
@TargetApi(Build.VERSION_CODES.O)
-public class LauncherPreviewRenderer {
+public class LauncherPreviewRenderer implements Callable<Bitmap> {
private static final String TAG = "LauncherPreviewRenderer";
@@ -110,7 +111,8 @@
context.getString(R.string.label_application);
}
- public Bitmap createScreenShot() {
+ @Override
+ public Bitmap call() {
return BitmapRenderer.createHardwareBitmap(mDp.widthPx, mDp.heightPx, c -> {
if (Looper.myLooper() == Looper.getMainLooper()) {
diff --git a/tests/tapl/com/android/launcher3/tapl/AllApps.java b/tests/tapl/com/android/launcher3/tapl/AllApps.java
index 84fd908..82ea8be 100644
--- a/tests/tapl/com/android/launcher3/tapl/AllApps.java
+++ b/tests/tapl/com/android/launcher3/tapl/AllApps.java
@@ -54,7 +54,7 @@
@NonNull
public AppIcon getAppIcon(String appName) {
final UiObject2 allAppsContainer = verifyActiveContainer();
- final BySelector appIconSelector = AppIcon.getAppIconSelector(appName);
+ final BySelector appIconSelector = AppIcon.getAppIconSelector(appName, mLauncher);
if (!allAppsContainer.hasObject(appIconSelector)) {
scrollBackToBeginning();
int attempts = 0;
diff --git a/tests/tapl/com/android/launcher3/tapl/AppIcon.java b/tests/tapl/com/android/launcher3/tapl/AppIcon.java
index efefc0d..7582d53 100644
--- a/tests/tapl/com/android/launcher3/tapl/AppIcon.java
+++ b/tests/tapl/com/android/launcher3/tapl/AppIcon.java
@@ -31,8 +31,8 @@
super(launcher, icon);
}
- static BySelector getAppIconSelector(String appName) {
- return By.clazz(TextView.class).text(appName).pkg(LauncherInstrumentation.LAUNCHER_PKG);
+ static BySelector getAppIconSelector(String appName, LauncherInstrumentation launcher) {
+ return By.clazz(TextView.class).text(appName).pkg(launcher.mLauncherPackageName);
}
/**
diff --git a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
index 4fce211..5f60113 100644
--- a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
+++ b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
@@ -16,13 +16,13 @@
package com.android.launcher3.tapl;
-import java.util.Collections;
-import java.util.List;
-
import androidx.annotation.NonNull;
import androidx.test.uiautomator.Direction;
import androidx.test.uiautomator.UiObject2;
+import java.util.Collections;
+import java.util.List;
+
/**
* Common overview pane for both Launcher and fallback recents
*/
@@ -69,7 +69,7 @@
public OverviewTask getCurrentTask() {
verifyActiveContainer();
final List<UiObject2> taskViews = mLauncher.getDevice().findObjects(
- LauncherInstrumentation.getLauncherObjectSelector("snapshot"));
+ mLauncher.getLauncherObjectSelector("snapshot"));
LauncherInstrumentation.assertNotEquals("Unable to find a task", 0, taskViews.size());
// taskViews contains up to 3 task views: the 'main' (having the widest visible
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index bd1c657..7070555 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -83,13 +83,13 @@
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";
public 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;
+ final String mLauncherPackageName;
private final boolean mSwipeUpEnabled;
private Boolean mSwipeUpEnabledOverride = null;
private final Instrumentation mInstrumentation;
@@ -101,6 +101,7 @@
public LauncherInstrumentation(Instrumentation instrumentation) {
mInstrumentation = instrumentation;
mDevice = UiDevice.getInstance(instrumentation);
+ mLauncherPackageName = mDevice.getLauncherPackageName();
final boolean swipeUpEnabledDefault =
!SwipeUpSetting.isSwipeUpSettingAvailable() ||
SwipeUpSetting.isSwipeUpEnabledDefaultValue();
@@ -379,14 +380,15 @@
@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);
+ final BySelector selector = getLauncherObjectSelector(resName);
+ final UiObject2 object = mDevice.wait(Until.findObject(selector), WAIT_TIME_MS);
+ assertNotNull("Can't find a launcher object; selector: " + selector + ", current launcher: "
+ + mDevice.getLauncherPackageName(), object);
return object;
}
- static BySelector getLauncherObjectSelector(String resName) {
- return By.res(LAUNCHER_PKG, resName);
+ BySelector getLauncherObjectSelector(String resName) {
+ return By.res(mLauncherPackageName, resName);
}
@NonNull
diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java
index c45f0f0..5e6ad4d 100644
--- a/tests/tapl/com/android/launcher3/tapl/Workspace.java
+++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java
@@ -69,7 +69,7 @@
@Nullable
public AppIcon tryGetWorkspaceAppIcon(String appName) {
final UiObject2 workspace = verifyActiveContainer();
- final UiObject2 icon = workspace.findObject(AppIcon.getAppIconSelector(appName));
+ final UiObject2 icon = workspace.findObject(AppIcon.getAppIconSelector(appName, mLauncher));
return icon != null ? new AppIcon(mLauncher, icon) : null;
}
@@ -85,7 +85,7 @@
return new AppIcon(mLauncher,
mLauncher.getObjectInContainer(
verifyActiveContainer(),
- AppIcon.getAppIconSelector(appName)));
+ AppIcon.getAppIconSelector(appName, mLauncher)));
}
/**
@@ -108,7 +108,7 @@
@NonNull
private AppIcon getHotseatAppIcon(String appName) {
return new AppIcon(mLauncher, mLauncher.getObjectInContainer(
- mHotseat, AppIcon.getAppIconSelector(appName)));
+ mHotseat, AppIcon.getAppIconSelector(appName, mLauncher)));
}
private void dragIconToNextScreen(AppIcon app, UiObject2 workspace) {