Merge "Prevent removing the feedback view and callbacks when the user completes a gesture." into tm-dev
diff --git a/build.gradle b/build.gradle
index e4ade88..68ed73d 100644
--- a/build.gradle
+++ b/build.gradle
@@ -170,7 +170,7 @@
protobuf {
// Configure the protoc executable
protoc {
- artifact = "com.google.protobuf:protoc:${protocVersion}"
+ artifact = "com.google.protobuf:protoc:${protocVersion}${PROTO_ARCH_SUFFIX}"
}
generateProtoTasks {
all().each { task ->
diff --git a/quickstep/res/layout/taskbar_all_apps.xml b/quickstep/res/layout/taskbar_all_apps.xml
index 7dc0cbe..d402469 100644
--- a/quickstep/res/layout/taskbar_all_apps.xml
+++ b/quickstep/res/layout/taskbar_all_apps.xml
@@ -51,6 +51,12 @@
<include layout="@layout/all_apps_personal_work_tabs" />
</com.android.launcher3.allapps.FloatingHeaderView>
+ <com.android.launcher3.taskbar.allapps.TaskbarAllAppsFallbackSearchContainer
+ android:id="@+id/search_container_all_apps"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:visibility="gone" />
+
<include layout="@layout/all_apps_fast_scroller" />
</com.android.launcher3.taskbar.allapps.TaskbarAllAppsContainerView>
</com.android.launcher3.taskbar.allapps.TaskbarAllAppsSlideInView>
diff --git a/quickstep/src/com/android/launcher3/taskbar/BaseTaskbarContext.java b/quickstep/src/com/android/launcher3/taskbar/BaseTaskbarContext.java
index 27e89ba..4e1f54c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/BaseTaskbarContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/BaseTaskbarContext.java
@@ -23,14 +23,14 @@
import com.android.launcher3.DeviceProfile.DeviceProfileListenable;
import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
import com.android.launcher3.util.Themes;
-import com.android.launcher3.views.ActivityContext;
+import com.android.launcher3.views.AppLauncher;
import java.util.ArrayList;
import java.util.List;
// TODO(b/218912746): Share more behavior to avoid all apps context depending directly on taskbar.
/** Base for common behavior between taskbar window contexts. */
-public abstract class BaseTaskbarContext extends ContextThemeWrapper implements ActivityContext,
+public abstract class BaseTaskbarContext extends ContextThemeWrapper implements AppLauncher,
DeviceProfileListenable {
protected final LayoutInflater mLayoutInflater;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 6c74ae3..0f3a6ee 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -442,7 +442,8 @@
mControllers.stashedHandleViewController.setIsHomeButtonDisabled(
mControllers.navbarButtonsViewController.isHomeDisabled());
mControllers.taskbarKeyguardController.updateStateForSysuiFlags(systemUiStateFlags);
- mControllers.taskbarStashController.updateStateForSysuiFlags(systemUiStateFlags, fromInit);
+ mControllers.taskbarStashController.updateStateForSysuiFlags(
+ systemUiStateFlags, fromInit || !isUserSetupComplete());
mControllers.taskbarScrimViewController.updateStateForSysuiFlags(systemUiStateFlags,
fromInit);
mControllers.navButtonController.updateSysuiFlags(systemUiStateFlags);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index f9a282b..54dd0b2 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -54,6 +54,10 @@
public static final int FLAG_STASHED_IN_APP_IME = 1 << 5; // IME is visible
public static final int FLAG_IN_STASHED_LAUNCHER_STATE = 1 << 6;
public static final int FLAG_STASHED_IN_APP_ALL_APPS = 1 << 7; // All apps is visible.
+ public static final int FLAG_IN_SETUP = 1 << 8; // In the Setup Wizard
+
+ // If any of these flags are enabled, isInApp should return true.
+ private static final int FLAGS_IN_APP = FLAG_IN_APP | FLAG_IN_SETUP;
// If we're in an app and any of these flags are enabled, taskbar should be stashed.
private static final int FLAGS_STASHED_IN_APP = FLAG_STASHED_IN_APP_MANUAL
@@ -141,7 +145,7 @@
// Evaluate whether the handle should be stashed
private final StatePropertyHolder mStatePropertyHolder = new StatePropertyHolder(
flags -> {
- boolean inApp = hasAnyFlag(flags, FLAG_IN_APP);
+ boolean inApp = hasAnyFlag(flags, FLAGS_IN_APP);
boolean stashedInApp = hasAnyFlag(flags, FLAGS_STASHED_IN_APP);
boolean stashedLauncherState = hasAnyFlag(flags, FLAG_IN_STASHED_LAUNCHER_STATE);
return (inApp && stashedInApp) || (!inApp && stashedLauncherState);
@@ -179,10 +183,7 @@
boolean isInSetup = !mActivity.isUserSetupComplete() || sharedState.setupUIVisible;
updateStateForFlag(FLAG_STASHED_IN_APP_MANUAL, isManuallyStashedInApp);
updateStateForFlag(FLAG_STASHED_IN_APP_SETUP, isInSetup);
- if (isInSetup) {
- // Update the in-app state to ensure isStashed() reflects right state during SUW
- updateStateForFlag(FLAG_IN_APP, true);
- }
+ updateStateForFlag(FLAG_IN_SETUP, isInSetup);
applyState();
notifyStashChange(/* visible */ false, /* stashed */ isStashedInApp());
@@ -216,9 +217,10 @@
* Sets the flag indicating setup UI is visible
*/
protected void setSetupUIVisible(boolean isVisible) {
- updateStateForFlag(FLAG_STASHED_IN_APP_SETUP,
- isVisible || !mActivity.isUserSetupComplete());
- applyState();
+ boolean hideTaskbar = isVisible || !mActivity.isUserSetupComplete();
+ updateStateForFlag(FLAG_IN_SETUP, hideTaskbar);
+ updateStateForFlag(FLAG_STASHED_IN_APP_SETUP, hideTaskbar);
+ applyState(hideTaskbar ? 0 : TASKBAR_STASH_DURATION);
}
/**
@@ -259,7 +261,7 @@
}
private boolean isInApp() {
- return hasAnyFlag(FLAG_IN_APP);
+ return hasAnyFlag(FLAGS_IN_APP);
}
/**
@@ -478,7 +480,7 @@
}
public void applyState() {
- applyState(TASKBAR_STASH_DURATION);
+ applyState(hasAnyFlag(FLAG_IN_SETUP) ? 0 : TASKBAR_STASH_DURATION);
}
public void applyState(long duration) {
@@ -568,8 +570,8 @@
if (hasAnyFlag(changedFlags, FLAGS_STASHED_IN_APP)) {
mControllers.uiController.onStashedInAppChanged();
}
- if (hasAnyFlag(changedFlags, FLAGS_STASHED_IN_APP | FLAG_IN_APP)) {
- notifyStashChange(/* visible */ hasAnyFlag(FLAG_IN_APP),
+ if (hasAnyFlag(changedFlags, FLAGS_STASHED_IN_APP | FLAGS_IN_APP)) {
+ notifyStashChange(/* visible */ hasAnyFlag(FLAGS_IN_APP),
/* stashed */ isStashedInApp());
}
if (hasAnyFlag(changedFlags, FLAG_STASHED_IN_APP_MANUAL)) {
@@ -613,6 +615,7 @@
str.add((flags & FLAG_IN_STASHED_LAUNCHER_STATE) != 0
? "FLAG_IN_STASHED_LAUNCHER_STATE" : "");
str.add((flags & FLAG_STASHED_IN_APP_ALL_APPS) != 0 ? "FLAG_STASHED_IN_APP_ALL_APPS" : "");
+ str.add((flags & FLAG_IN_SETUP) != 0 ? "FLAG_IN_SETUP" : "");
return str.toString();
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
index 6bc2a93..d5c399b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
@@ -75,4 +75,15 @@
public void hideAllApps() {
mControllers.taskbarAllAppsController.hide();
}
+
+ /**
+ * User expands PiP to full-screen (or split-screen) mode, try to hide the Taskbar.
+ */
+ public void onExpandPip() {
+ if (mControllers != null) {
+ final TaskbarStashController stashController = mControllers.taskbarStashController;
+ stashController.updateStateForFlag(TaskbarStashController.FLAG_IN_APP, true);
+ stashController.applyState();
+ }
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContainerView.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContainerView.java
index 37cd753..0ea2aa0 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContainerView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContainerView.java
@@ -17,22 +17,17 @@
import android.content.Context;
import android.util.AttributeSet;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
import android.view.WindowInsets;
-import androidx.recyclerview.widget.RecyclerView;
-
+import com.android.launcher3.allapps.ActivityAllAppsContainerView;
import com.android.launcher3.allapps.AllAppsGridAdapter;
import com.android.launcher3.allapps.AlphabeticalAppsList;
import com.android.launcher3.allapps.BaseAdapterProvider;
import com.android.launcher3.allapps.BaseAllAppsAdapter;
-import com.android.launcher3.allapps.BaseAllAppsContainerView;
-import com.android.launcher3.allapps.search.SearchAdapterProvider;
/** All apps container accessible from taskbar. */
-public class TaskbarAllAppsContainerView extends BaseAllAppsContainerView<TaskbarAllAppsContext> {
+public class TaskbarAllAppsContainerView extends
+ ActivityAllAppsContainerView<TaskbarAllAppsContext> {
public TaskbarAllAppsContainerView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
@@ -43,41 +38,6 @@
}
@Override
- protected SearchAdapterProvider<?> createMainAdapterProvider() {
- // Taskbar all apps does not yet support search, so this implementation is minimal.
- return new SearchAdapterProvider<TaskbarAllAppsContext>(mActivityContext) {
- @Override
- public boolean launchHighlightedItem() {
- return false;
- }
-
- @Override
- public View getHighlightedItem() {
- return null;
- }
-
- @Override
- public RecyclerView.ItemDecoration getDecorator() {
- return null;
- }
-
- @Override
- public boolean isViewSupported(int viewType) {
- return false;
- }
-
- @Override
- public void onBindView(AllAppsGridAdapter.ViewHolder holder, int position) { }
-
- @Override
- public AllAppsGridAdapter.ViewHolder onCreateViewHolder(LayoutInflater layoutInflater,
- ViewGroup parent, int viewType) {
- return null;
- }
- };
- }
-
- @Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
setInsets(insets.getInsets(WindowInsets.Type.systemBars()).toRect());
return super.onApplyWindowInsets(insets);
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContext.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContext.java
index 22fffdf..50dfff0 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContext.java
@@ -32,6 +32,9 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
+import com.android.launcher3.allapps.ActivityAllAppsContainerView;
+import com.android.launcher3.allapps.search.DefaultSearchAdapterProvider;
+import com.android.launcher3.allapps.search.SearchAdapterProvider;
import com.android.launcher3.dot.DotInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.popup.PopupDataProvider;
@@ -154,6 +157,12 @@
@Override
public void onPopupVisibilityChanged(boolean isVisible) {}
+ @Override
+ public SearchAdapterProvider<?> createSearchAdapterProvider(
+ ActivityAllAppsContainerView<?> appsView) {
+ return new DefaultSearchAdapterProvider(this);
+ }
+
/** Root drag layer for this context. */
private static class TaskbarAllAppsDragLayer extends
BaseDragLayer<TaskbarAllAppsContext> implements OnComputeInsetsListener {
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsFallbackSearchContainer.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsFallbackSearchContainer.java
new file mode 100644
index 0000000..53fe06d
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsFallbackSearchContainer.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2022 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.taskbar.allapps;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.ExtendedEditText;
+import com.android.launcher3.allapps.ActivityAllAppsContainerView;
+import com.android.launcher3.allapps.SearchUiManager;
+
+/** Empty search container for Taskbar All Apps used as a fallback if search is not supported. */
+public class TaskbarAllAppsFallbackSearchContainer extends View implements SearchUiManager {
+ public TaskbarAllAppsFallbackSearchContainer(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public TaskbarAllAppsFallbackSearchContainer(
+ Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ @Override
+ public void initializeSearch(ActivityAllAppsContainerView<?> containerView) {
+ // Do nothing.
+ }
+
+ @Override
+ public void resetSearch() {
+ // Do nothing.
+ }
+
+ @Nullable
+ @Override
+ public ExtendedEditText getEditText() {
+ return null;
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 253903c..43be051 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -1273,8 +1273,7 @@
HomeAnimationFactory homeAnimFactory =
createHomeAnimationFactory(cookies, duration, isTranslucent, appCanEnterPip,
runningTaskTarget);
- mIsSwipingPipToHome = !mIsSwipeForStagedSplit
- && homeAnimFactory.supportSwipePipToHome() && appCanEnterPip;
+ mIsSwipingPipToHome = !mIsSwipeForStagedSplit && appCanEnterPip;
final RectFSpringAnim[] windowAnim;
if (mIsSwipingPipToHome) {
mSwipePipToHomeAnimator = createWindowAnimationToPip(
diff --git a/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java b/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
index 4eb190a..a62e9d1 100644
--- a/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
@@ -50,12 +50,14 @@
import android.view.SurfaceControl.Transaction;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.anim.SpringAnimationBuilder;
+import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.util.DisplayController;
import com.android.quickstep.fallback.FallbackRecentsView;
import com.android.quickstep.fallback.RecentsState;
@@ -93,6 +95,8 @@
private final Matrix mTmpMatrix = new Matrix();
private float mMaxLauncherScale = 1;
+ private boolean mAppCanEnterPip;
+
public FallbackSwipeHandler(Context context, RecentsAnimationDeviceState deviceState,
TaskAnimationManager taskAnimationManager, GestureState gestureState, long touchTimeMs,
boolean continuingLastGesture, InputConsumerController inputConsumer) {
@@ -135,16 +139,27 @@
protected HomeAnimationFactory createHomeAnimationFactory(ArrayList<IBinder> launchCookies,
long duration, boolean isTargetTranslucent, boolean appCanEnterPip,
RemoteAnimationTargetCompat runningTaskTarget) {
+ mAppCanEnterPip = appCanEnterPip;
+ if (appCanEnterPip) {
+ return new FallbackPipToHomeAnimationFactory();
+ }
mActiveAnimationFactory = new FallbackHomeAnimationFactory(duration);
+ startHomeIntent(mActiveAnimationFactory);
+ return mActiveAnimationFactory;
+ }
+
+ private void startHomeIntent(
+ @Nullable FallbackHomeAnimationFactory gestureContractAnimationFactory) {
ActivityOptions options = ActivityOptions.makeCustomAnimation(mContext, 0, 0);
Intent intent = new Intent(mGestureState.getHomeIntent());
- mActiveAnimationFactory.addGestureContract(intent);
+ if (gestureContractAnimationFactory != null) {
+ gestureContractAnimationFactory.addGestureContract(intent);
+ }
try {
mContext.startActivity(intent, options.toBundle());
} catch (NullPointerException | ActivityNotFoundException | SecurityException e) {
mContext.startActivity(createHomeIntent());
}
- return mActiveAnimationFactory;
}
@Override
@@ -160,8 +175,20 @@
@Override
protected void finishRecentsControllerToHome(Runnable callback) {
+ final Runnable recentsCallback;
+ if (mAppCanEnterPip) {
+ // Make sure Launcher is resumed after auto-enter-pip transition to actually trigger
+ // the PiP task appearing.
+ recentsCallback = () -> {
+ callback.run();
+ startHomeIntent(null /* gestureContractAnimationFactory */);
+ };
+ } else {
+ recentsCallback = callback;
+ }
+ mRecentsView.cleanupRemoteTargets();
mRecentsAnimationController.finish(
- false /* toRecents */, callback, true /* sendUserLeaveHint */);
+ mAppCanEnterPip /* toRecents */, recentsCallback, true /* sendUserLeaveHint */);
}
@Override
@@ -186,6 +213,17 @@
}
}
+ private class FallbackPipToHomeAnimationFactory extends HomeAnimationFactory {
+ @NonNull
+ @Override
+ public AnimatorPlaybackController createActivityAnimationToHome() {
+ // copied from {@link LauncherSwipeHandlerV2.LauncherHomeAnimationFactory}
+ long accuracy = 2 * Math.max(mDp.widthPx, mDp.heightPx);
+ return mActivity.getStateManager().createAnimationToNewWorkspace(
+ RecentsState.HOME, accuracy, StateAnimationConfig.SKIP_ALL_ANIMATIONS);
+ }
+ }
+
private class FallbackHomeAnimationFactory extends HomeAnimationFactory {
private final Rect mTempRect = new Rect();
private final TransformParams mHomeAlphaParams = new TransformParams();
diff --git a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
index bc7a6ae..50d1244 100644
--- a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
+++ b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
@@ -239,6 +239,7 @@
@Override
protected void finishRecentsControllerToHome(Runnable callback) {
+ mRecentsView.cleanupRemoteTargets();
mRecentsAnimationController.finish(
true /* toRecents */, callback, true /* sendUserLeaveHint */);
}
@@ -284,10 +285,5 @@
getViewIgnoredInWorkspaceRevealAnimation())
.start();
}
-
- @Override
- public boolean supportSwipePipToHome() {
- return true;
- }
}
}
diff --git a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
index 8d9a685..8862073 100644
--- a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
+++ b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
@@ -184,14 +184,6 @@
public void onCancel() { }
/**
- * @return {@code true} if this factory supports animating an Activity to PiP window on
- * swiping up to home.
- */
- public boolean supportSwipePipToHome() {
- return false;
- }
-
- /**
* @param progress The progress of the animation to the home screen.
* @return The current alpha to set on the animating app window.
*/
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index f3ad0f6..ee69fc3 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -111,7 +111,7 @@
if (mInitialTaskIntent != null) {
fillInIntent = new Intent();
if (TextUtils.equals(mInitialTaskIntent.getComponent().getPackageName(),
- task.topActivity.getPackageName())) {
+ task.getTopComponent().getPackageName())) {
fillInIntent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
}
} else {
diff --git a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
index 27a748d..79b15c7 100644
--- a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
+++ b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
@@ -306,7 +306,7 @@
private void setBanner(@Nullable View view) {
mBanner = view;
- if (view != null) {
+ if (view != null && mTaskView.getRecentsView() != null) {
setupAndAddBanner();
setBannerOutline();
}
diff --git a/quickstep/src/com/android/quickstep/views/FloatingTaskThumbnailView.java b/quickstep/src/com/android/quickstep/views/FloatingTaskThumbnailView.java
index cfb0056..d869fed 100644
--- a/quickstep/src/com/android/quickstep/views/FloatingTaskThumbnailView.java
+++ b/quickstep/src/com/android/quickstep/views/FloatingTaskThumbnailView.java
@@ -42,8 +42,6 @@
private @Nullable BitmapShader mBitmapShader;
private @Nullable Bitmap mBitmap;
- private FloatingTaskView.FullscreenDrawParams mFullscreenParams;
-
public FloatingTaskThumbnailView(Context context) {
this(context, null);
}
@@ -58,18 +56,18 @@
@Override
protected void onDraw(Canvas canvas) {
- if (mFullscreenParams == null || mBitmap == null) {
+ if (mBitmap == null) {
return;
}
// Scale down the bitmap to fix x, and crop in y.
float scale = 1.0f * getMeasuredWidth() / mBitmap.getWidth();
+ mMatrix.reset();
mMatrix.postScale(scale, scale);
mBitmapShader.setLocalMatrix(mMatrix);
- canvas.drawRoundRect(0, 0, getMeasuredWidth(), getMeasuredHeight(),
- mFullscreenParams.mCurrentDrawnCornerRadius / mFullscreenParams.mScaleX,
- mFullscreenParams.mCurrentDrawnCornerRadius / mFullscreenParams.mScaleY, mPaint);
+ FloatingTaskView parent = (FloatingTaskView) getParent();
+ parent.drawRoundedRect(canvas, mPaint);
}
public void setThumbnail(Bitmap bitmap) {
@@ -79,8 +77,4 @@
mPaint.setShader(mBitmapShader);
}
}
-
- public void setFullscreenParams(FloatingTaskView.FullscreenDrawParams fullscreenParams) {
- mFullscreenParams = fullscreenParams;
- }
}
diff --git a/quickstep/src/com/android/quickstep/views/FloatingTaskView.java b/quickstep/src/com/android/quickstep/views/FloatingTaskView.java
index c59dc18..fe5e1d0 100644
--- a/quickstep/src/com/android/quickstep/views/FloatingTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/FloatingTaskView.java
@@ -3,11 +3,12 @@
import static com.android.launcher3.anim.Interpolators.ACCEL;
import static com.android.launcher3.anim.Interpolators.DEACCEL_3;
import static com.android.launcher3.anim.Interpolators.LINEAR;
-import static com.android.systemui.shared.system.QuickStepContract.supportsRoundedCornersOnWindows;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
@@ -31,15 +32,13 @@
import com.android.quickstep.util.TaskCornerRadius;
import com.android.systemui.shared.system.QuickStepContract;
-import java.util.function.Consumer;
-
/**
* Create an instance via
- * {@link #getFloatingTaskView(StatefulActivity, View, Bitmap, Drawable, RectF, Consumer)} to
+ * {@link #getFloatingTaskView(StatefulActivity, View, Bitmap, Drawable, RectF)} to
* which will have the thumbnail from the provided existing TaskView overlaying the taskview itself.
*
* Can then animate the taskview using
- * {@link #addAnimation(PendingAnimation, RectF, Rect, View, boolean)}
+ * {@link #addAnimation(PendingAnimation, RectF, Rect, boolean, boolean)}
* giving a starting and ending bounds. Currently this is set to use the split placeholder view,
* but it could be generified.
*
@@ -47,13 +46,13 @@
*/
public class FloatingTaskView extends FrameLayout {
+ private FloatingTaskThumbnailView mThumbnailView;
private SplitPlaceholderView mSplitPlaceholderView;
private RectF mStartingPosition;
private final StatefulActivity mActivity;
private final boolean mIsRtl;
- private final FullscreenDrawParams mCurrentFullscreenParams;
+ private final FullscreenDrawParams mFullscreenParams;
private PagedOrientationHandler mOrientationHandler;
- private FloatingTaskThumbnailView mThumbnailView;
public FloatingTaskView(Context context) {
this(context, null);
@@ -67,17 +66,15 @@
super(context, attrs, defStyleAttr);
mActivity = BaseActivity.fromContext(context);
mIsRtl = Utilities.isRtl(getResources());
- mCurrentFullscreenParams = new FullscreenDrawParams(context);
+ mFullscreenParams = new FullscreenDrawParams(context);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mThumbnailView = findViewById(R.id.thumbnail);
- mThumbnailView.setFullscreenParams(mCurrentFullscreenParams);
mSplitPlaceholderView = findViewById(R.id.split_placeholder);
mSplitPlaceholderView.setAlpha(0);
- mSplitPlaceholderView.setFullscreenParams(mCurrentFullscreenParams);
}
private void init(StatefulActivity launcher, View originalView, @Nullable Bitmap thumbnail,
@@ -94,20 +91,18 @@
// Copy bounds of exiting thumbnail into ImageView
mThumbnailView.setThumbnail(thumbnail);
+ mThumbnailView.setVisibility(VISIBLE);
+
RecentsView recentsView = launcher.getOverviewPanel();
mOrientationHandler = recentsView.getPagedOrientationHandler();
mSplitPlaceholderView.setIcon(icon,
- launcher.getDeviceProfile().overviewTaskIconDrawableSizePx);
+ mContext.getResources().getDimensionPixelSize(R.dimen.split_placeholder_icon_size));
mSplitPlaceholderView.getIconView().setRotation(mOrientationHandler.getDegreesRotated());
}
/**
* Configures and returns a an instance of {@link FloatingTaskView} initially matching the
* appearance of {@code originalView}.
- *
- * @param additionalOffsetter optional, to set additional offsets to the FloatingTaskView
- * to account for translations. If {@code null} then the
- * translation values from originalView will be used
*/
public static FloatingTaskView getFloatingTaskView(StatefulActivity launcher,
View originalView, @Nullable Bitmap thumbnail, Drawable icon, RectF positionOut) {
@@ -133,21 +128,22 @@
setLayoutParams(lp);
}
- public void update(RectF position, float progress) {
+ public void update(RectF bounds, float progress) {
MarginLayoutParams lp = (MarginLayoutParams) getLayoutParams();
- float dX = position.left - mStartingPosition.left;
- float dY = position.top - lp.topMargin;
- float scaleX = position.width() / lp.width;
- float scaleY = position.height() / lp.height;
+ float dX = bounds.left - mStartingPosition.left;
+ float dY = bounds.top - lp.topMargin;
+ float scaleX = bounds.width() / lp.width;
+ float scaleY = bounds.height() / lp.height;
- mCurrentFullscreenParams.updateParams(position, progress, scaleX, scaleY);
+ mFullscreenParams.updateParams(bounds, progress, scaleX, scaleY);
setTranslationX(dX);
setTranslationY(dY);
setScaleX(scaleX);
setScaleY(scaleY);
mSplitPlaceholderView.invalidate();
+ mThumbnailView.invalidate();
float childScaleX = 1f / scaleX;
float childScaleY = 1f / scaleY;
@@ -178,8 +174,8 @@
}
public void addAnimation(PendingAnimation animation, RectF startingBounds, Rect endBounds,
- boolean fadeWithThumbnail, boolean isInitialSplit) {
- mCurrentFullscreenParams.setIsInitialSplit(isInitialSplit);
+ boolean fadeWithThumbnail, boolean isStagedTask) {
+ mFullscreenParams.setIsStagedTask(isStagedTask);
final BaseDragLayer dragLayer = mActivity.getDragLayer();
int[] dragLayerBounds = new int[2];
dragLayer.getLocationOnScreen(dragLayerBounds);
@@ -219,6 +215,25 @@
transitionAnimator.addUpdateListener(listener);
}
+ public void drawRoundedRect(Canvas canvas, Paint paint) {
+ if (mFullscreenParams == null) {
+ return;
+ }
+
+ canvas.drawRoundRect(0, 0, getMeasuredWidth(), getMeasuredHeight(),
+ mFullscreenParams.mCurrentDrawnCornerRadius / mFullscreenParams.mScaleX,
+ mFullscreenParams.mCurrentDrawnCornerRadius / mFullscreenParams.mScaleY,
+ paint);
+ }
+
+ public float getFullscreenScaleX() {
+ return mFullscreenParams.mScaleX;
+ }
+
+ public float getFullscreenScaleY() {
+ return mFullscreenParams.mScaleY;
+ }
+
private static class SplitOverlayProperties {
private final float finalTaskViewScaleX;
@@ -247,9 +262,8 @@
private final float mCornerRadius;
private final float mWindowCornerRadius;
-
- public boolean mIsInitialSplit = true;
- public final RectF mFloatingTaskViewBounds = new RectF();
+ public boolean mIsStagedTask;
+ public final RectF mBounds = new RectF();
public float mCurrentDrawnCornerRadius;
public float mScaleX = 1;
public float mScaleY = 1;
@@ -261,17 +275,16 @@
mCurrentDrawnCornerRadius = mCornerRadius;
}
- public void updateParams(RectF floatingTaskViewBounds, float progress, float scaleX,
- float scaleY) {
- mFloatingTaskViewBounds.set(floatingTaskViewBounds);
+ public void updateParams(RectF bounds, float progress, float scaleX, float scaleY) {
+ mBounds.set(bounds);
mScaleX = scaleX;
mScaleY = scaleY;
- mCurrentDrawnCornerRadius = mIsInitialSplit ? 0 :
+ mCurrentDrawnCornerRadius = mIsStagedTask ? mWindowCornerRadius :
Utilities.mapRange(progress, mCornerRadius, mWindowCornerRadius);
}
- public void setIsInitialSplit(boolean isInitialSplit) {
- mIsInitialSplit = isInitialSplit;
+ public void setIsStagedTask(boolean isStagedTask) {
+ mIsStagedTask = isStagedTask;
}
}
}
diff --git a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
index d9f668d..b9615ab 100644
--- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
@@ -271,7 +271,8 @@
getPagedOrientationHandler().setSplitIconParams(mIconView, mIconView2,
taskIconHeight, mSnapshotView.getMeasuredWidth(), mSnapshotView.getMeasuredHeight(),
- isRtl, deviceProfile, mSplitBoundsConfig);
+ getMeasuredHeight(), getMeasuredWidth(), isRtl, deviceProfile,
+ mSplitBoundsConfig);
}
private void updateSecondaryDwbPlacement() {
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 3c10e21..22491bc 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -425,6 +425,7 @@
private final int mScrollHapticMinGapMillis;
private final RecentsModel mModel;
private final int mSplitPlaceholderSize;
+ private final int mSplitPlaceholderInset;
private final ClearAllButton mClearAllButton;
private final Rect mClearAllButtonDeadZoneRect = new Rect();
private final Rect mTaskViewDeadZoneRect = new Rect();
@@ -697,6 +698,8 @@
setLayoutDirection(mIsRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR);
mSplitPlaceholderSize = getResources().getDimensionPixelSize(
R.dimen.split_placeholder_size);
+ mSplitPlaceholderInset = getResources().getDimensionPixelSize(
+ R.dimen.split_placeholder_inset);
mSquaredTouchSlop = squaredTouchSlop(context);
mEmptyIcon = context.getDrawable(R.drawable.ic_empty_recents);
@@ -2702,7 +2705,7 @@
*/
private void createInitialSplitSelectAnimation(PendingAnimation anim) {
mOrientationHandler.getInitialSplitPlaceholderBounds(mSplitPlaceholderSize,
- mActivity.getDeviceProfile(),
+ mSplitPlaceholderInset, mActivity.getDeviceProfile(),
mSplitSelectStateController.getActiveSplitStagePosition(), mTempRect);
RectF startingTaskRect = new RectF();
@@ -2714,7 +2717,7 @@
mSplitHiddenTaskView.getIconView().getDrawable(), startingTaskRect);
mFirstFloatingTaskView.setAlpha(1);
mFirstFloatingTaskView.addAnimation(anim, startingTaskRect,
- mTempRect, true /* fadeWithThumbnail */, true /* isInitialSplit */);
+ mTempRect, true /* fadeWithThumbnail */, true /* isStagedTask */);
} else {
mSplitSelectSource.view.setVisibility(INVISIBLE);
mFirstFloatingTaskView = FloatingTaskView.getFloatingTaskView(mActivity,
@@ -2722,7 +2725,7 @@
mSplitSelectSource.drawable, startingTaskRect);
mFirstFloatingTaskView.setAlpha(1);
mFirstFloatingTaskView.addAnimation(anim, startingTaskRect,
- mTempRect, true /* fadeWithThumbnail */, true /* isInitialSplit */);
+ mTempRect, true /* fadeWithThumbnail */, true /* isStagedTask */);
}
anim.addEndListener(success -> {
if (success) {
@@ -4002,14 +4005,14 @@
mFirstFloatingTaskView.getBoundsOnScreen(firstTaskStartingBounds);
mFirstFloatingTaskView.addAnimation(pendingAnimation,
new RectF(firstTaskStartingBounds), firstTaskEndingBounds,
- false /* fadeWithThumbnail */, false /* isInitialSplit */);
+ false /* fadeWithThumbnail */, true /* isStagedTask */);
mSecondFloatingTaskView = FloatingTaskView.getFloatingTaskView(mActivity,
thumbnailView, thumbnailView.getThumbnail(),
iconView.getDrawable(), secondTaskStartingBounds);
mSecondFloatingTaskView.setAlpha(1);
mSecondFloatingTaskView.addAnimation(pendingAnimation, secondTaskStartingBounds,
- secondTaskEndingBounds, true /* fadeWithThumbnail */, false /* isInitialSplit */);
+ secondTaskEndingBounds, true /* fadeWithThumbnail */, false /* isStagedTask */);
pendingAnimation.addEndListener(aBoolean ->
mSplitSelectStateController.setSecondTask(
task, aBoolean1 -> RecentsView.this.resetFromSplitSelectionState()));
@@ -4077,10 +4080,9 @@
protected void onRotateInSplitSelectionState() {
mOrientationHandler.getInitialSplitPlaceholderBounds(mSplitPlaceholderSize,
- mActivity.getDeviceProfile(),
+ mSplitPlaceholderInset, mActivity.getDeviceProfile(),
mSplitSelectStateController.getActiveSplitStagePosition(), mTempRect);
mTempRectF.set(mTempRect);
- // TODO(194414938) set correct corner radius
mFirstFloatingTaskView.updateOrientationHandler(mOrientationHandler);
mFirstFloatingTaskView.update(mTempRectF, /*progress=*/1f);
@@ -4281,7 +4283,7 @@
}
mPendingAnimation.addEndListener(isSuccess -> {
if (isSuccess) {
- if (tv.getTaskIds()[1] != -1) {
+ if (tv.getTaskIds()[1] != -1 && mRemoteTargetHandles != null) {
// TODO(b/194414938): make this part of the animations instead.
TaskViewUtils.createSplitAuxiliarySurfacesAnimator(
mRemoteTargetHandles[0].getTransformParams().getTargetSet().nonApps,
@@ -5102,6 +5104,19 @@
mRecentsView.mPipCornerRadius = cornerRadius;
}
}
+
+ @Override
+ public void onExpandPip() {
+ MAIN_EXECUTOR.execute(() -> {
+ if (mRecentsView == null
+ || mRecentsView.mSizeStrategy.getTaskbarController() == null) {
+ return;
+ }
+ // Hide the task bar when leaving PiP to prevent it from flickering once
+ // the app settles in full-screen mode.
+ mRecentsView.mSizeStrategy.getTaskbarController().onExpandPip();
+ });
+ }
}
/** Get the color used for foreground scrimming the RecentsView for sharing. */
diff --git a/quickstep/src/com/android/quickstep/views/SplitPlaceholderView.java b/quickstep/src/com/android/quickstep/views/SplitPlaceholderView.java
index d37dfbf..7444217 100644
--- a/quickstep/src/com/android/quickstep/views/SplitPlaceholderView.java
+++ b/quickstep/src/com/android/quickstep/views/SplitPlaceholderView.java
@@ -19,11 +19,11 @@
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
+import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.FloatProperty;
import android.util.TypedValue;
-import android.view.Gravity;
import android.widget.FrameLayout;
import androidx.annotation.Nullable;
@@ -31,8 +31,7 @@
public class SplitPlaceholderView extends FrameLayout {
private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-
- private FloatingTaskView.FullscreenDrawParams mFullscreenParams;
+ private final Rect mTempRect = new Rect();
public static final FloatProperty<SplitPlaceholderView> ALPHA_FLOAT =
new FloatProperty<SplitPlaceholderView>("SplitViewAlpha") {
@@ -54,7 +53,7 @@
public SplitPlaceholderView(Context context, AttributeSet attrs) {
super(context, attrs);
- mPaint.setColor(getThemePrimaryColor(context));
+ mPaint.setColor(getThemeBackgroundColor(context));
setWillNotDraw(false);
}
@@ -64,6 +63,19 @@
drawBackground(canvas);
super.dispatchDraw(canvas);
+
+ if (mIconView != null) {
+ // Center the icon view in the visible area.
+ getLocalVisibleRect(mTempRect);
+ FloatingTaskView parent = (FloatingTaskView) getParent();
+ FrameLayout.LayoutParams params =
+ (FrameLayout.LayoutParams) mIconView.getLayoutParams();
+ params.leftMargin = Math.round(mTempRect.centerX() / parent.getFullscreenScaleX()
+ - 1.0f * mIconView.getDrawableWidth() / 2);
+ params.topMargin = Math.round(mTempRect.centerY() / parent.getFullscreenScaleY()
+ - 1.0f * mIconView.getDrawableHeight() / 2);
+ mIconView.setLayoutParams(params);
+ }
}
@Nullable
@@ -71,10 +83,6 @@
return mIconView;
}
- public void setFullscreenParams(FloatingTaskView.FullscreenDrawParams fullscreenParams) {
- mFullscreenParams = fullscreenParams;
- }
-
public void setIcon(Drawable drawable, int iconSize) {
if (mIconView == null) {
mIconView = new IconView(getContext());
@@ -83,23 +91,17 @@
mIconView.setDrawable(drawable);
mIconView.setDrawableSize(iconSize, iconSize);
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(iconSize, iconSize);
- params.gravity = Gravity.CENTER;
mIconView.setLayoutParams(params);
}
private void drawBackground(Canvas canvas) {
- if (mFullscreenParams == null) {
- return;
- }
-
- canvas.drawRoundRect(0, 0, getMeasuredWidth(), getMeasuredHeight(),
- mFullscreenParams.mCurrentDrawnCornerRadius / mFullscreenParams.mScaleX,
- mFullscreenParams.mCurrentDrawnCornerRadius / mFullscreenParams.mScaleY, mPaint);
+ FloatingTaskView parent = (FloatingTaskView) getParent();
+ parent.drawRoundedRect(canvas, mPaint);
}
- private static int getThemePrimaryColor(Context context) {
+ private static int getThemeBackgroundColor(Context context) {
final TypedValue value = new TypedValue();
- context.getTheme().resolveAttribute(android.R.attr.colorPrimary, value, true);
+ context.getTheme().resolveAttribute(android.R.attr.colorBackground, value, true);
return value.data;
}
}
diff --git a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
index 11f9ddd..60b0d17 100644
--- a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
@@ -50,7 +50,6 @@
import com.android.launcher3.BaseActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Utilities;
-import com.android.launcher3.icons.BitmapRenderer;
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.SystemUiController;
import com.android.quickstep.TaskOverlayFactory.TaskOverlay;
@@ -162,23 +161,6 @@
setThumbnail(task, thumbnailData, true /* refreshNow */);
}
- /**
- * By combining the two in a single bitmap then we only have to do a single draw
- * call in the onDraw function. Also, this fixes a bug where the background was
- * visible in the corners because of anti-aliasing.
- */
- public Bitmap combineThumbnailAndBackground(Bitmap bm) {
- return BitmapRenderer.createHardwareBitmap(bm.getWidth(), bm.getHeight(), c -> {
- final boolean drawBackgroundOnly = mTask == null || mTask.isLocked;
- if (drawBackgroundOnly) {
- c.drawPaint(mBackgroundPaint);
- } else {
- c.drawPaint(mBackgroundPaint);
- c.drawBitmap(bm, 0, 0, null);
- }
- });
- }
-
/** Updates the shader, paint, matrix to redraw. */
public void refresh() {
refresh(false);
@@ -191,7 +173,6 @@
private void refresh(boolean shouldRefreshOverlay) {
if (mThumbnailData != null && mThumbnailData.thumbnail != null) {
Bitmap bm = mThumbnailData.thumbnail;
- bm = combineThumbnailAndBackground(bm);
bm.prepareToDraw();
mBitmapShader = new BitmapShader(bm, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
mPaint.setShader(mBitmapShader);
@@ -213,6 +194,7 @@
* <p>
* If dimAlpha is 0, no dimming is applied; if dimAlpha is 1, the thumbnail will be the
* extracted background color.
+ *
*/
public void setDimAlpha(float dimAlpha) {
mDimAlpha = dimAlpha;
@@ -314,6 +296,18 @@
return;
}
}
+
+ // Always draw the background since the snapshots might be translucent or partially empty
+ // (For example, tasks been reparented out of dismissing split root when drag-to-dismiss
+ // split screen).
+ canvas.drawRoundRect(x, y, width, height, cornerRadius, cornerRadius, mBackgroundPaint);
+
+ final boolean drawBackgroundOnly = mTask == null || mTask.isLocked || mBitmapShader == null
+ || mThumbnailData == null;
+ if (drawBackgroundOnly) {
+ return;
+ }
+
canvas.drawRoundRect(x, y, width, height, cornerRadius, cornerRadius, mPaint);
}
@@ -344,6 +338,7 @@
private void updateThumbnailPaintFilter() {
ColorFilter filter = getColorFilter(mDimAlpha);
+ mBackgroundPaint.setColorFilter(filter);
int alpha = (int) (mDimAlpha * 255);
mDimmingPaintAfterClearing.setAlpha(alpha);
if (mBitmapShader != null) {
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index 1d621dc..ce033e5 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -890,15 +890,7 @@
if (confirmSecondSplitSelectApp()) {
return;
}
- if (ENABLE_QUICKSTEP_LIVE_TILE.get() && isRunningTask()) {
- RecentsView recentsView = getRecentsView();
- recentsView.switchToScreenshot(
- () -> recentsView.finishRecentsAnimation(true /* toRecents */,
- false /* shouldPip */,
- () -> showTaskMenu(iconView)));
- } else {
- showTaskMenu(iconView);
- }
+ showTaskMenu(iconView);
});
iconView.setOnLongClickListener(v -> {
requestDisallowInterceptTouchEvent(true);
@@ -1008,8 +1000,11 @@
// resetViewTransforms is called during Quickswitch scrolling.
mDismissTranslationX = mTaskOffsetTranslationX =
mTaskResistanceTranslationX = mSplitSelectTranslationX = mGridEndTranslationX = 0f;
- mDismissTranslationY = mTaskOffsetTranslationY = mTaskResistanceTranslationY =
- mSplitSelectTranslationY = 0f;
+ mDismissTranslationY = mTaskOffsetTranslationY = mTaskResistanceTranslationY = 0f;
+ if (getRecentsView() == null || !getRecentsView().isSplitSelectionActive()) {
+ mSplitSelectTranslationY = 0f;
+ }
+
setSnapshotScale(1f);
applyTranslationX();
applyTranslationY();
diff --git a/res/values-sw600dp-land/dimens.xml b/res/values-sw600dp-land/dimens.xml
index 6c5be91..daca048 100644
--- a/res/values-sw600dp-land/dimens.xml
+++ b/res/values-sw600dp-land/dimens.xml
@@ -16,14 +16,17 @@
-->
<resources>
- <!-- Hotseat -->
+<!-- Hotseat -->
<dimen name="spring_loaded_hotseat_top_margin">44dp</dimen>
- <!-- Dynamic grid -->
+<!-- Dynamic grid -->
<dimen name="dynamic_grid_edge_margin">11.33dp</dimen>
<dimen name="cell_layout_padding">11.33dp</dimen>
- <!-- Dragging -->
+<!-- Dragging -->
<dimen name="drop_target_top_margin">0dp</dimen>
<dimen name="drop_target_bottom_margin">16dp</dimen>
+
+<!-- AllApps -->
+ <dimen name="all_apps_bottom_sheet_horizontal_padding">52dp</dimen>
</resources>
diff --git a/res/values-sw600dp/dimens.xml b/res/values-sw600dp/dimens.xml
index 501ead6..73edc6f 100644
--- a/res/values-sw600dp/dimens.xml
+++ b/res/values-sw600dp/dimens.xml
@@ -23,7 +23,7 @@
<!-- AllApps -->
<dimen name="all_apps_search_bar_content_overlap">0dp</dimen>
- <dimen name="all_apps_bottom_sheet_horizontal_padding">46dp</dimen>
+ <dimen name="all_apps_bottom_sheet_horizontal_padding">48dp</dimen>
<!-- Fast scroll -->
<dimen name="fastscroll_popup_width">75dp</dimen>
diff --git a/res/values-sw720dp-land/dimens.xml b/res/values-sw720dp-land/dimens.xml
index 33da4a1..eb5c751 100644
--- a/res/values-sw720dp-land/dimens.xml
+++ b/res/values-sw720dp-land/dimens.xml
@@ -18,13 +18,20 @@
<!-- Dragging-->
<dimen name="drop_target_top_margin">0dp</dimen>
<dimen name="drop_target_bottom_margin">32dp</dimen>
+
<!-- Dynamic grid -->
<dimen name="dynamic_grid_edge_margin">21.93dp</dimen>
<dimen name="cell_layout_padding">29.33dp</dimen>
+
<!-- Hotseat -->
<dimen name="spring_loaded_hotseat_top_margin">64dp</dimen>
+
+<!-- AllApps -->
+ <dimen name="all_apps_bottom_sheet_horizontal_padding">32dp</dimen>
+
<!-- Widget picker-->
<dimen name="widget_list_horizontal_margin">49dp</dimen>
+
<!-- Bottom sheet-->
<dimen name="bottom_sheet_extra_top_padding">0dp</dimen>
</resources>
diff --git a/res/values-sw720dp/dimens.xml b/res/values-sw720dp/dimens.xml
index b4c8837..3ec211a 100644
--- a/res/values-sw720dp/dimens.xml
+++ b/res/values-sw720dp/dimens.xml
@@ -16,10 +16,12 @@
<resources>
<!-- AllApps -->
- <dimen name="all_apps_bottom_sheet_horizontal_padding">65dp</dimen>
+ <dimen name="all_apps_bottom_sheet_horizontal_padding">28dp</dimen>
+
<!-- Dynamic grid -->
<dimen name="dynamic_grid_edge_margin">27.59dp</dimen>
<dimen name="cell_layout_padding">36dp</dimen>
+
<!-- Dragging -->
<dimen name="drop_target_text_size">20sp</dimen>
<dimen name="dynamic_grid_drop_target_size">72dp</dimen>
@@ -28,6 +30,7 @@
<dimen name="drop_target_button_gap">32dp</dimen>
<dimen name="drop_target_top_margin">32dp</dimen>
<dimen name="drop_target_bottom_margin">32dp</dimen>
+
<!-- Hotseat -->
<dimen name="spring_loaded_hotseat_top_margin">164dp</dimen>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 4ed31f8..c96a228 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -241,9 +241,28 @@
if not specified -->
<attr name="borderSpaceTwoPanelLandscapeVertical" format="float" />
+ <!-- These min cell values are only used if GridDisplayOption#isScalable is true -->
+ <!-- defaults to minCellHeight, if not specified -->
+ <attr name="allAppsCellHeight" format="float" />
+ <!-- defaults to minCellWidth, if not specified -->
+ <attr name="allAppsCellWidth" format="float" />
+ <!-- defaults to allAppsCellHeight, if not specified -->
+ <attr name="allAppsCellHeightLandscape" format="float" />
+ <!-- defaults to allAppsCellWidth, if not specified -->
+ <attr name="allAppsCellWidthLandscape" format="float" />
+ <!-- defaults to allAppsCellHeight, if not specified -->
+ <attr name="allAppsCellHeightTwoPanelPortrait" format="float" />
+ <!-- defaults to allAppsCellWidth, if not specified -->
+ <attr name="allAppsCellWidthTwoPanelPortrait" format="float" />
+ <!-- defaults to allAppsCellHeight, if not specified -->
+ <attr name="allAppsCellHeightTwoPanelLandscape" format="float" />
+ <!-- defaults to allAppsCellWidth, if not specified -->
+ <attr name="allAppsCellWidthTwoPanelLandscape" format="float" />
<!-- defaults to borderSpace, if not specified -->
<attr name="allAppsBorderSpace" format="float" />
<!-- defaults to allAppsBorderSpace, if not specified -->
+ <attr name="allAppsBorderSpaceLandscape" format="float" />
+ <!-- defaults to allAppsBorderSpace, if not specified -->
<attr name="allAppsBorderSpaceTwoPanelPortrait" format="float" />
<!-- defaults to allAppsBorderSpace, if not specified -->
<attr name="allAppsBorderSpaceTwoPanelLandscape" format="float" />
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index a6abee2..0615053 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -359,7 +359,9 @@
<dimen name="overview_grid_side_margin">0dp</dimen>
<dimen name="overview_grid_row_spacing">0dp</dimen>
<dimen name="overview_page_spacing">0dp</dimen>
- <dimen name="split_placeholder_size">110dp</dimen>
+ <dimen name="split_placeholder_size">72dp</dimen>
+ <dimen name="split_placeholder_inset">16dp</dimen>
+ <dimen name="split_placeholder_icon_size">44dp</dimen>
<dimen name="task_menu_width_grid">200dp</dimen>
diff --git a/src/com/android/launcher3/BaseDraggingActivity.java b/src/com/android/launcher3/BaseDraggingActivity.java
index 3af43c0..6de3884 100644
--- a/src/com/android/launcher3/BaseDraggingActivity.java
+++ b/src/com/android/launcher3/BaseDraggingActivity.java
@@ -216,6 +216,7 @@
* Creates and returns {@link SearchAdapterProvider} for build variant specific search result
* views
*/
+ @Override
public SearchAdapterProvider<?> createSearchAdapterProvider(
ActivityAllAppsContainerView<?> allApps) {
return new DefaultSearchAdapterProvider(this);
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index e184a91..f7133c4 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -93,7 +93,7 @@
private int mFixedCellWidth;
private int mFixedCellHeight;
@ViewDebug.ExportedProperty(category = "launcher")
- private final Point mBorderSpace;
+ private Point mBorderSpace;
@ViewDebug.ExportedProperty(category = "launcher")
private int mCountX;
@@ -239,22 +239,7 @@
mActivity = ActivityContext.lookupContext(context);
DeviceProfile deviceProfile = mActivity.getDeviceProfile();
- switch (mContainerType) {
- case FOLDER:
- mBorderSpace = new Point(deviceProfile.folderCellLayoutBorderSpacePx);
- break;
- case HOTSEAT:
- mBorderSpace = new Point(deviceProfile.hotseatBorderSpace,
- deviceProfile.hotseatBorderSpace);
- break;
- case WORKSPACE:
- default:
- mBorderSpace = new Point(deviceProfile.cellLayoutBorderSpacePx);
- break;
- }
-
- mCellWidth = mCellHeight = -1;
- mFixedCellWidth = mFixedCellHeight = -1;
+ resetCellSizeInternal(deviceProfile);
mCountX = deviceProfile.inv.numColumns;
mCountY = deviceProfile.inv.numRows;
@@ -379,6 +364,12 @@
return mShortcutsAndWidgets.getLayerType() == LAYER_TYPE_HARDWARE;
}
+ /**
+ * Change sizes of cells
+ *
+ * @param width the new width of the cells
+ * @param height the new height of the cells
+ */
public void setCellDimensions(int width, int height) {
mFixedCellWidth = mCellWidth = width;
mFixedCellHeight = mCellHeight = height;
@@ -386,6 +377,33 @@
mBorderSpace);
}
+ private void resetCellSizeInternal(DeviceProfile deviceProfile) {
+ switch (mContainerType) {
+ case FOLDER:
+ mBorderSpace = new Point(deviceProfile.folderCellLayoutBorderSpacePx);
+ break;
+ case HOTSEAT:
+ mBorderSpace = new Point(deviceProfile.hotseatBorderSpace,
+ deviceProfile.hotseatBorderSpace);
+ break;
+ case WORKSPACE:
+ default:
+ mBorderSpace = new Point(deviceProfile.cellLayoutBorderSpacePx);
+ break;
+ }
+
+ mCellWidth = mCellHeight = -1;
+ mFixedCellWidth = mFixedCellHeight = -1;
+ }
+
+ /**
+ * Reset the cell sizes and border space
+ */
+ public void resetCellSize(DeviceProfile deviceProfile) {
+ resetCellSizeInternal(deviceProfile);
+ requestLayout();
+ }
+
public void setGridSize(int x, int y) {
mCountX = x;
mCountY = y;
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 91fa4ca..0c33bce 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -624,14 +624,15 @@
+ textHeight + (topBottomPadding * 2);
}
- private void updateAllAppsWidth(Resources res) {
+ private void updateAllAppsContainerWidth(Resources res) {
int cellLayoutHorizontalPadding =
(cellLayoutPaddingPx.left + cellLayoutPaddingPx.right) / 2;
if (isTablet) {
- allAppsLeftRightPadding = res.getDimensionPixelSize(
- R.dimen.all_apps_bottom_sheet_horizontal_padding) + cellLayoutHorizontalPadding;
+ allAppsLeftRightPadding =
+ res.getDimensionPixelSize(R.dimen.all_apps_bottom_sheet_horizontal_padding);
+
int usedWidth = (allAppsCellWidthPx * numShownAllAppsColumns)
- + (allAppsBorderSpacePx.x * (numShownAllAppsColumns + 1))
+ + (allAppsBorderSpacePx.x * (numShownAllAppsColumns - 1))
+ allAppsLeftRightPadding * 2;
allAppsLeftRightMargin = Math.max(1, (availableWidthPx - usedWidth) / 2);
} else {
@@ -755,24 +756,26 @@
* Updates the iconSize for allApps* variants.
*/
public void updateAllAppsIconSize(float scale, Resources res) {
- if (numShownAllAppsColumns != inv.numColumns) {
+ //TODO(b/218638090): remove the tablet condition once we have phone specs
+ if (isScalableGrid && isTablet) {
allAppsIconSizePx =
pxFromDp(inv.allAppsIconSize[mTypeIndex], mMetrics);
allAppsIconTextSizePx =
pxFromSp(inv.allAppsIconTextSize[mTypeIndex], mMetrics);
allAppsIconDrawablePaddingPx = iconDrawablePaddingOriginalPx;
- autoResizeAllAppsCells();
+ allAppsCellWidthPx = pxFromDp(inv.allAppsCellSize[mTypeIndex].x, mMetrics, scale);
+ allAppsCellHeightPx = pxFromDp(inv.allAppsCellSize[mTypeIndex].y, mMetrics, scale);
} else {
float invIconSizeDp = inv.iconSize[mTypeIndex];
float invIconTextSizeSp = inv.iconTextSize[mTypeIndex];
allAppsIconSizePx = Math.max(1, pxFromDp(invIconSizeDp, mMetrics, scale));
allAppsIconTextSizePx = (int) (pxFromSp(invIconTextSizeSp, mMetrics) * scale);
allAppsIconDrawablePaddingPx = (int) (iconDrawablePaddingOriginalPx * scale);
+ allAppsCellWidthPx = allAppsIconSizePx + (2 * allAppsIconDrawablePaddingPx);
allAppsCellHeightPx = getCellSize().y;
}
- allAppsCellWidthPx = allAppsIconSizePx + (2 * allAppsIconDrawablePaddingPx);
- updateAllAppsWidth(res);
+ updateAllAppsContainerWidth(res);
if (isVerticalBarLayout()) {
hideWorkspaceLabelsIfNotEnoughSpace();
}
@@ -979,8 +982,17 @@
*/
public Rect getHotseatLayoutPadding(Context context) {
if (isVerticalBarLayout()) {
- int paddingTop = Math.max(mInsets.top - cellLayoutPaddingPx.top, 0);
- int paddingBottom = Math.max(mInsets.bottom - cellLayoutPaddingPx.bottom, 0);
+ // The hotseat icons will be placed in the middle of the hotseat cells.
+ // Changing the hotseatCellHeightPx is not affecting hotseat icon positions
+ // in vertical bar layout.
+ // Workspace icons are moved up by a small factor. The variable diffOverlapFactor
+ // is set to account for that difference.
+ float diffOverlapFactor = iconSizePx * (ICON_OVERLAP_FACTOR - 1) / 2;
+ int paddingTop = Math.max((int) (mInsets.top + cellLayoutPaddingPx.top
+ - diffOverlapFactor), 0);
+ int paddingBottom = Math.max((int) (mInsets.bottom + cellLayoutPaddingPx.bottom
+ + diffOverlapFactor), 0);
+
if (isSeascape()) {
mHotseatPadding.set(mInsets.left + hotseatBarSidePaddingStartPx, paddingTop,
hotseatBarSidePaddingEndPx, paddingBottom);
@@ -998,7 +1010,7 @@
additionalLeftSpace = qsbWidth + hotseatBorderSpace;
}
- int hotseatTopDiff = hotseatHeight - taskbarOffset;
+ int hotseatTopPadding = hotseatHeight - taskbarOffset - hotseatCellHeightPx;
int endOffset = ApiWrapper.getHotseatEndOffset(context);
int requiredWidth = iconSizePx * numShownHotseatIcons
@@ -1007,7 +1019,7 @@
int hotseatSize = Math.min(requiredWidth, availableWidthPx - endOffset);
int sideSpacing = (availableWidthPx - hotseatSize) / 2;
- mHotseatPadding.set(sideSpacing + additionalLeftSpace, hotseatTopDiff, sideSpacing,
+ mHotseatPadding.set(sideSpacing + additionalLeftSpace, hotseatTopPadding, sideSpacing,
taskbarOffset);
if (endOffset > sideSpacing) {
@@ -1223,6 +1235,7 @@
allAppsIconDrawablePaddingPx));
writer.println(prefix + pxToDpStr("allAppsCellHeightPx", allAppsCellHeightPx));
writer.println(prefix + pxToDpStr("allAppsCellWidthPx", allAppsCellWidthPx));
+ writer.println(prefix + pxToDpStr("allAppsBorderSpacePx", allAppsBorderSpacePx.x));
writer.println(prefix + "\tnumShownAllAppsColumns: " + numShownAllAppsColumns);
writer.println(prefix + pxToDpStr("allAppsLeftRightPadding", allAppsLeftRightPadding));
writer.println(prefix + pxToDpStr("allAppsLeftRightMargin", allAppsLeftRightMargin));
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index e1680fc..9c749aa7 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -84,6 +84,7 @@
removeAllViewsInLayout();
mHasVerticalHotseat = hasVerticalHotseat;
DeviceProfile dp = mActivity.getDeviceProfile();
+ resetCellSize(dp);
if (hasVerticalHotseat) {
setGridSize(1, dp.numShownHotseatIcons);
} else {
@@ -110,10 +111,9 @@
mQsb.setVisibility(View.VISIBLE);
lp.gravity = Gravity.BOTTOM;
lp.width = ViewGroup.LayoutParams.MATCH_PARENT;
- lp.height = (grid.isTaskbarPresent
+ lp.height = grid.isTaskbarPresent
? grid.workspacePadding.bottom
- : grid.hotseatBarSizePx)
- + (grid.isTaskbarPresent ? grid.taskbarSize : insets.bottom);
+ : grid.hotseatBarSizePx + insets.bottom;
}
Rect padding = grid.getHotseatLayoutPadding(getContext());
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index 9dd1493..219ed9e 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -128,6 +128,7 @@
public float[] horizontalMargin;
+ public PointF[] allAppsCellSize;
public float[] allAppsIconSize;
public float[] allAppsIconTextSize;
public PointF[] allAppsBorderSpaces;
@@ -357,6 +358,7 @@
numDatabaseAllAppsColumns = deviceType == TYPE_MULTI_DISPLAY
? closestProfile.numDatabaseAllAppsColumns : closestProfile.numAllAppsColumns;
+ allAppsCellSize = displayOption.allAppsCellSize;
allAppsBorderSpaces = displayOption.allAppsBorderSpaces;
allAppsIconSize = displayOption.allAppsIconSizes;
allAppsIconTextSize = displayOption.allAppsIconTextSizes;
@@ -798,6 +800,7 @@
private final float[] iconSizes = new float[COUNT_SIZES];
private final float[] textSizes = new float[COUNT_SIZES];
+ private final PointF[] allAppsCellSize = new PointF[COUNT_SIZES];
private final float[] allAppsIconSizes = new float[COUNT_SIZES];
private final float[] allAppsIconTextSizes = new float[COUNT_SIZES];
private final PointF[] allAppsBorderSpaces = new PointF[COUNT_SIZES];
@@ -873,9 +876,35 @@
folderBorderSpace = borderSpace;
+ x = a.getFloat(R.styleable.ProfileDisplayOption_allAppsCellWidth,
+ minCellSize[INDEX_DEFAULT].x);
+ y = a.getFloat(R.styleable.ProfileDisplayOption_allAppsCellHeight,
+ minCellSize[INDEX_DEFAULT].y);
+ allAppsCellSize[INDEX_DEFAULT] = new PointF(x, y);
+
+ x = a.getFloat(R.styleable.ProfileDisplayOption_allAppsCellWidthLandscape,
+ allAppsCellSize[INDEX_DEFAULT].x);
+ y = a.getFloat(R.styleable.ProfileDisplayOption_allAppsCellHeightLandscape,
+ allAppsCellSize[INDEX_DEFAULT].y);
+ allAppsCellSize[INDEX_LANDSCAPE] = new PointF(x, y);
+
+ x = a.getFloat(R.styleable.ProfileDisplayOption_allAppsCellWidthTwoPanelPortrait,
+ allAppsCellSize[INDEX_DEFAULT].x);
+ y = a.getFloat(R.styleable.ProfileDisplayOption_allAppsCellHeightTwoPanelPortrait,
+ allAppsCellSize[INDEX_DEFAULT].y);
+ allAppsCellSize[INDEX_TWO_PANEL_PORTRAIT] = new PointF(x, y);
+
+ x = a.getFloat(R.styleable.ProfileDisplayOption_allAppsCellWidthTwoPanelLandscape,
+ allAppsCellSize[INDEX_DEFAULT].x);
+ y = a.getFloat(R.styleable.ProfileDisplayOption_allAppsCellHeightTwoPanelLandscape,
+ allAppsCellSize[INDEX_DEFAULT].y);
+ allAppsCellSize[INDEX_TWO_PANEL_LANDSCAPE] = new PointF(x, y);
+
x = y = a.getFloat(R.styleable.ProfileDisplayOption_allAppsBorderSpace,
borderSpace);
allAppsBorderSpaces[INDEX_DEFAULT] = new PointF(x, y);
+ x = y = a.getFloat(R.styleable.ProfileDisplayOption_allAppsBorderSpaceLandscape,
+ allAppsBorderSpaces[INDEX_DEFAULT].x);
allAppsBorderSpaces[INDEX_LANDSCAPE] = new PointF(x, y);
x = y = a.getFloat(
R.styleable.ProfileDisplayOption_allAppsBorderSpaceTwoPanelPortrait,
@@ -971,6 +1000,7 @@
textSizes[i] = 0;
borderSpaces[i] = new PointF();
minCellSize[i] = new PointF();
+ allAppsCellSize[i] = new PointF();
allAppsIconSizes[i] = 0;
allAppsIconTextSizes[i] = 0;
allAppsBorderSpaces[i] = new PointF();
@@ -987,6 +1017,8 @@
minCellSize[i].y *= w;
horizontalMargin[i] *= w;
hotseatBorderSpaces[i] *= w;
+ allAppsCellSize[i].x *= w;
+ allAppsCellSize[i].y *= w;
allAppsIconSizes[i] *= w;
allAppsIconTextSizes[i] *= w;
allAppsBorderSpaces[i].x *= w;
@@ -1008,6 +1040,8 @@
minCellSize[i].y += p.minCellSize[i].y;
horizontalMargin[i] += p.horizontalMargin[i];
hotseatBorderSpaces[i] += p.hotseatBorderSpaces[i];
+ allAppsCellSize[i].x += p.allAppsCellSize[i].x;
+ allAppsCellSize[i].y += p.allAppsCellSize[i].y;
allAppsIconSizes[i] += p.allAppsIconSizes[i];
allAppsIconTextSizes[i] += p.allAppsIconTextSizes[i];
allAppsBorderSpaces[i].x += p.allAppsBorderSpaces[i].x;
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 2f9b563..1cead11 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -651,7 +651,7 @@
mDragLayer.onOneHandedModeStateChanged(activated);
}
- private void initDeviceProfile(InvariantDeviceProfile idp) {
+ protected void initDeviceProfile(InvariantDeviceProfile idp) {
// Load configuration-specific DeviceProfile
mDeviceProfile = idp.getDeviceProfile(this);
if (isInMultiWindowMode()) {
diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java
index be2cd88..baee49f 100644
--- a/src/com/android/launcher3/LauncherState.java
+++ b/src/com/android/launcher3/LauncherState.java
@@ -16,6 +16,7 @@
package com.android.launcher3;
import static com.android.launcher3.anim.Interpolators.ACCEL_2;
+import static com.android.launcher3.anim.Interpolators.DEACCEL_2;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_OVERVIEW;
import static com.android.launcher3.testing.TestProtocol.ALL_APPS_STATE_ORDINAL;
@@ -91,6 +92,14 @@
}
};
+ protected static final PageTranslationProvider DEFAULT_PAGE_TRANSLATION_PROVIDER =
+ new PageTranslationProvider(DEACCEL_2) {
+ @Override
+ public float getPageTranslation(int pageIndex) {
+ return 0;
+ }
+ };
+
private static final LauncherState[] sAllStates = new LauncherState[10];
/**
@@ -288,6 +297,25 @@
};
}
+ /**
+ * Gets the translation provider for workspace pages.
+ */
+ public PageTranslationProvider getWorkspacePageTranslationProvider(Launcher launcher) {
+ if (this != SPRING_LOADED || !launcher.getDeviceProfile().isTwoPanels) {
+ return DEFAULT_PAGE_TRANSLATION_PROVIDER;
+ }
+ final float quarterPageSpacing = launcher.getWorkspace().getPageSpacing() / 4f;
+ return new PageTranslationProvider(DEACCEL_2) {
+ @Override
+ public float getPageTranslation(int pageIndex) {
+ boolean isRtl = launcher.getWorkspace().mIsRtl;
+ boolean isFirstPage = pageIndex % 2 == 0;
+ return ((isFirstPage && !isRtl) || (!isFirstPage && isRtl)) ? -quarterPageSpacing
+ : quarterPageSpacing;
+ }
+ };
+ }
+
@Override
public LauncherState getHistoryForState(LauncherState previousState) {
// No history is supported
@@ -318,6 +346,23 @@
public abstract float getPageAlpha(int pageIndex);
}
+ /**
+ * Provider for the translation and animation interpolation of workspace pages.
+ */
+ public abstract static class PageTranslationProvider {
+
+ public final Interpolator interpolator;
+
+ public PageTranslationProvider(Interpolator interpolator) {
+ this.interpolator = interpolator;
+ }
+
+ /**
+ * Gets the translation of the workspace page at the provided page index.
+ */
+ public abstract float getPageTranslation(int pageIndex);
+ }
+
public static class ScaleAndTranslation {
public float scale;
public float translationX;
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index d94e84c..1e09b2d 100644
--- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -39,6 +39,7 @@
import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_TRANSLATE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_SCRIM_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_FADE;
+import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_PAGE_TRANSLATE_X;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_SCALE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_TRANSLATE;
import static com.android.launcher3.states.StateAnimationConfig.SKIP_SCRIM;
@@ -49,6 +50,7 @@
import android.view.animation.Interpolator;
import com.android.launcher3.LauncherState.PageAlphaProvider;
+import com.android.launcher3.LauncherState.PageTranslationProvider;
import com.android.launcher3.LauncherState.ScaleAndTranslation;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.anim.PropertySetter;
@@ -155,6 +157,12 @@
scaleAndTranslation.translationX, translationInterpolator);
propertySetter.setFloat(mWorkspace, VIEW_TRANSLATE_Y,
scaleAndTranslation.translationY, translationInterpolator);
+ PageTranslationProvider pageTranslationProvider = state.getWorkspacePageTranslationProvider(
+ mLauncher);
+ for (int i = 0; i < childCount; i++) {
+ applyPageTranslation((CellLayout) mWorkspace.getChildAt(i), i, pageTranslationProvider,
+ propertySetter, config);
+ }
Interpolator hotseatTranslationInterpolator = config.getInterpolator(
ANIM_HOTSEAT_TRANSLATE, translationInterpolator);
@@ -202,6 +210,16 @@
pageAlpha, fadeInterpolator);
}
+ private void applyPageTranslation(CellLayout cellLayout, int childIndex,
+ PageTranslationProvider pageTranslationProvider, PropertySetter propertySetter,
+ StateAnimationConfig config) {
+ float pageTranslation = pageTranslationProvider.getPageTranslation(childIndex);
+ Interpolator translationInterpolator = config.getInterpolator(
+ ANIM_WORKSPACE_PAGE_TRANSLATE_X, pageTranslationProvider.interpolator);
+ propertySetter.setFloat(cellLayout, VIEW_TRANSLATE_X, pageTranslation,
+ translationInterpolator);
+ }
+
/**
* Returns a spring based animator for the scale property of {@param workspace}.
*/
diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
index b94a612..11e0a1f 100644
--- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
@@ -26,12 +26,13 @@
import androidx.core.graphics.ColorUtils;
import androidx.recyclerview.widget.RecyclerView;
-import com.android.launcher3.BaseDraggingActivity;
+import com.android.launcher3.DeviceProfile.DeviceProfileListenable;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.allapps.search.SearchAdapterProvider;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.PackageManagerHelper;
+import com.android.launcher3.views.AppLauncher;
import java.util.Objects;
@@ -40,8 +41,8 @@
*
* @param <T> Type of context inflating all apps.
*/
-public class ActivityAllAppsContainerView<T extends BaseDraggingActivity> extends
- BaseAllAppsContainerView<T> {
+public class ActivityAllAppsContainerView<T extends Context & AppLauncher
+ & DeviceProfileListenable> extends BaseAllAppsContainerView<T> {
protected SearchUiManager mSearchUiManager;
/**
@@ -103,13 +104,8 @@
}
}
- /** Handles selection on focused view and returns {@code true} on success. */
- public boolean launchHighlightedItem() {
- return getMainAdapterProvider().launchHighlightedItem();
- }
-
@Override
- protected SearchAdapterProvider<?> createMainAdapterProvider() {
+ protected final SearchAdapterProvider<?> createMainAdapterProvider() {
return mActivityContext.createSearchAdapterProvider(this);
}
diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
index 16264da..7687fea 100644
--- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -84,7 +84,7 @@
private final ArrayList<AdapterItem> mSearchResults = new ArrayList<>();
private BaseAllAppsAdapter<T> mAdapter;
private AppInfoComparator mAppNameComparator;
- private final int mNumAppsPerRow;
+ private final int mNumAppsPerRowAllApps;
private int mNumAppRowsInAdapter;
private ItemInfoMatcher mItemFilter;
@@ -94,7 +94,7 @@
mActivityContext = ActivityContext.lookupContext(context);
mAppNameComparator = new AppInfoComparator(context);
mWorkAdapterProvider = adapterProvider;
- mNumAppsPerRow = mActivityContext.getDeviceProfile().inv.numColumns;
+ mNumAppsPerRowAllApps = mActivityContext.getDeviceProfile().inv.numAllAppsColumns;
mAllAppsStore.addUpdateListener(this);
}
@@ -336,7 +336,7 @@
}
}
- if (mNumAppsPerRow != 0) {
+ if (mNumAppsPerRowAllApps != 0) {
// Update the number of rows in the adapter after we do all the merging (otherwise, we
// would have to shift the values again)
int numAppsInSection = 0;
@@ -344,10 +344,10 @@
int rowIndex = -1;
for (AdapterItem item : mAdapterItems) {
item.rowIndex = 0;
- if (AllAppsGridAdapter.isDividerViewType(item.viewType)) {
+ if (BaseAllAppsAdapter.isDividerViewType(item.viewType)) {
numAppsInSection = 0;
- } else if (AllAppsGridAdapter.isIconViewType(item.viewType)) {
- if (numAppsInSection % mNumAppsPerRow == 0) {
+ } else if (BaseAllAppsAdapter.isIconViewType(item.viewType)) {
+ if (numAppsInSection % mNumAppsPerRowAllApps == 0) {
numAppsInRow = 0;
rowIndex++;
}
@@ -365,12 +365,13 @@
float rowFraction = 1f / mNumAppRowsInAdapter;
for (FastScrollSectionInfo info : mFastScrollerSections) {
AdapterItem item = info.fastScrollToItem;
- if (!AllAppsGridAdapter.isIconViewType(item.viewType)) {
+ if (!BaseAllAppsAdapter.isIconViewType(item.viewType)) {
info.touchFraction = 0f;
continue;
}
- float subRowFraction = item.rowAppIndex * (rowFraction / mNumAppsPerRow);
+ float subRowFraction =
+ item.rowAppIndex * (rowFraction / mNumAppsPerRowAllApps);
info.touchFraction = item.rowIndex * rowFraction + subRowFraction;
}
break;
@@ -379,7 +380,7 @@
float cumulativeTouchFraction = 0f;
for (FastScrollSectionInfo info : mFastScrollerSections) {
AdapterItem item = info.fastScrollToItem;
- if (!AllAppsGridAdapter.isIconViewType(item.viewType)) {
+ if (!BaseAllAppsAdapter.isIconViewType(item.viewType)) {
info.touchFraction = 0f;
continue;
}
diff --git a/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java b/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
index 1d1960d..976284d 100644
--- a/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
+++ b/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
@@ -163,10 +163,10 @@
protected String mEmptySearchMessage;
protected int mAppsPerRow;
- private final LayoutInflater mLayoutInflater;
- private final OnClickListener mOnIconClickListener;
- private OnLongClickListener mOnIconLongClickListener = INSTANCE_ALL_APPS;
- private OnFocusChangeListener mIconFocusListener;
+ protected final LayoutInflater mLayoutInflater;
+ protected final OnClickListener mOnIconClickListener;
+ protected OnLongClickListener mOnIconLongClickListener = INSTANCE_ALL_APPS;
+ protected OnFocusChangeListener mIconFocusListener;
// The click listener to send off to the market app, updated each time the search query changes.
private OnClickListener mMarketSearchClickListener;
private final int mExtraHeight;
diff --git a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
index fd8945a..a6a47a7 100644
--- a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
+++ b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
@@ -29,14 +29,13 @@
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
-import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.ExtendedEditText;
-import com.android.launcher3.Launcher;
import com.android.launcher3.Utilities;
import com.android.launcher3.allapps.BaseAllAppsAdapter.AdapterItem;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.search.SearchAlgorithm;
import com.android.launcher3.search.SearchCallback;
+import com.android.launcher3.views.ActivityContext;
/**
* An interface to a search box that AllApps can command.
@@ -45,7 +44,7 @@
implements TextWatcher, OnEditorActionListener, ExtendedEditText.OnBackKeyListener,
OnFocusChangeListener {
- protected BaseDraggingActivity mLauncher;
+ protected ActivityContext mLauncher;
protected SearchCallback<AdapterItem> mCallback;
protected ExtendedEditText mInput;
protected String mQuery;
@@ -62,7 +61,7 @@
*/
public final void initialize(
SearchAlgorithm<AdapterItem> searchAlgorithm, ExtendedEditText input,
- BaseDraggingActivity launcher, SearchCallback<AdapterItem> callback) {
+ ActivityContext launcher, SearchCallback<AdapterItem> callback) {
mCallback = callback;
mLauncher = launcher;
@@ -125,7 +124,7 @@
mLauncher.getStatsLogManager().logger()
.log(LAUNCHER_ALLAPPS_FOCUSED_ITEM_SELECTED_WITH_IME);
// selectFocusedView should return SearchTargetEvent that is passed onto onClick
- return Launcher.getLauncher(mLauncher).getAppsView().launchHighlightedItem();
+ return mLauncher.getAppsView().getMainAdapterProvider().launchHighlightedItem();
}
return false;
}
diff --git a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
index cb459ea..893e547 100644
--- a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
+++ b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
@@ -32,7 +32,6 @@
import android.view.View;
import android.view.ViewGroup.MarginLayoutParams;
-import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.ExtendedEditText;
import com.android.launcher3.Insettable;
@@ -43,6 +42,7 @@
import com.android.launcher3.allapps.BaseAllAppsAdapter.AdapterItem;
import com.android.launcher3.allapps.SearchUiManager;
import com.android.launcher3.search.SearchCallback;
+import com.android.launcher3.views.ActivityContext;
import java.util.ArrayList;
@@ -53,7 +53,7 @@
implements SearchUiManager, SearchCallback<AdapterItem>,
AllAppsStore.OnUpdateListener, Insettable {
- private final BaseDraggingActivity mLauncher;
+ private final ActivityContext mLauncher;
private final AllAppsSearchBarController mSearchBarController;
private final SpannableStringBuilder mSearchQueryBuilder;
@@ -74,7 +74,7 @@
public AppsSearchContainerLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
- mLauncher = BaseDraggingActivity.fromContext(context);
+ mLauncher = ActivityContext.lookupContext(context);
mSearchBarController = new AllAppsSearchBarController();
mSearchQueryBuilder = new SpannableStringBuilder();
@@ -134,7 +134,7 @@
mApps = appsView.getApps();
mAppsView = appsView;
mSearchBarController.initialize(
- new DefaultAppSearchAlgorithm(mLauncher),
+ new DefaultAppSearchAlgorithm(getContext()),
this, mLauncher, this);
}
diff --git a/src/com/android/launcher3/allapps/search/DefaultSearchAdapterProvider.java b/src/com/android/launcher3/allapps/search/DefaultSearchAdapterProvider.java
index 2fe4915..a95bd51 100644
--- a/src/com/android/launcher3/allapps/search/DefaultSearchAdapterProvider.java
+++ b/src/com/android/launcher3/allapps/search/DefaultSearchAdapterProvider.java
@@ -23,20 +23,20 @@
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
-import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.allapps.AllAppsGridAdapter;
import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.views.AppLauncher;
/**
- * Provides views for local search results
+ * Provides views for local search results.
*/
-public class DefaultSearchAdapterProvider extends SearchAdapterProvider<BaseDraggingActivity> {
+public class DefaultSearchAdapterProvider extends SearchAdapterProvider<AppLauncher> {
private final RecyclerView.ItemDecoration mDecoration;
private View mHighlightedView;
- public DefaultSearchAdapterProvider(BaseDraggingActivity launcher) {
+ public DefaultSearchAdapterProvider(AppLauncher launcher) {
super(launcher);
mDecoration = new RecyclerView.ItemDecoration() {
@Override
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index de33ae5..7727fae 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -258,6 +258,9 @@
"ENABLE_NEW_MIGRATION_LOGIC", true,
"Enable the new grid migration logic, keeping pages when src < dest");
+ public static final BooleanFlag ENABLE_ONE_SEARCH_MOTION = new DeviceFlag(
+ "ENABLE_ONE_SEARCH_MOTION", true, "Enables animations in OneSearch.");
+
public static void initialize(Context context) {
synchronized (sDebugFlags) {
for (DebugFlag flag : sDebugFlags) {
diff --git a/src/com/android/launcher3/icons/IconCache.java b/src/com/android/launcher3/icons/IconCache.java
index 5ece4a6..7ba2317 100644
--- a/src/com/android/launcher3/icons/IconCache.java
+++ b/src/com/android/launcher3/icons/IconCache.java
@@ -16,6 +16,7 @@
package com.android.launcher3.icons;
+import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
import static com.android.launcher3.widget.WidgetSections.NO_CATEGORY;
@@ -340,14 +341,15 @@
Map<Pair<UserHandle, Boolean>, List<IconRequestInfo<T>>> iconLoadSubsectionsMap =
iconRequestInfos.stream()
.filter(iconRequest -> {
- if (iconRequest.itemInfo.getTargetComponent() != null) {
- return true;
+ if (iconRequest.itemInfo.getTargetComponent() == null) {
+ Log.i(TAG,
+ "Skipping Item info with null component name: "
+ + iconRequest.itemInfo);
+ iconRequest.itemInfo.bitmap = getDefaultIcon(
+ iconRequest.itemInfo.user);
+ return false;
}
- Log.i(TAG,
- "Skipping Item info with null component name: "
- + iconRequest.itemInfo);
- iconRequest.itemInfo.bitmap = getDefaultIcon(iconRequest.itemInfo.user);
- return false;
+ return true;
})
.collect(groupingBy(iconRequest ->
Pair.create(iconRequest.itemInfo.user, iconRequest.useLowResIcon)));
@@ -356,6 +358,17 @@
iconLoadSubsectionsMap.forEach((sectionKey, filteredList) -> {
Map<ComponentName, List<IconRequestInfo<T>>> duplicateIconRequestsMap =
filteredList.stream()
+ .filter(iconRequest -> {
+ // Filter out icons that should not share the same bitmap and title
+ if (iconRequest.itemInfo.itemType == ITEM_TYPE_DEEP_SHORTCUT) {
+ Log.e(TAG,
+ "Skipping Item info for deep shortcut: "
+ + iconRequest.itemInfo,
+ new IllegalStateException());
+ return false;
+ }
+ return true;
+ })
.collect(groupingBy(iconRequest ->
iconRequest.itemInfo.getTargetComponent()));
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index b9fa21d..f1c5d59 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -615,7 +615,13 @@
}
if (info != null) {
- iconRequestInfos.add(c.createIconRequestInfo(info, useLowResIcon));
+ if (info.itemType
+ != LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
+ // Skip deep shortcuts; their title and icons have already been
+ // loaded above.
+ iconRequestInfos.add(
+ c.createIconRequestInfo(info, useLowResIcon));
+ }
c.applyCommonProperties(info);
diff --git a/src/com/android/launcher3/states/StateAnimationConfig.java b/src/com/android/launcher3/states/StateAnimationConfig.java
index bd6f7d3..f04e685 100644
--- a/src/com/android/launcher3/states/StateAnimationConfig.java
+++ b/src/com/android/launcher3/states/StateAnimationConfig.java
@@ -62,6 +62,7 @@
ANIM_OVERVIEW_MODAL,
ANIM_DEPTH,
ANIM_OVERVIEW_ACTIONS_FADE,
+ ANIM_WORKSPACE_PAGE_TRANSLATE_X,
})
@Retention(RetentionPolicy.SOURCE)
public @interface AnimType {}
@@ -80,8 +81,9 @@
public static final int ANIM_OVERVIEW_MODAL = 12;
public static final int ANIM_DEPTH = 13;
public static final int ANIM_OVERVIEW_ACTIONS_FADE = 14;
+ public static final int ANIM_WORKSPACE_PAGE_TRANSLATE_X = 15;
- private static final int ANIM_TYPES_COUNT = 15;
+ private static final int ANIM_TYPES_COUNT = 16;
protected final Interpolator[] mInterpolators = new Interpolator[ANIM_TYPES_COUNT];
diff --git a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
index 2609e54..4fcba18 100644
--- a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
+++ b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
@@ -16,6 +16,7 @@
package com.android.launcher3.touch;
+import static android.view.Gravity.BOTTOM;
import static android.view.Gravity.CENTER_VERTICAL;
import static android.view.Gravity.END;
import static android.view.Gravity.START;
@@ -393,12 +394,21 @@
}
@Override
- public void getInitialSplitPlaceholderBounds(int placeholderHeight, DeviceProfile dp,
- @StagePosition int stagePosition, Rect out) {
+ public void getInitialSplitPlaceholderBounds(int placeholderHeight, int placeholderInset,
+ DeviceProfile dp, @StagePosition int stagePosition, Rect out) {
// In fake land/seascape, the placeholder always needs to go to the "top" of the device,
// which is the same bounds as 0 rotation.
int width = dp.widthPx;
out.set(0, 0, width, placeholderHeight);
+ out.inset(placeholderInset, 0);
+
+ // Adjust the top to account for content off screen. This will help to animate the view in
+ // with rounded corners.
+ int screenWidth = dp.widthPx;
+ int screenHeight = dp.heightPx;
+ int totalHeight = (int) (1.0f * screenHeight / 2 * (screenWidth - 2 * placeholderInset)
+ / screenWidth);
+ out.top -= (totalHeight - placeholderHeight);
}
@Override
@@ -414,14 +424,17 @@
@Override
public void setSplitTaskSwipeRect(DeviceProfile dp, Rect outRect,
StagedSplitBounds splitInfo, int desiredStagePosition) {
- float diff;
- float horizontalDividerDiff = splitInfo.visualDividerBounds.width() / 2f;
+ float topLeftTaskPercent = splitInfo.appsStackedVertically
+ ? splitInfo.topTaskPercent
+ : splitInfo.leftTaskPercent;
+ float dividerBarPercent = splitInfo.appsStackedVertically
+ ? splitInfo.dividerHeightPercent
+ : splitInfo.dividerWidthPercent;
+
if (desiredStagePosition == SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT) {
- diff = outRect.height() * (1f - splitInfo.leftTaskPercent) + horizontalDividerDiff;
- outRect.bottom -= diff;
+ outRect.bottom = outRect.top + (int) (outRect.height() * topLeftTaskPercent);
} else {
- diff = outRect.height() * splitInfo.leftTaskPercent + horizontalDividerDiff;
- outRect.top += diff;
+ outRect.top += (int) (outRect.height() * (topLeftTaskPercent + dividerBarPercent));
}
}
@@ -468,18 +481,42 @@
@Override
public void setSplitIconParams(View primaryIconView, View secondaryIconView,
int taskIconHeight, int primarySnapshotWidth, int primarySnapshotHeight,
- boolean isRtl, DeviceProfile deviceProfile, StagedSplitBounds splitConfig) {
+ int groupedTaskViewHeight, int groupedTaskViewWidth, boolean isRtl,
+ DeviceProfile deviceProfile, StagedSplitBounds splitConfig) {
FrameLayout.LayoutParams primaryIconParams =
(FrameLayout.LayoutParams) primaryIconView.getLayoutParams();
FrameLayout.LayoutParams secondaryIconParams =
new FrameLayout.LayoutParams(primaryIconParams);
- primaryIconParams.gravity = CENTER_VERTICAL | (isRtl ? START : END);
+ // We calculate the "midpoint" of the thumbnail area, and place the icons there.
+ // This is the place where the thumbnail area splits by default, in a near-50/50 split.
+ // It is usually not exactly 50/50, due to insets/screen cutouts.
+ int fullscreenInsetThickness = deviceProfile.getInsets().top;
+ int fullscreenMidpointFromBottom = ((deviceProfile.heightPx - fullscreenInsetThickness)
+ / 2);
+ float midpointFromBottomPct = (float) fullscreenMidpointFromBottom / deviceProfile.heightPx;
+ float insetPct = (float) fullscreenInsetThickness / deviceProfile.heightPx;
+ int spaceAboveSnapshots = deviceProfile.overviewTaskThumbnailTopMarginPx;
+ int overviewThumbnailAreaThickness = groupedTaskViewHeight - spaceAboveSnapshots;
+ int bottomToMidpointOffset = (int) (overviewThumbnailAreaThickness * midpointFromBottomPct);
+ int insetOffset = (int) (overviewThumbnailAreaThickness * insetPct);
+
+ primaryIconParams.gravity = BOTTOM | (isRtl ? START : END);
+ secondaryIconParams.gravity = BOTTOM | (isRtl ? START : END);
primaryIconView.setTranslationX(0);
- primaryIconView.setTranslationY(-(taskIconHeight / 2f));
- secondaryIconParams.gravity = CENTER_VERTICAL | (isRtl ? START : END);
secondaryIconView.setTranslationX(0);
- secondaryIconView.setTranslationY(taskIconHeight / 2f);
+ if (splitConfig.initiatedFromSeascape) {
+ // if the split was initiated from seascape,
+ // the task on the right (secondary) is slightly larger
+ primaryIconView.setTranslationY(-bottomToMidpointOffset - insetOffset);
+ secondaryIconView.setTranslationY(-bottomToMidpointOffset - insetOffset
+ + taskIconHeight);
+ } else {
+ // if not,
+ // the task on the left (primary) is slightly larger
+ primaryIconView.setTranslationY(-bottomToMidpointOffset);
+ secondaryIconView.setTranslationY(-bottomToMidpointOffset + taskIconHeight);
+ }
primaryIconView.setLayoutParams(primaryIconParams);
secondaryIconView.setLayoutParams(secondaryIconParams);
diff --git a/src/com/android/launcher3/touch/PagedOrientationHandler.java b/src/com/android/launcher3/touch/PagedOrientationHandler.java
index 6e594e9..850eaaf 100644
--- a/src/com/android/launcher3/touch/PagedOrientationHandler.java
+++ b/src/com/android/launcher3/touch/PagedOrientationHandler.java
@@ -110,10 +110,10 @@
int getDistanceToBottomOfRect(DeviceProfile dp, Rect rect);
List<SplitPositionOption> getSplitPositionOptions(DeviceProfile dp);
/**
- * @param splitholderSize height of placeholder view in portrait, width in landscape
+ * @param placeholderHeight height of placeholder view in portrait, width in landscape
*/
- void getInitialSplitPlaceholderBounds(int splitholderSize, DeviceProfile dp,
- @StagePosition int stagePosition, Rect out);
+ void getInitialSplitPlaceholderBounds(int placeholderHeight, int placeholderInset,
+ DeviceProfile dp, @StagePosition int stagePosition, Rect out);
/**
* @param splitDividerSize height of split screen drag handle in portrait, width in landscape
@@ -146,7 +146,8 @@
int taskIconMargin, int taskIconHeight, int thumbnailTopMargin, boolean isRtl);
void setSplitIconParams(View primaryIconView, View secondaryIconView,
int taskIconHeight, int primarySnapshotWidth, int primarySnapshotHeight,
- boolean isRtl, DeviceProfile deviceProfile, StagedSplitBounds splitConfig);
+ int groupedTaskViewHeight, int groupedTaskViewWidth, boolean isRtl,
+ DeviceProfile deviceProfile, StagedSplitBounds splitConfig);
/*
* The following two methods try to center the TaskMenuView in landscape by finding the center
diff --git a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
index 2c9afd6..d132901 100644
--- a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
+++ b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
@@ -18,6 +18,7 @@
import static android.view.Gravity.BOTTOM;
import static android.view.Gravity.CENTER_HORIZONTAL;
+import static android.view.Gravity.END;
import static android.view.Gravity.START;
import static android.view.Gravity.TOP;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
@@ -334,8 +335,14 @@
// Set translations
if (deviceProfile.isLandscape) {
if (desiredTaskId == splitBounds.rightBottomTaskId) {
- translationX = ((taskViewWidth * splitBounds.leftTaskPercent)
- + (taskViewWidth * splitBounds.dividerWidthPercent));
+ float leftTopTaskPercent = splitBounds.appsStackedVertically
+ ? splitBounds.topTaskPercent
+ : splitBounds.leftTaskPercent;
+ float dividerThicknessPercent = splitBounds.appsStackedVertically
+ ? splitBounds.dividerHeightPercent
+ : splitBounds.dividerWidthPercent;
+ translationX = ((taskViewWidth * leftTopTaskPercent)
+ + (taskViewWidth * dividerThicknessPercent));
}
} else {
if (desiredTaskId == splitBounds.leftTopTaskId) {
@@ -429,29 +436,48 @@
}
@Override
- public void getInitialSplitPlaceholderBounds(int placeholderHeight, DeviceProfile dp,
- @StagePosition int stagePosition, Rect out) {
- int width = dp.widthPx;
- out.set(0, 0, width, placeholderHeight);
+ public void getInitialSplitPlaceholderBounds(int placeholderHeight, int placeholderInset,
+ DeviceProfile dp, @StagePosition int stagePosition, Rect out) {
+ int screenWidth = dp.widthPx;
+ int screenHeight = dp.heightPx;
+ out.set(0, 0, screenWidth, placeholderHeight);
if (!dp.isLandscape) {
// portrait, phone or tablet - spans width of screen, nothing else to do
+ out.inset(placeholderInset, 0);
+
+ // Adjust the top to account for content off screen. This will help to animate the view
+ // in with rounded corners.
+ int totalHeight = (int) (1.0f * screenHeight / 2 * (screenWidth - 2 * placeholderInset)
+ / screenWidth);
+ out.top -= (totalHeight - placeholderHeight);
return;
}
// Now we rotate the portrait rect depending on what side we want pinned
boolean pinToRight = stagePosition == STAGE_POSITION_BOTTOM_OR_RIGHT;
- int screenHeight = dp.heightPx;
- float postRotateScale = (float) screenHeight / width;
+ float postRotateScale = (float) screenHeight / screenWidth;
mTmpMatrix.reset();
mTmpMatrix.postRotate(pinToRight ? 90 : 270);
- mTmpMatrix.postTranslate(pinToRight ? width : 0, pinToRight ? 0 : width);
+ mTmpMatrix.postTranslate(pinToRight ? screenWidth : 0, pinToRight ? 0 : screenWidth);
// The placeholder height stays constant after rotation, so we don't change width scale
mTmpMatrix.postScale(1, postRotateScale);
mTmpRectF.set(out);
mTmpMatrix.mapRect(mTmpRectF);
+ mTmpRectF.inset(0, placeholderInset);
mTmpRectF.roundOut(out);
+
+ // Adjust the top to account for content off screen. This will help to animate the view in
+ // with rounded corners.
+ int totalWidth = (int) (1.0f * screenWidth / 2 * (screenHeight - 2 * placeholderInset)
+ / screenHeight);
+ int width = out.width();
+ if (pinToRight) {
+ out.right += totalWidth - width;
+ } else {
+ out.left -= totalWidth - width;
+ }
}
@Override
@@ -488,19 +514,24 @@
public void setSplitTaskSwipeRect(DeviceProfile dp, Rect outRect,
StagedSplitBounds splitInfo, int desiredStagePosition) {
boolean isLandscape = dp.isLandscape;
+ float topLeftTaskPercent = splitInfo.appsStackedVertically
+ ? splitInfo.topTaskPercent
+ : splitInfo.leftTaskPercent;
+ float dividerBarPercent = splitInfo.appsStackedVertically
+ ? splitInfo.dividerHeightPercent
+ : splitInfo.dividerWidthPercent;
+
if (desiredStagePosition == SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT) {
if (isLandscape) {
- outRect.right = outRect.left + (int) (outRect.width() * splitInfo.leftTaskPercent);
+ outRect.right = outRect.left + (int) (outRect.width() * topLeftTaskPercent);
} else {
- outRect.bottom = outRect.top + (int) (outRect.height() * splitInfo.topTaskPercent);
+ outRect.bottom = outRect.top + (int) (outRect.height() * topLeftTaskPercent);
}
} else {
if (isLandscape) {
- outRect.left += (int) (outRect.width() *
- (splitInfo.leftTaskPercent + splitInfo.dividerWidthPercent));
+ outRect.left += (int) (outRect.width() * (topLeftTaskPercent + dividerBarPercent));
} else {
- outRect.top += (int) (outRect.height() *
- (splitInfo.topTaskPercent + splitInfo.dividerHeightPercent));
+ outRect.top += (int) (outRect.height() * (topLeftTaskPercent + dividerBarPercent));
}
}
}
@@ -559,18 +590,70 @@
@Override
public void setSplitIconParams(View primaryIconView, View secondaryIconView,
int taskIconHeight, int primarySnapshotWidth, int primarySnapshotHeight,
- boolean isRtl, DeviceProfile deviceProfile, StagedSplitBounds splitConfig) {
+ int groupedTaskViewHeight, int groupedTaskViewWidth, boolean isRtl,
+ DeviceProfile deviceProfile, StagedSplitBounds splitConfig) {
FrameLayout.LayoutParams primaryIconParams =
(FrameLayout.LayoutParams) primaryIconView.getLayoutParams();
FrameLayout.LayoutParams secondaryIconParams =
new FrameLayout.LayoutParams(primaryIconParams);
- primaryIconParams.gravity = TOP | CENTER_HORIZONTAL;
- // shifts icon half a width left (height is used conveniently here since icons are square)
- primaryIconView.setTranslationX(-(taskIconHeight / 2f));
+ if (deviceProfile.isLandscape) {
+ // We calculate the "midpoint" of the thumbnail area, and place the icons there.
+ // This is the place where the thumbnail area splits by default, in a near-50/50 split.
+ // It is usually not exactly 50/50, due to insets/screen cutouts.
+ int fullscreenInsetThickness = deviceProfile.isSeascape()
+ ? deviceProfile.getInsets().right
+ : deviceProfile.getInsets().left;
+ int fullscreenMidpointFromBottom = ((deviceProfile.widthPx
+ - fullscreenInsetThickness) / 2);
+ float midpointFromBottomPct = (float) fullscreenMidpointFromBottom
+ / deviceProfile.widthPx;
+ float insetPct = (float) fullscreenInsetThickness / deviceProfile.widthPx;
+ int spaceAboveSnapshots = 0;
+ int overviewThumbnailAreaThickness = groupedTaskViewWidth - spaceAboveSnapshots;
+ int bottomToMidpointOffset = (int) (overviewThumbnailAreaThickness
+ * midpointFromBottomPct);
+ int insetOffset = (int) (overviewThumbnailAreaThickness * insetPct);
+
+ if (deviceProfile.isSeascape()) {
+ primaryIconParams.gravity = TOP | (isRtl ? END : START);
+ secondaryIconParams.gravity = TOP | (isRtl ? END : START);
+ if (splitConfig.initiatedFromSeascape) {
+ // if the split was initiated from seascape,
+ // the task on the right (secondary) is slightly larger
+ primaryIconView.setTranslationX(bottomToMidpointOffset - taskIconHeight);
+ secondaryIconView.setTranslationX(bottomToMidpointOffset);
+ } else {
+ // if not,
+ // the task on the left (primary) is slightly larger
+ primaryIconView.setTranslationX(bottomToMidpointOffset + insetOffset
+ - taskIconHeight);
+ secondaryIconView.setTranslationX(bottomToMidpointOffset + insetOffset);
+ }
+ } else {
+ primaryIconParams.gravity = TOP | (isRtl ? START : END);
+ secondaryIconParams.gravity = TOP | (isRtl ? START : END);
+ if (!splitConfig.initiatedFromSeascape) {
+ // if the split was initiated from landscape,
+ // the task on the left (primary) is slightly larger
+ primaryIconView.setTranslationX(-bottomToMidpointOffset);
+ secondaryIconView.setTranslationX(-bottomToMidpointOffset + taskIconHeight);
+ } else {
+ // if not,
+ // the task on the right (secondary) is slightly larger
+ primaryIconView.setTranslationX(-bottomToMidpointOffset - insetOffset);
+ secondaryIconView.setTranslationX(-bottomToMidpointOffset - insetOffset
+ + taskIconHeight);
+ }
+ }
+ } else {
+ primaryIconParams.gravity = TOP | CENTER_HORIZONTAL;
+ // shifts icon half a width left (height is used here since icons are square)
+ primaryIconView.setTranslationX(-(taskIconHeight / 2f));
+ secondaryIconParams.gravity = TOP | CENTER_HORIZONTAL;
+ secondaryIconView.setTranslationX(taskIconHeight / 2f);
+ }
primaryIconView.setTranslationY(0);
- secondaryIconParams.gravity = TOP | CENTER_HORIZONTAL;
- secondaryIconView.setTranslationX(taskIconHeight / 2f);
secondaryIconView.setTranslationY(0);
primaryIconView.setLayoutParams(primaryIconParams);
diff --git a/src/com/android/launcher3/touch/SeascapePagedViewHandler.java b/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
index 9151796..74b6a5b 100644
--- a/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
+++ b/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
@@ -178,16 +178,46 @@
@Override
public void setSplitIconParams(View primaryIconView, View secondaryIconView,
int taskIconHeight, int primarySnapshotWidth, int primarySnapshotHeight,
- boolean isRtl, DeviceProfile deviceProfile, StagedSplitBounds splitConfig) {
+ int groupedTaskViewHeight, int groupedTaskViewWidth, boolean isRtl,
+ DeviceProfile deviceProfile, StagedSplitBounds splitConfig) {
super.setSplitIconParams(primaryIconView, secondaryIconView, taskIconHeight,
- primarySnapshotWidth, primarySnapshotHeight, isRtl, deviceProfile, splitConfig);
+ primarySnapshotWidth, primarySnapshotHeight, groupedTaskViewHeight,
+ groupedTaskViewWidth, isRtl, deviceProfile, splitConfig);
FrameLayout.LayoutParams primaryIconParams =
(FrameLayout.LayoutParams) primaryIconView.getLayoutParams();
FrameLayout.LayoutParams secondaryIconParams =
(FrameLayout.LayoutParams) secondaryIconView.getLayoutParams();
- primaryIconParams.gravity = CENTER_VERTICAL | (isRtl ? END : START);
- secondaryIconParams.gravity = CENTER_VERTICAL | (isRtl ? END : START);
+ // We calculate the "midpoint" of the thumbnail area, and place the icons there.
+ // This is the place where the thumbnail area splits by default, in a near-50/50 split.
+ // It is usually not exactly 50/50, due to insets/screen cutouts.
+ int fullscreenInsetThickness = deviceProfile.getInsets().top;
+ int fullscreenMidpointFromBottom = ((deviceProfile.heightPx
+ - fullscreenInsetThickness) / 2);
+ float midpointFromBottomPct = (float) fullscreenMidpointFromBottom / deviceProfile.heightPx;
+ float insetPct = (float) fullscreenInsetThickness / deviceProfile.heightPx;
+ int spaceAboveSnapshots = deviceProfile.overviewTaskThumbnailTopMarginPx;
+ int overviewThumbnailAreaThickness = groupedTaskViewHeight - spaceAboveSnapshots;
+ int bottomToMidpointOffset = (int) (overviewThumbnailAreaThickness * midpointFromBottomPct);
+ int insetOffset = (int) (overviewThumbnailAreaThickness * insetPct);
+
+ primaryIconParams.gravity = BOTTOM | (isRtl ? END : START);
+ secondaryIconParams.gravity = BOTTOM | (isRtl ? END : START);
+ primaryIconView.setTranslationX(0);
+ secondaryIconView.setTranslationX(0);
+ if (splitConfig.initiatedFromSeascape) {
+ // if the split was initiated from seascape,
+ // the task on the right (secondary) is slightly larger
+ primaryIconView.setTranslationY(-bottomToMidpointOffset - insetOffset);
+ secondaryIconView.setTranslationY(-bottomToMidpointOffset - insetOffset
+ + taskIconHeight);
+ } else {
+ // if not,
+ // the task on the left (primary) is slightly larger
+ primaryIconView.setTranslationY(-bottomToMidpointOffset);
+ secondaryIconView.setTranslationY(-bottomToMidpointOffset + taskIconHeight);
+ }
+
primaryIconView.setLayoutParams(primaryIconParams);
secondaryIconView.setLayoutParams(secondaryIconParams);
}
diff --git a/src/com/android/launcher3/util/SplitConfigurationOptions.java b/src/com/android/launcher3/util/SplitConfigurationOptions.java
index cb714b2..b40493a 100644
--- a/src/com/android/launcher3/util/SplitConfigurationOptions.java
+++ b/src/com/android/launcher3/util/SplitConfigurationOptions.java
@@ -113,6 +113,14 @@
* the bounds were originally in
*/
public final boolean appsStackedVertically;
+ /**
+ * If {@code true}, that means at the time of creation of this object, the phone was in
+ * seascape orientation. This is important on devices with insets, because they do not split
+ * evenly -- one of the insets must be slightly larger to account for the inset.
+ * From landscape, it is the leftTop task that expands slightly.
+ * From seascape, it is the rightBottom task that expands slightly.
+ */
+ public final boolean initiatedFromSeascape;
public final int leftTopTaskId;
public final int rightBottomTaskId;
@@ -128,11 +136,22 @@
this.visualDividerBounds = new Rect(leftTopBounds.left, leftTopBounds.bottom,
leftTopBounds.right, rightBottomBounds.top);
appsStackedVertically = true;
+ initiatedFromSeascape = false;
} else {
// horizontal apps, vertical divider
this.visualDividerBounds = new Rect(leftTopBounds.right, leftTopBounds.top,
rightBottomBounds.left, leftTopBounds.bottom);
appsStackedVertically = false;
+ // The following check is unreliable on devices without insets
+ // (initiatedFromSeascape will always be set to false.) This happens to be OK for
+ // all our current uses, but should be refactored.
+ // TODO: Create a more reliable check, or refactor how splitting works on devices
+ // with insets.
+ if (rightBottomBounds.width() > leftTopBounds.width()) {
+ initiatedFromSeascape = true;
+ } else {
+ initiatedFromSeascape = false;
+ }
}
leftTaskPercent = this.leftTopBounds.width() / (float) rightBottomBounds.right;
diff --git a/src/com/android/launcher3/views/ActivityContext.java b/src/com/android/launcher3/views/ActivityContext.java
index 3c90eea..93078e4 100644
--- a/src/com/android/launcher3/views/ActivityContext.java
+++ b/src/com/android/launcher3/views/ActivityContext.java
@@ -25,7 +25,8 @@
import androidx.annotation.Nullable;
import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.allapps.BaseAllAppsContainerView;
+import com.android.launcher3.allapps.ActivityAllAppsContainerView;
+import com.android.launcher3.allapps.search.SearchAdapterProvider;
import com.android.launcher3.dot.DotInfo;
import com.android.launcher3.dragndrop.DragController;
import com.android.launcher3.folder.FolderIcon;
@@ -99,7 +100,7 @@
/**
* The all apps container, if it exists in this context.
*/
- default BaseAllAppsContainerView<?> getAppsView() {
+ default ActivityAllAppsContainerView<?> getAppsView() {
return null;
}
@@ -190,4 +191,14 @@
default StringCache getStringCache() {
return null;
}
+
+ /**
+ * Creates and returns {@link SearchAdapterProvider} for build variant specific search result
+ * views.
+ */
+ @Nullable
+ default SearchAdapterProvider<?> createSearchAdapterProvider(
+ ActivityAllAppsContainerView<?> appsView) {
+ return null;
+ }
}
diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java
index 867e488..2a9a8a5 100644
--- a/src/com/android/launcher3/views/OptionsPopupView.java
+++ b/src/com/android/launcher3/views/OptionsPopupView.java
@@ -229,7 +229,7 @@
Launcher launcher = Launcher.getLauncher(view.getContext());
launcher.startActivity(new Intent(Intent.ACTION_APPLICATION_PREFERENCES)
.setPackage(launcher.getPackageName())
- .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK));
return true;
}
diff --git a/tests/src/com/android/launcher3/DeviceProfileTest.kt b/tests/src/com/android/launcher3/DeviceProfileTest.kt
index 75ad21d..d1e91ed 100644
--- a/tests/src/com/android/launcher3/DeviceProfileTest.kt
+++ b/tests/src/com/android/launcher3/DeviceProfileTest.kt
@@ -208,6 +208,12 @@
PointF(64f, 83f),
PointF(64f, 83f)
).toTypedArray()
+ allAppsCellSize = listOf(
+ PointF(64f, 83f),
+ PointF(64f, 83f),
+ PointF(64f, 83f),
+ PointF(64f, 83f)
+ ).toTypedArray()
}
}
}
\ No newline at end of file