Merge "Don't show taskbar when keyguard occluded" into sc-v2-dev
diff --git a/go/quickstep/res/layout/overview_actions_container.xml b/go/quickstep/res/layout/overview_actions_container.xml
index cc65cbf..710e2e0 100644
--- a/go/quickstep/res/layout/overview_actions_container.xml
+++ b/go/quickstep/res/layout/overview_actions_container.xml
@@ -105,6 +105,23 @@
<!-- Unused. Included only for compatibility with parent class. -->
<Button
+ android:id="@+id/action_split"
+ style="@style/GoOverviewActionButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:drawableStart="@drawable/ic_split_screen"
+ android:text="@string/action_split"
+ android:theme="@style/ThemeControlHighlightWorkspaceColor"
+ android:visibility="gone" />
+
+ <Space
+ android:id="@+id/action_split_space"
+ android:layout_width="0dp"
+ android:layout_height="1dp"
+ android:layout_weight="1"
+ android:visibility="gone" />
+
+ <Button
android:id="@+id/action_share"
style="@style/GoOverviewActionButton"
android:layout_width="wrap_content"
diff --git a/quickstep/AndroidManifest.xml b/quickstep/AndroidManifest.xml
index dc92731..bc8bd3a 100644
--- a/quickstep/AndroidManifest.xml
+++ b/quickstep/AndroidManifest.xml
@@ -116,7 +116,6 @@
<activity android:name="com.android.quickstep.interaction.AllSetActivity"
android:autoRemoveFromRecents="true"
android:excludeFromRecents="true"
- android:screenOrientation="portrait"
android:permission="android.permission.REBOOT"
android:theme="@style/AllSetTheme"
android:label="@string/allset_title"
diff --git a/quickstep/res/layout/activity_allset.xml b/quickstep/res/layout/activity_allset.xml
index e79e57e..4fbb8a0 100644
--- a/quickstep/res/layout/activity_allset.xml
+++ b/quickstep/res/layout/activity_allset.xml
@@ -14,7 +14,8 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingStart="@dimen/allset_page_margin_horizontal"
@@ -22,60 +23,72 @@
android:layoutDirection="locale"
android:textDirection="locale">
- <LinearLayout
+ <ImageView
+ android:id="@+id/icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/allset_title_icon_margin_top"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ android:src="@drawable/ic_all_set"/>
+
+ <TextView
+ android:id="@+id/title"
+ style="@style/TextAppearance.GestureTutorial.Feedback.Title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_alignParentTop="true"
- android:layout_gravity="start"
+ android:layout_marginTop="@dimen/allset_title_margin_top"
+ app:layout_constraintTop_toBottomOf="@id/icon"
+ app:layout_constraintStart_toStartOf="parent"
android:gravity="start"
- android:orientation="vertical">
+ android:text="@string/allset_title"/>
- <ImageView
- android:id="@+id/icon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/allset_title_icon_margin_top"
- android:src="@drawable/ic_all_set"/>
+ <TextView
+ android:id="@+id/subtitle"
+ style="@style/TextAppearance.GestureTutorial.Feedback.Subtitle"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/allset_subtitle_margin_top"
+ app:layout_constraintTop_toBottomOf="@id/title"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintWidth_max="@dimen/allset_subtitle_width_max"
+ android:gravity="start"
+ android:text="@string/allset_description"/>
- <TextView
- android:id="@+id/title"
- style="@style/TextAppearance.GestureTutorial.Feedback.Title"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/allset_title_margin_top"
- android:gravity="start"
- android:text="@string/allset_title"/>
-
- <TextView
- android:id="@+id/subtitle"
- style="@style/TextAppearance.GestureTutorial.Feedback.Subtitle"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/allset_subtitle_margin_top"
- android:gravity="start"
- android:text="@string/allset_description"/>
- </LinearLayout>
+ <androidx.constraintlayout.widget.Guideline
+ android:id="@+id/navigation_settings_guideline_bottom"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ app:layout_constraintGuide_percent="0.83" />
<TextView
android:id="@+id/navigation_settings"
style="@style/TextAppearance.GestureTutorial.LinkText"
- android:layout_width="match_parent"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_above="@+id/hint"
- android:gravity="center"
- android:layout_marginBottom="72dp"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintBottom_toBottomOf="@id/navigation_settings_guideline_bottom"
android:minHeight="48dp"
android:background="?android:attr/selectableItemBackground"
android:text="@string/allset_navigation_settings" />
+ <androidx.constraintlayout.widget.Guideline
+ android:id="@+id/hint_guideline_bottom"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ app:layout_constraintGuide_percent="0.94" />
+
<TextView
- android:id="@id/hint"
+ android:id="@+id/hint"
style="@style/TextAppearance.GestureTutorial.Feedback.Subtitle"
android:textSize="14sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginBottom="@dimen/allset_hint_margin_bottom"
- android:layout_alignParentBottom="true"
- android:layout_centerHorizontal="true"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintBottom_toBottomOf="@id/hint_guideline_bottom"
android:text="@string/allset_hint"/>
-</RelativeLayout>
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index c649082..38c202b 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -27,6 +27,7 @@
<dimen name="task_menu_corner_radius">22dp</dimen>
<dimen name="task_menu_item_corner_radius">4dp</dimen>
<dimen name="task_menu_spacing">2dp</dimen>
+ <dimen name="task_menu_width_grid">200dp</dimen>
<dimen name="overview_proactive_row_height">48dp</dimen>
<dimen name="overview_proactive_row_bottom_margin">16dp</dimen>
@@ -125,8 +126,8 @@
<dimen name="allset_page_margin_horizontal">40dp</dimen>
<dimen name="allset_title_margin_top">24dp</dimen>
<dimen name="allset_title_icon_margin_top">32dp</dimen>
- <dimen name="allset_hint_margin_bottom">52dp</dimen>
<dimen name="allset_subtitle_margin_top">24dp</dimen>
+ <dimen name="allset_subtitle_width_max">348dp</dimen>
<!-- All Apps Education tutorial -->
<dimen name="swipe_edu_padding">8dp</dimen>
diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
index c80818a..b8ce818 100644
--- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
@@ -349,7 +349,7 @@
mActionsView = findViewById(R.id.overview_actions_view);
RecentsView overviewPanel = (RecentsView) getOverviewPanel();
SplitSelectStateController controller =
- new SplitSelectStateController(SystemUiProxy.INSTANCE.get(this));
+ new SplitSelectStateController(mHandler, SystemUiProxy.INSTANCE.get(this));
overviewPanel.init(mActionsView, controller);
mActionsView.setDp(getDeviceProfile());
mActionsView.updateVerticalMargin(SysUINavigationMode.getMode(this));
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index b8d00bd..2537134 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -1307,7 +1307,8 @@
}
final RectF startRect = new RectF(0, 0, mDeviceProfile.widthPx, mDeviceProfile.heightPx);
- RectFSpringAnim anim = new RectFSpringAnim(startRect, targetRect, mLauncher);
+ RectFSpringAnim anim = new RectFSpringAnim(startRect, targetRect, mLauncher,
+ mDeviceProfile);
// Hook up floating views to the closing window animators.
if (floatingIconView != null) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 0b6f9c4..0316333 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -20,6 +20,8 @@
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_OPEN;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
import static com.android.systemui.shared.system.WindowManagerWrapper.ITYPE_BOTTOM_TAPPABLE_ELEMENT;
import static com.android.systemui.shared.system.WindowManagerWrapper.ITYPE_EXTRA_NAVIGATION_BAR;
@@ -156,7 +158,8 @@
MATCH_PARENT,
mLastRequestedNonFullscreenHeight,
TYPE_NAVIGATION_BAR_PANEL,
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
+ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_SLIPPERY,
PixelFormat.TRANSLUCENT);
mWindowLayoutParams.setTitle(WINDOW_TITLE);
mWindowLayoutParams.packageName = getPackageName();
@@ -311,6 +314,10 @@
systemUiStateFlags, forceUpdate);
mControllers.taskbarViewController.setImeIsVisible(
mControllers.navbarButtonsViewController.isImeVisible());
+ boolean panelExpanded = (systemUiStateFlags & SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED) != 0;
+ boolean inSettings = (systemUiStateFlags & SYSUI_STATE_QUICK_SETTINGS_EXPANDED) != 0;
+ mControllers.taskbarViewController.setNotificationShadeIsExpanded(
+ panelExpanded || inSettings);
mControllers.taskbarViewController.setRecentsButtonDisabled(
mControllers.navbarButtonsViewController.isRecentsDisabled());
mControllers.taskbarKeyguardController.updateStateForSysuiFlags(systemUiStateFlags);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index a9ff03b..02170ab 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -107,7 +107,7 @@
// Evaluate whether the handle should be stashed
private final StatePropertyHolder mStatePropertyHolder = new StatePropertyHolder(
flags -> {
- if (!supportsStashing()) {
+ if (!supportsVisualStashing()) {
return false;
}
boolean inApp = (flags & FLAG_IN_APP) != 0;
@@ -141,7 +141,7 @@
mTaskbarStashedHandleAlpha = stashedHandleController.getStashedHandleAlpha();
mTaskbarStashedHandleHintScale = stashedHandleController.getStashedHandleHintScale();
- mIsStashedInApp = supportsStashing()
+ mIsStashedInApp = supportsManualStashing()
&& mPrefs.getBoolean(SHARED_PREFS_STASHED_KEY, DEFAULT_STASHED_PREF);
updateStateForFlag(FLAG_STASHED_IN_APP, mIsStashedInApp);
@@ -150,10 +150,18 @@
}
/**
+ * Returns whether the taskbar can visually stash into a handle based on the current device
+ * state.
+ */
+ private boolean supportsVisualStashing() {
+ return !mActivity.isThreeButtonNav();
+ }
+
+ /**
* Returns whether the user can manually stash the taskbar based on the current device state.
*/
- private boolean supportsStashing() {
- return !mActivity.isThreeButtonNav()
+ private boolean supportsManualStashing() {
+ return supportsVisualStashing()
&& (!Utilities.IS_RUNNING_IN_TEST_HARNESS || supportsStashingForTests());
}
@@ -206,7 +214,7 @@
* @return Whether we started an animation to either be newly stashed or unstashed.
*/
public boolean updateAndAnimateIsStashedInApp(boolean isStashedInApp) {
- if (!supportsStashing()) {
+ if (!supportsManualStashing()) {
return false;
}
if (mIsStashedInApp != isStashedInApp) {
@@ -307,7 +315,7 @@
* unstashed state.
*/
public void startStashHint(boolean animateForward) {
- if (isStashed() || !supportsStashing()) {
+ if (isStashed() || !supportsManualStashing()) {
// Already stashed, no need to hint in that direction.
return;
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index f359a3d..4cd6814 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -49,7 +49,8 @@
public static final int ALPHA_INDEX_KEYGUARD = 2;
public static final int ALPHA_INDEX_STASH = 3;
public static final int ALPHA_INDEX_RECENTS_DISABLED = 4;
- private static final int NUM_ALPHA_CHANNELS = 5;
+ public static final int ALPHA_INDEX_NOTIFICATION_EXPANDED = 5;
+ private static final int NUM_ALPHA_CHANNELS = 6;
private final TaskbarActivityContext mActivity;
private final TaskbarView mTaskbarView;
@@ -107,6 +108,16 @@
}
/**
+ * Should be called when the notification shade is expanded, so we can hide taskbar icons as
+ * well. Note that we are animating icons to appear / disappear.
+ */
+ public void setNotificationShadeIsExpanded(boolean isNotificationShadeExpanded) {
+ mTaskbarIconAlpha.getProperty(ALPHA_INDEX_NOTIFICATION_EXPANDED)
+ .animateToValue(isNotificationShadeExpanded ? 0 : 1)
+ .start();
+ }
+
+ /**
* Should be called when the recents button is disabled, so we can hide taskbar icons as well.
*/
public void setRecentsButtonDisabled(boolean isDisabled) {
diff --git a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
index dc22a61..0181cd7 100644
--- a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
+++ b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
@@ -137,6 +137,12 @@
// opaque until it is ready.
private boolean mIsFloatingIconReady = false;
+ @Nullable
+ @Override
+ protected View getViewIgnoredInWorkspaceRevealAnimation() {
+ return workspaceView;
+ }
+
@Override
public RectF getWindowTargetRect() {
super.getWindowTargetRect();
diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
index cc6cfd7..03e2395 100644
--- a/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -122,7 +122,7 @@
SYSUI_PROGRESS.set(getRootView().getSysUiScrim(), 0f);
SplitSelectStateController controller =
- new SplitSelectStateController(SystemUiProxy.INSTANCE.get(this));
+ new SplitSelectStateController(mHandler, SystemUiProxy.INSTANCE.get(this));
mDragLayer.recreateControllers();
mFallbackRecentsView.init(mActionsView, controller);
}
diff --git a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
index d188018..2fee945 100644
--- a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
+++ b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
@@ -295,7 +295,7 @@
taskViewSimulator.getCurrentCornerRadius(),
homeAnimationFactory.getEndRadius(cropRectF));
} else {
- anim = new RectFSpringAnim(startRect, targetRect, mContext);
+ anim = new RectFSpringAnim(startRect, targetRect, mContext, mDp);
}
homeAnimationFactory.setAnimation(anim);
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index 23dc913..37d88ae 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -35,6 +35,7 @@
import static com.android.launcher3.anim.Interpolators.clampToProgress;
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
import static com.android.launcher3.statehandlers.DepthController.DEPTH;
+import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING;
@@ -42,6 +43,7 @@
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
import android.annotation.TargetApi;
import android.content.ComponentName;
import android.content.Context;
@@ -79,6 +81,8 @@
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
+import java.util.ArrayList;
+
/**
* Utility class for helpful methods related to {@link TaskView} objects and their tasks.
*/
@@ -427,34 +431,64 @@
@NonNull RemoteAnimationTargetCompat[] wallpaperTargets,
@NonNull RemoteAnimationTargetCompat[] nonAppTargets,
@NonNull Runnable finishCallback) {
+ final ArrayList<SurfaceControl> openingTargets = new ArrayList<>();
+ final ArrayList<SurfaceControl> closingTargets = new ArrayList<>();
- final int[] splitRoots = new int[2];
- for (int i = 0; i < appTargets.length; ++i) {
- final int taskId = appTargets[i].taskInfo != null ? appTargets[i].taskInfo.taskId : -1;
- final int mode = appTargets[i].mode;
- if (taskId == initialTask.key.id || taskId == secondTask.key.id) {
- if (mode != MODE_OPENING) {
- throw new IllegalStateException(
- "Expected task to be opening, but it is " + mode);
- }
- splitRoots[taskId == initialTask.key.id ? 0 : 1] = i;
+ for (RemoteAnimationTargetCompat appTarget : appTargets) {
+ final int taskId = appTarget.taskInfo != null ? appTarget.taskInfo.taskId : -1;
+ final int mode = appTarget.mode;
+ final SurfaceControl leash = appTarget.leash.getSurfaceControl();
+ if (leash == null) {
+ continue;
+ }
+
+ if (mode == MODE_OPENING) {
+ openingTargets.add(leash);
+ } else if (taskId == initialTask.key.id || taskId == secondTask.key.id) {
+ throw new IllegalStateException("Expected task to be opening, but it is " + mode);
+ } else if (mode == MODE_CLOSING) {
+ closingTargets.add(leash);
}
}
- SurfaceControl.Transaction t = new SurfaceControl.Transaction();
-
- // This is where we should animate the split roots. For now, though, just make them visible.
- for (int i = 0; i < 2; ++i) {
- t.show(appTargets[splitRoots[i]].leash.getSurfaceControl());
- t.setAlpha(appTargets[splitRoots[i]].leash.getSurfaceControl(), 1.f);
+ for (int i = 0; i < nonAppTargets.length; ++i) {
+ final SurfaceControl leash = appTargets[i].leash.getSurfaceControl();
+ if (nonAppTargets[i].windowType == TYPE_DOCK_DIVIDER && leash != null) {
+ openingTargets.add(leash);
+ }
}
- // This contains the initial state (before animation), so apply this at the beginning of
- // the animation.
- t.apply();
+ final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f);
+ animator.addUpdateListener(valueAnimator -> {
+ float progress = valueAnimator.getAnimatedFraction();
+ for (SurfaceControl leash: openingTargets) {
+ t.setAlpha(leash, progress);
+ }
+ for (SurfaceControl leash: closingTargets) {
+ t.setAlpha(leash, 1 - progress);
+ }
+ t.apply();
+ });
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ for (SurfaceControl leash: openingTargets) {
+ t.show(leash).setAlpha(leash, 0.0f);
+ }
+ t.apply();
+ }
- // Once there is an animation, this should be called AFTER the animation completes.
- finishCallback.run();
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ for (SurfaceControl leash: closingTargets) {
+ t.hide(leash);
+ }
+ super.onAnimationEnd(animation);
+ finishCallback.run();
+ }
+ });
+ animator.start();
}
public static void composeRecentsLaunchAnimator(@NonNull AnimatorSet anim, @NonNull View v,
diff --git a/quickstep/src/com/android/quickstep/util/RectFSpringAnim.java b/quickstep/src/com/android/quickstep/util/RectFSpringAnim.java
index 02ec68a..158fba9 100644
--- a/quickstep/src/com/android/quickstep/util/RectFSpringAnim.java
+++ b/quickstep/src/com/android/quickstep/util/RectFSpringAnim.java
@@ -15,24 +15,31 @@
*/
package com.android.quickstep.util;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
import android.animation.Animator;
import android.content.Context;
import android.graphics.PointF;
+import android.graphics.Rect;
import android.graphics.RectF;
+import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
import androidx.dynamicanimation.animation.DynamicAnimation.OnAnimationEndListener;
import androidx.dynamicanimation.animation.FloatPropertyCompat;
import androidx.dynamicanimation.animation.SpringAnimation;
import androidx.dynamicanimation.animation.SpringForce;
+import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.FlingSpringAnim;
+import com.android.launcher3.touch.OverScroll;
import com.android.launcher3.util.DynamicResource;
import com.android.quickstep.RemoteAnimationTargets.ReleaseCheck;
import com.android.systemui.plugins.ResourceProvider;
+import java.lang.annotation.Retention;
import java.util.ArrayList;
import java.util.List;
@@ -94,7 +101,6 @@
private float mCurrentCenterX;
private float mCurrentY;
// If true, tracking the bottom of the rects, else tracking the top.
- private boolean mTrackingBottomY;
private float mCurrentScaleProgress;
private FlingSpringAnim mRectXAnim;
private FlingSpringAnim mRectYAnim;
@@ -105,20 +111,68 @@
private boolean mRectScaleAnimEnded;
private float mMinVisChange;
- private float mYOvershoot;
+ private int mMaxVelocityPxPerS;
- public RectFSpringAnim(RectF startRect, RectF targetRect, Context context) {
+ /**
+ * Indicates which part of the start & target rects we are interpolating between.
+ */
+ public static final int TRACKING_TOP = 0;
+ public static final int TRACKING_CENTER = 1;
+ public static final int TRACKING_BOTTOM = 2;
+
+ @Retention(SOURCE)
+ @IntDef(value = {TRACKING_TOP,
+ TRACKING_CENTER,
+ TRACKING_BOTTOM})
+ public @interface Tracking{}
+
+ @Tracking
+ public final int mTracking;
+
+ public RectFSpringAnim(RectF startRect, RectF targetRect, Context context,
+ @Nullable DeviceProfile deviceProfile) {
mStartRect = startRect;
mTargetRect = targetRect;
mCurrentCenterX = mStartRect.centerX();
- mTrackingBottomY = startRect.bottom < targetRect.bottom;
- mCurrentY = mTrackingBottomY ? mStartRect.bottom : mStartRect.top;
-
ResourceProvider rp = DynamicResource.provider(context);
mMinVisChange = rp.getDimension(R.dimen.swipe_up_fling_min_visible_change);
- mYOvershoot = rp.getDimension(R.dimen.swipe_up_y_overshoot);
+ mMaxVelocityPxPerS = (int) rp.getDimension(R.dimen.swipe_up_max_velocity);
setCanRelease(true);
+
+ if (deviceProfile == null) {
+ mTracking = startRect.bottom < targetRect.bottom
+ ? TRACKING_BOTTOM
+ : TRACKING_TOP;
+ } else {
+ int heightPx = deviceProfile.heightPx;
+ Rect padding = deviceProfile.workspacePadding;
+
+ final float topThreshold = heightPx / 3f;
+ final float bottomThreshold = deviceProfile.heightPx - padding.bottom;
+
+ if (targetRect.bottom > bottomThreshold) {
+ mTracking = TRACKING_BOTTOM;
+ } else if (targetRect.top < topThreshold) {
+ mTracking = TRACKING_TOP;
+ } else {
+ mTracking = TRACKING_CENTER;
+ }
+ }
+
+ mCurrentY = getTrackedYFromRect(mStartRect);
+ }
+
+ private float getTrackedYFromRect(RectF rect) {
+ switch (mTracking) {
+ case TRACKING_TOP:
+ return rect.top;
+ case TRACKING_BOTTOM:
+ return rect.bottom;
+ case TRACKING_CENTER:
+ default:
+ return rect.centerY();
+ }
}
public void onTargetPositionChanged() {
@@ -127,10 +181,22 @@
}
if (mRectYAnim != null) {
- if (mTrackingBottomY && mRectYAnim.getTargetPosition() != mTargetRect.bottom) {
- mRectYAnim.updatePosition(mCurrentY, mTargetRect.bottom);
- } else if (!mTrackingBottomY && mRectYAnim.getTargetPosition() != mTargetRect.top) {
- mRectYAnim.updatePosition(mCurrentY, mTargetRect.top);
+ switch (mTracking) {
+ case TRACKING_TOP:
+ if (mRectYAnim.getTargetPosition() != mTargetRect.top) {
+ mRectYAnim.updatePosition(mCurrentY, mTargetRect.top);
+ }
+ break;
+ case TRACKING_BOTTOM:
+ if (mRectYAnim.getTargetPosition() != mTargetRect.bottom) {
+ mRectYAnim.updatePosition(mCurrentY, mTargetRect.bottom);
+ }
+ break;
+ case TRACKING_CENTER:
+ if (mRectYAnim.getTargetPosition() != mTargetRect.centerY()) {
+ mRectYAnim.updatePosition(mCurrentY, mTargetRect.centerY());
+ }
+ break;
}
}
}
@@ -159,22 +225,29 @@
maybeOnEnd();
});
+ // We dampen the user velocity here to keep the natural feeling and to prevent the
+ // rect from straying too from a linear path.
+ final float xVelocityPxPerS = velocityPxPerMs.x * 1000;
+ final float yVelocityPxPerS = velocityPxPerMs.y * 1000;
+ final float dampedXVelocityPxPerS = OverScroll.dampedScroll(
+ Math.abs(xVelocityPxPerS), mMaxVelocityPxPerS) * Math.signum(xVelocityPxPerS);
+ final float dampedYVelocityPxPerS = OverScroll.dampedScroll(
+ Math.abs(yVelocityPxPerS), mMaxVelocityPxPerS) * Math.signum(yVelocityPxPerS);
+
float startX = mCurrentCenterX;
float endX = mTargetRect.centerX();
float minXValue = Math.min(startX, endX);
float maxXValue = Math.max(startX, endX);
- mRectXAnim = new FlingSpringAnim(this, context, RECT_CENTER_X, startX, endX,
- velocityPxPerMs.x * 1000, mMinVisChange, minXValue, maxXValue, 1f, onXEndListener);
- float startVelocityY = velocityPxPerMs.y * 1000;
- // Scale the Y velocity based on the initial velocity to tune the curves.
- float springVelocityFactor = 0.1f + 0.9f * Math.abs(startVelocityY) / 20000.0f;
+ mRectXAnim = new FlingSpringAnim(this, context, RECT_CENTER_X, startX, endX,
+ dampedXVelocityPxPerS, mMinVisChange, minXValue, maxXValue, onXEndListener);
+
float startY = mCurrentY;
- float endY = mTrackingBottomY ? mTargetRect.bottom : mTargetRect.top;
- float minYValue = Math.min(startY, endY - mYOvershoot);
+ float endY = getTrackedYFromRect(mTargetRect);
+ float minYValue = Math.min(startY, endY);
float maxYValue = Math.max(startY, endY);
- mRectYAnim = new FlingSpringAnim(this, context, RECT_Y, startY, endY, startVelocityY,
- mMinVisChange, minYValue, maxYValue, springVelocityFactor, onYEndListener);
+ mRectYAnim = new FlingSpringAnim(this, context, RECT_Y, startY, endY, dampedYVelocityPxPerS,
+ mMinVisChange, minYValue, maxYValue, onYEndListener);
float minVisibleChange = Math.abs(1f / mStartRect.height());
ResourceProvider rp = DynamicResource.provider(context);
@@ -234,12 +307,25 @@
mTargetRect.width());
float currentHeight = Utilities.mapRange(mCurrentScaleProgress, mStartRect.height(),
mTargetRect.height());
- if (mTrackingBottomY) {
- mCurrentRect.set(mCurrentCenterX - currentWidth / 2, mCurrentY - currentHeight,
- mCurrentCenterX + currentWidth / 2, mCurrentY);
- } else {
- mCurrentRect.set(mCurrentCenterX - currentWidth / 2, mCurrentY,
- mCurrentCenterX + currentWidth / 2, mCurrentY + currentHeight);
+ switch (mTracking) {
+ case TRACKING_TOP:
+ mCurrentRect.set(mCurrentCenterX - currentWidth / 2,
+ mCurrentY,
+ mCurrentCenterX + currentWidth / 2,
+ mCurrentY + currentHeight);
+ break;
+ case TRACKING_BOTTOM:
+ mCurrentRect.set(mCurrentCenterX - currentWidth / 2,
+ mCurrentY - currentHeight,
+ mCurrentCenterX + currentWidth / 2,
+ mCurrentY);
+ break;
+ case TRACKING_CENTER:
+ mCurrentRect.set(mCurrentCenterX - currentWidth / 2,
+ mCurrentY - currentHeight / 2,
+ mCurrentCenterX + currentWidth / 2,
+ mCurrentY + currentHeight / 2);
+ break;
}
for (OnUpdateListener onUpdateListener : mOnUpdateListeners) {
onUpdateListener.onUpdate(null, mCurrentRect, mCurrentScaleProgress);
diff --git a/quickstep/src/com/android/quickstep/util/RectFSpringAnim2.java b/quickstep/src/com/android/quickstep/util/RectFSpringAnim2.java
index c331a13..cb35809 100644
--- a/quickstep/src/com/android/quickstep/util/RectFSpringAnim2.java
+++ b/quickstep/src/com/android/quickstep/util/RectFSpringAnim2.java
@@ -132,7 +132,7 @@
public RectFSpringAnim2(RectF startRect, RectF targetRect, Context context, float startRadius,
float endRadius) {
- super(startRect, targetRect, context);
+ super(startRect, targetRect, context, null);
mStartRect = startRect;
mTargetRect = targetRect;
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index 3069504..e9a695d 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -16,17 +16,20 @@
package com.android.quickstep.util;
+import static com.android.launcher3.Utilities.postAsyncCallback;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
import android.app.ActivityThread;
import android.graphics.Rect;
+import android.os.Handler;
import android.os.IBinder;
import android.view.RemoteAnimationAdapter;
import android.view.SurfaceControl;
import android.window.TransitionInfo;
+import com.android.launcher3.Utilities;
import com.android.launcher3.util.SplitConfigurationOptions;
import com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
import com.android.quickstep.SystemUiProxy;
@@ -47,13 +50,15 @@
*/
public class SplitSelectStateController {
+ private final Handler mHandler;
private final SystemUiProxy mSystemUiProxy;
private @StagePosition int mStagePosition;
private Task mInitialTask;
private Task mSecondTask;
private Rect mInitialBounds;
- public SplitSelectStateController(SystemUiProxy systemUiProxy) {
+ public SplitSelectStateController(Handler handler, SystemUiProxy systemUiProxy) {
+ mHandler = handler;
mSystemUiProxy = systemUiProxy;
}
@@ -70,9 +75,9 @@
/**
* To be called after second task selected
*/
- public void setSecondTaskId(Task taskView) {
+ public void setSecondTaskId(Task taskView, Consumer<Boolean> callback) {
mSecondTask = taskView;
- launchTasks(mInitialTask, mSecondTask, mStagePosition, null /*callback*/);
+ launchTasks(mInitialTask, mSecondTask, mStagePosition, callback);
}
/**
@@ -151,22 +156,27 @@
public void onAnimationStart(int transit, RemoteAnimationTargetCompat[] apps,
RemoteAnimationTargetCompat[] wallpapers, RemoteAnimationTargetCompat[] nonApps,
Runnable finishedCallback) {
- TaskViewUtils.composeRecentsSplitLaunchAnimatorLegacy(mInitialTask,
- mSecondTask, apps, wallpapers, nonApps, () -> {
- finishedCallback.run();
- if (mSuccessCallback != null) {
- mSuccessCallback.accept(true);
- }
- });
+ postAsyncCallback(mHandler,
+ () -> TaskViewUtils.composeRecentsSplitLaunchAnimatorLegacy(mInitialTask,
+ mSecondTask, apps, wallpapers, nonApps, () -> {
+ finishedCallback.run();
+ if (mSuccessCallback != null) {
+ mSuccessCallback.accept(true);
+ }
+ }));
+
// After successful launch, call resetState
resetState();
}
@Override
public void onAnimationCancelled() {
- if (mSuccessCallback != null) {
- mSuccessCallback.accept(false);
- }
+ postAsyncCallback(mHandler, () -> {
+ if (mSuccessCallback != null) {
+ mSuccessCallback.accept(false);
+ }
+ });
+
resetState();
}
}
diff --git a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
index d4191fe..a30216c 100644
--- a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
+++ b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
@@ -116,7 +116,7 @@
@NonNull Rect destinationBoundsTransformed,
int cornerRadius,
@NonNull View view) {
- super(startBounds, new RectF(destinationBoundsTransformed), context);
+ super(startBounds, new RectF(destinationBoundsTransformed), context, null);
mTaskId = taskId;
mComponentName = componentName;
mLeash = leash;
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index cb8e7f7..5794396 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -3836,10 +3836,9 @@
mSecondFloatingTaskView.addAnimation(pendingAnimation, secondTaskStartingBounds,
secondTaskEndingBounds, taskView.getThumbnail(),
true /*fadeWithThumbnail*/);
- pendingAnimation.addEndListener(aBoolean -> {
- mSplitSelectStateController.setSecondTaskId(taskView.getTask());
- resetFromSplitSelectionState();
- });
+ pendingAnimation.addEndListener(aBoolean ->
+ mSplitSelectStateController.setSecondTaskId(taskView.getTask(),
+ aBoolean1 -> RecentsView.this.resetFromSplitSelectionState()));
mSecondSplitHiddenTaskView = taskView;
taskView.setVisibility(INVISIBLE);
pendingAnimation.buildAnim().start();
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuView.java b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
index 5ddbf87..2cf447f 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
@@ -151,7 +151,7 @@
}
setRotation(pagedOrientationHandler.getDegreesRotated());
setX(pagedOrientationHandler.getTaskMenuX(adjustedX,
- mTaskContainer.getThumbnailView(), overscrollShift));
+ mTaskContainer.getThumbnailView(), overscrollShift, deviceProfile));
setY(pagedOrientationHandler.getTaskMenuY(
adjustedY, mTaskContainer.getThumbnailView(), overscrollShift));
@@ -229,7 +229,6 @@
private void addMenuOptions(TaskIdAttributeContainer taskContainer) {
mTaskName.setText(TaskUtils.getTitle(getContext(), taskContainer.getTask()));
mTaskName.setOnClickListener(v -> close(true));
-
TaskOverlayFactory.getEnabledShortcuts(mTaskView, mActivity.getDeviceProfile(),
taskContainer)
.forEach(this::addMenuOption);
@@ -256,13 +255,21 @@
orientationHandler.setTaskMenuAroundTaskView(this, mTaskInsetMargin);
// Get Position
+ DeviceProfile deviceProfile = mActivity.getDeviceProfile();
mActivity.getDragLayer().getDescendantRectRelativeToSelf(mTaskView, sTempRect);
Rect insets = mActivity.getDragLayer().getInsets();
BaseDragLayer.LayoutParams params = (BaseDragLayer.LayoutParams) getLayoutParams();
int padding = getResources()
.getDimensionPixelSize(R.dimen.task_menu_vertical_padding);
- params.width = orientationHandler
- .getTaskMenuWidth(taskContainer.getThumbnailView()) - (2 * padding);
+ if (deviceProfile.overviewShowAsGrid) {
+ // TODO(b/193432925) temporary so it doesn't look terrible on large screen
+ params.width =
+ getContext().getResources().getDimensionPixelSize(R.dimen.task_menu_width_grid);
+ } else {
+ params.width = orientationHandler
+ .getTaskMenuWidth(taskContainer.getThumbnailView(),
+ deviceProfile) - (2 * padding);
+ }
// Gravity set to Left instead of Start as sTempRect.left measures Left distance not Start
params.gravity = Gravity.LEFT;
setLayoutParams(params);
@@ -276,7 +283,7 @@
mOptionLayout.setShowDividers(SHOW_DIVIDER_MIDDLE);
orientationHandler.setTaskOptionsMenuLayoutOrientation(
- mActivity.getDeviceProfile(), mOptionLayout, dividerSpacing, divider);
+ deviceProfile, mOptionLayout, dividerSpacing, divider);
setPosition(sTempRect.left - insets.left, sTempRect.top - insets.top, 0);
}
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index 053d07c..b3e0dce 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -847,6 +847,9 @@
if (icon != null) {
iconView.setDrawable(icon);
iconView.setOnClickListener(v -> {
+ if (confirmSecondSplitSelectApp()) {
+ return;
+ }
if (ENABLE_QUICKSTEP_LIVE_TILE.get() && isRunningTask()) {
RecentsView recentsView = getRecentsView();
recentsView.switchToScreenshot(
diff --git a/res/color-v31/overview_scrim_dark.xml b/res/color-v31/overview_scrim_dark.xml
index 85ede9a..2ab8ecd 100644
--- a/res/color-v31/overview_scrim_dark.xml
+++ b/res/color-v31/overview_scrim_dark.xml
@@ -14,5 +14,5 @@
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:color="@android:color/system_neutral2_500" android:lStar="35" />
+ <item android:color="@android:color/system_neutral1_500" android:lStar="35" />
</selector>
diff --git a/res/layout/widgets_full_sheet.xml b/res/layout/widgets_full_sheet.xml
index 8afd40b..0fc0ff8 100644
--- a/res/layout/widgets_full_sheet.xml
+++ b/res/layout/widgets_full_sheet.xml
@@ -67,7 +67,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/collapse_handle"
- android:layout_marginHorizontal="@dimen/widget_list_horizontal_margin"
+ android:paddingHorizontal="@dimen/widget_list_horizontal_margin"
android:visibility="gone"
android:clipToPadding="false" />
diff --git a/res/layout/widgets_full_sheet_paged_view.xml b/res/layout/widgets_full_sheet_paged_view.xml
index 85f14cd..dfe226a 100644
--- a/res/layout/widgets_full_sheet_paged_view.xml
+++ b/res/layout/widgets_full_sheet_paged_view.xml
@@ -20,7 +20,6 @@
android:id="@+id/widgets_view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_marginHorizontal="@dimen/widget_list_horizontal_margin"
android:clipToPadding="false"
android:layout_below="@id/collapse_handle"
android:descendantFocusability="afterDescendants"
@@ -30,12 +29,14 @@
android:id="@+id/primary_widgets_list_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:paddingHorizontal="@dimen/widget_list_horizontal_margin"
android:clipToPadding="false" />
<com.android.launcher3.widget.picker.WidgetsRecyclerView
android:id="@+id/work_widgets_list_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:paddingHorizontal="@dimen/widget_list_horizontal_margin"
android:clipToPadding="false" />
</com.android.launcher3.workprofile.PersonalWorkPagedView>
diff --git a/res/layout/widgets_full_sheet_recyclerview.xml b/res/layout/widgets_full_sheet_recyclerview.xml
index dde82ea..6a5d6cb 100644
--- a/res/layout/widgets_full_sheet_recyclerview.xml
+++ b/res/layout/widgets_full_sheet_recyclerview.xml
@@ -19,7 +19,7 @@
android:layout_below="@id/collapse_handle"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_marginHorizontal="@dimen/widget_list_horizontal_margin"
+ android:paddingHorizontal="@dimen/widget_list_horizontal_margin"
android:clipToPadding="false" />
<!-- SearchAndRecommendationsView without the tab layout as well -->
diff --git a/res/values/config.xml b/res/values/config.xml
index 7c681a8..6fdb4de 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -184,8 +184,8 @@
<!-- Swipe up to home related -->
<dimen name="swipe_up_fling_min_visible_change">18dp</dimen>
- <dimen name="swipe_up_y_overshoot">10dp</dimen>
<dimen name="swipe_up_max_workspace_trans_y">-60dp</dimen>
+ <dimen name="swipe_up_max_velocity">7.619dp</dimen>
<array name="dynamic_resources">
<item>@dimen/swipe_up_duration</item>
@@ -201,6 +201,7 @@
<item>@dimen/swipe_up_launcher_alpha_max_progress</item>
<item>@dimen/swipe_up_rect_2_y_stiffness_low_swipe_multiplier</item>
<item>@dimen/swipe_up_low_swipe_duration_multiplier</item>
+ <item>@dimen/swipe_up_max_velocity</item>
<item>@dimen/c1_a</item>
<item>@dimen/c1_b</item>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index bc232a6..1cf49fc 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -128,7 +128,6 @@
<dimen name="work_card_button_height">52dp</dimen>
<dimen name="work_fab_margin">16dp</dimen>
<dimen name="work_profile_footer_padding">20dp</dimen>
- <dimen name="work_profile_footer_text_size">16sp</dimen>
<dimen name="work_edu_card_margin">16dp</dimen>
<dimen name="work_edu_card_radius">28dp</dimen>
@@ -324,7 +323,7 @@
<!-- Size of the maximum radius for the enforced rounded rectangles. -->
<dimen name="enforced_rounded_corner_max_radius">16dp</dimen>
-<!-- Overview placeholder to compile in Launcer3 without Quickstep -->
+<!-- Overview placeholder to compile in Launcher3 without Quickstep -->
<dimen name="task_thumbnail_icon_size">0dp</dimen>
<dimen name="task_thumbnail_icon_drawable_size">0dp</dimen>
<dimen name="task_thumbnail_icon_drawable_size_grid">0dp</dimen>
@@ -342,6 +341,8 @@
<dimen name="recents_page_spacing">0dp</dimen>
<dimen name="recents_page_spacing_grid">0dp</dimen>
<dimen name="split_placeholder_size">110dp</dimen>
+ <dimen name="task_menu_width_grid">200dp</dimen>
+
<!-- Workspace grid visualization parameters -->
<dimen name="grid_visualization_rounding_radius">22dp</dimen>
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 3121bfc..ce8cf3c 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -33,7 +33,6 @@
import android.graphics.PointF;
import android.graphics.Rect;
import android.util.DisplayMetrics;
-import android.util.Pair;
import android.view.Surface;
import com.android.launcher3.CellLayout.ContainerType;
@@ -215,8 +214,6 @@
// Whether Taskbar will inset the bottom of apps by taskbarSize.
public boolean isTaskbarPresentInApps;
public int taskbarSize;
- // How much of the bottom inset is due to Taskbar rather than other system elements.
- public int nonOverlappingTaskbarInset;
// DragController
public int flingToDeleteThresholdVelocity;
@@ -239,7 +236,7 @@
widthPx = windowBounds.bounds.width();
heightPx = windowBounds.bounds.height();
availableWidthPx = windowBounds.availableSize.x;
- int nonFinalAvailableHeightPx = windowBounds.availableSize.y;
+ availableHeightPx = windowBounds.availableSize.y;
mInfo = info;
// If the device's pixel density was scaled (usually via settings for A11y), use the
@@ -266,15 +263,8 @@
isTaskbarPresent = isTablet && ApiWrapper.TASKBAR_DRAWN_IN_PROCESS
&& FeatureFlags.ENABLE_TASKBAR.get();
if (isTaskbarPresent) {
- // Taskbar will be added later, but provides bottom insets that we should subtract
- // from availableHeightPx.
taskbarSize = res.getDimensionPixelSize(R.dimen.taskbar_size);
- nonOverlappingTaskbarInset = taskbarSize - windowBounds.insets.bottom;
- if (nonOverlappingTaskbarInset > 0) {
- nonFinalAvailableHeightPx -= nonOverlappingTaskbarInset;
- }
}
- availableHeightPx = nonFinalAvailableHeightPx;
edgeMarginPx = res.getDimensionPixelSize(R.dimen.dynamic_grid_edge_margin);
@@ -842,7 +832,7 @@
padding.right = hotseatBarSizePx;
}
} else {
- int hotseatTop = isTaskbarPresent ? taskbarSize : hotseatBarSizePx;
+ int hotseatTop = hotseatBarSizePx;
int paddingBottom = hotseatTop + workspacePageIndicatorHeight
+ workspaceBottomPadding - mWorkspacePageIndicatorOverlapWorkspace;
if (isTablet) {
@@ -853,8 +843,7 @@
((inv.numColumns - 1) * cellWidthPx)));
availablePaddingX = (int) Math.min(availablePaddingX,
widthPx * MAX_HORIZONTAL_PADDING_PERCENT);
- int hotseatVerticalPadding = isTaskbarPresent ? 0
- : hotseatBarTopPaddingPx + hotseatBarBottomPaddingPx;
+ int hotseatVerticalPadding = hotseatBarTopPaddingPx + hotseatBarBottomPaddingPx;
int availablePaddingY = Math.max(0, heightPx - edgeMarginPx - paddingBottom
- (2 * inv.numRows * cellHeightPx) - hotseatVerticalPadding);
padding.set(availablePaddingX / 2, edgeMarginPx + availablePaddingY / 2,
@@ -886,9 +875,9 @@
mInsets.right + hotseatBarSidePaddingStartPx, mInsets.bottom);
}
} else if (isTaskbarPresent) {
- int hotseatHeight = workspacePadding.bottom + taskbarSize;
+ int hotseatHeight = workspacePadding.bottom;
int taskbarOffset = getTaskbarOffsetY();
- int hotseatTopDiff = hotseatHeight - taskbarSize - taskbarOffset;
+ int hotseatTopDiff = hotseatHeight - taskbarOffset;
int endOffset = ApiWrapper.getHotseatEndOffset(context);
int requiredWidth = iconSizePx * numShownHotseatIcons;
@@ -938,7 +927,8 @@
: hotseatBarSizePx - hotseatCellHeightPx - hotseatQsbHeight;
if (isScalableGrid && qsbBottomMarginPx > mInsets.bottom) {
- return Math.min(qsbBottomMarginPx, freeSpace);
+ // Note that taskbarSize = 0 unless isTaskbarPresent.
+ return Math.min(qsbBottomMarginPx + taskbarSize, freeSpace);
} else {
return (int) (freeSpace * QSB_CENTER_FACTOR)
+ (isTaskbarPresent ? taskbarSize : mInsets.bottom);
@@ -1116,10 +1106,7 @@
writer.println(prefix + "\tisTaskbarPresent:" + isTaskbarPresent);
writer.println(prefix + "\tisTaskbarPresentInApps:" + isTaskbarPresentInApps);
-
writer.println(prefix + pxToDpStr("taskbarSize", taskbarSize));
- writer.println(prefix + pxToDpStr("nonOverlappingTaskbarInset",
- nonOverlappingTaskbarInset));
writer.println(prefix + pxToDpStr("workspacePadding.left", workspacePadding.left));
writer.println(prefix + pxToDpStr("workspacePadding.top", workspacePadding.top));
diff --git a/src/com/android/launcher3/LauncherRootView.java b/src/com/android/launcher3/LauncherRootView.java
index 28afc57..7de2ee4 100644
--- a/src/com/android/launcher3/LauncherRootView.java
+++ b/src/com/android/launcher3/LauncherRootView.java
@@ -47,15 +47,8 @@
}
private void handleSystemWindowInsets(Rect insets) {
- DeviceProfile dp = mActivity.getDeviceProfile();
-
- // Taskbar provides insets, but we don't want that for most Launcher elements so remove it.
- mTempRect.set(insets);
- insets = mTempRect;
- insets.bottom = Math.max(0, insets.bottom - dp.nonOverlappingTaskbarInset);
-
// Update device profile before notifying the children.
- dp.updateInsets(insets);
+ mActivity.getDeviceProfile().updateInsets(insets);
boolean resetState = !insets.equals(mInsets);
setInsets(insets);
@@ -86,10 +79,6 @@
* get its insets, we calculate them ourselves so they are stable regardless of whether taskbar
* is currently attached.
*
- * TODO(b/198798034): Currently we always calculate nav insets as taskbarSize, but then we
- * subtract nonOverlappingTaskbarInset in handleSystemWindowInsets(). Instead, we should just
- * calculate the normal nav bar height here, and remove nonOverlappingTaskbarInset altogether.
- *
* @param oldInsets The system-provided insets, which we are modifying.
* @return The updated insets.
*/
@@ -108,10 +97,8 @@
Insets oldNavInsets = oldInsets.getInsets(WindowInsets.Type.navigationBars());
Rect newNavInsets = new Rect(oldNavInsets.left, oldNavInsets.top, oldNavInsets.right,
oldNavInsets.bottom);
- if (dp.isTaskbarPresent) {
- // TODO (see javadoc): Remove this block and fall into the next one instead.
- newNavInsets.bottom = dp.taskbarSize;
- } else if (dp.isLandscape) {
+
+ if (dp.isLandscape) {
if (dp.isTablet) {
newNavInsets.bottom = ResourceUtils.getNavbarSize(
"navigation_bar_height_landscape", resources);
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 3faa3d0..c5e9dd2 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -314,8 +314,6 @@
Rect padding = grid.workspacePadding;
setPadding(padding.left, padding.top, padding.right, padding.bottom);
mInsets.set(insets);
- // Increase our bottom insets so we don't overlap with the taskbar.
- mInsets.bottom += grid.nonOverlappingTaskbarInset;
if (mWorkspaceFadeInAdjacentScreens) {
// In landscape mode the page spacing is set to the default.
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index a701548..9a5fd05 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -17,15 +17,11 @@
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_TAP_ON_PERSONAL_TAB;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_TAP_ON_WORK_TAB;
-import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_HAS_SHORTCUT_PERMISSION;
-import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_QUIET_MODE_CHANGE_PERMISSION;
-import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_QUIET_MODE_ENABLED;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.Context;
-import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
@@ -34,7 +30,7 @@
import android.os.Bundle;
import android.os.Parcelable;
import android.os.Process;
-import android.text.Selection;
+import android.os.UserManager;
import android.text.SpannableStringBuilder;
import android.util.AttributeSet;
import android.util.Log;
@@ -88,11 +84,12 @@
public static final float FLING_VELOCITY_MULTIPLIER = 1200f;
private final Paint mHeaderPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ private final Rect mInsets = new Rect();
protected final BaseDraggingActivity mLauncher;
protected final AdapterHolder[] mAH;
- private final ItemInfoMatcher mPersonalMatcher = ItemInfoMatcher.ofUser(Process.myUserHandle());
- private final ItemInfoMatcher mWorkMatcher = mPersonalMatcher.negate();
+ protected final ItemInfoMatcher mPersonalMatcher = ItemInfoMatcher.ofUser(
+ Process.myUserHandle());
private final AllAppsStore mAllAppsStore = new AllAppsStore();
private final RecyclerView.OnScrollListener mScrollListener =
@@ -102,6 +99,8 @@
updateHeaderScroll(((AllAppsRecyclerView) recyclerView).getCurrentScrollY());
}
};
+ private final WorkProfileManager mWorkManager;
+
private final Paint mNavBarScrimPaint;
private int mNavBarScrimHeight = 0;
@@ -111,8 +110,6 @@
private AllAppsPagedView mViewPager;
protected FloatingHeaderView mHeader;
- private float mHeaderTop;
- private WorkModeSwitch mWorkModeSwitch;
private SpannableStringBuilder mSearchQueryBuilder = null;
@@ -124,10 +121,7 @@
protected RecyclerViewFastScroller mTouchHandler;
protected final Point mFastScrollerOffset = new Point();
- private Rect mInsets = new Rect();
-
private SearchAdapterProvider mSearchAdapterProvider;
- private WorkAdapterProvider mWorkAdapterProvider;
private final int mScrimColor;
private final int mHeaderProtectionColor;
private final float mHeaderThreshold;
@@ -156,15 +150,11 @@
mLauncher.addOnDeviceProfileChangeListener(this);
mSearchAdapterProvider = mLauncher.createSearchAdapterProvider(this);
- mSearchQueryBuilder = new SpannableStringBuilder();
- Selection.setSelection(mSearchQueryBuilder, 0);
mAH = new AdapterHolder[2];
- mWorkAdapterProvider = new WorkAdapterProvider(mLauncher, () -> {
- if (mAH[AdapterHolder.WORK] != null) {
- mAH[AdapterHolder.WORK].appsList.updateAdapterItems();
- }
- });
+
+ mWorkManager = new WorkProfileManager(mLauncher.getSystemService(UserManager.class), this,
+ Utilities.getPrefs(mLauncher));
mAH[AdapterHolder.MAIN] = new AdapterHolder(false /* isWork */);
mAH[AdapterHolder.WORK] = new AdapterHolder(true /* isWork */);
@@ -220,8 +210,8 @@
return mAllAppsStore;
}
- public WorkModeSwitch getWorkModeSwitch() {
- return mWorkModeSwitch;
+ public WorkProfileManager getWorkManager() {
+ return mWorkManager;
}
@Override
@@ -240,7 +230,7 @@
private void onAppsUpdated() {
boolean hasWorkApps = false;
for (AppInfo app : mAllAppsStore.getApps()) {
- if (mWorkMatcher.matches(app, null)) {
+ if (mWorkManager.getMatcher().matches(app, null)) {
hasWorkApps = true;
break;
}
@@ -248,20 +238,12 @@
mHasWorkApps = hasWorkApps;
if (!mAH[AdapterHolder.MAIN].appsList.hasFilter()) {
rebindAdapters();
- if (mHasWorkApps) {
- resetWorkProfile();
+ if (hasWorkApps) {
+ mWorkManager.reset();
}
}
}
- private void resetWorkProfile() {
- boolean isEnabled = !mAllAppsStore.hasModelFlag(FLAG_QUIET_MODE_ENABLED);
- if (mWorkModeSwitch != null) {
- mWorkModeSwitch.updateCurrentState(isEnabled);
- }
- mWorkAdapterProvider.updateCurrentState(isEnabled);
- }
-
/**
* Returns whether the view itself will handle the touch event or not.
*/
@@ -460,7 +442,7 @@
if (mUsingTabs) {
mAH[AdapterHolder.MAIN].setup(mViewPager.getChildAt(0), mPersonalMatcher);
- mAH[AdapterHolder.WORK].setup(mViewPager.getChildAt(1), mWorkMatcher);
+ mAH[AdapterHolder.WORK].setup(mViewPager.getChildAt(1), mWorkManager.getMatcher());
mAH[AdapterHolder.WORK].recyclerView.setId(R.id.apps_list_view_work);
mViewPager.getPageIndicator().setActiveMarker(AdapterHolder.MAIN);
findViewById(R.id.tab_personal)
@@ -488,34 +470,12 @@
mAllAppsStore.registerIconContainer(mAH[AdapterHolder.WORK].recyclerView);
}
- private void setupWorkToggle() {
- removeWorkToggle();
- if (Utilities.ATLEAST_P) {
- mWorkModeSwitch = (WorkModeSwitch) mLauncher.getLayoutInflater().inflate(
- R.layout.work_mode_fab, this, false);
- this.addView(mWorkModeSwitch);
- mWorkModeSwitch.setInsets(mInsets);
- mWorkModeSwitch.post(() -> {
- mAH[AdapterHolder.WORK].applyPadding();
- resetWorkProfile();
- });
- }
- }
-
- private void removeWorkToggle() {
- if (mWorkModeSwitch == null) return;
- if (mWorkModeSwitch.getParent() == this) {
- this.removeView(mWorkModeSwitch);
- }
- mWorkModeSwitch = null;
- }
private void replaceRVContainer(boolean showTabs) {
- for (int i = 0; i < mAH.length; i++) {
- AllAppsRecyclerView rv = mAH[i].recyclerView;
- if (rv != null) {
- rv.setLayoutManager(null);
- rv.setAdapter(null);
+ for (AdapterHolder adapterHolder : mAH) {
+ if (adapterHolder.recyclerView != null) {
+ adapterHolder.recyclerView.setLayoutManager(null);
+ adapterHolder.recyclerView.setAdapter(null);
}
}
View oldView = getRecyclerViewContainer();
@@ -532,10 +492,10 @@
mViewPager = (AllAppsPagedView) newView;
mViewPager.initParentViews(this);
mViewPager.getPageIndicator().setOnActivePageChangedListener(this);
- setupWorkToggle();
+ mWorkManager.attachWorkModeSwitch();
} else {
+ mWorkManager.detachWorkModeSwitch();
mViewPager = null;
- removeWorkToggle();
}
}
@@ -550,11 +510,8 @@
mAH[currentActivePage].recyclerView.bindFastScrollbar();
}
reset(true /* animate */);
- if (mWorkModeSwitch != null) {
- mWorkModeSwitch.setWorkTabVisible(currentActivePage == AdapterHolder.WORK
- && mAllAppsStore.hasModelFlag(
- FLAG_HAS_SHORTCUT_PERMISSION | FLAG_QUIET_MODE_CHANGE_PERMISSION));
- }
+
+ mWorkManager.onActivePageChanged(currentActivePage);
}
// Used by tests only
@@ -626,7 +583,6 @@
mAH[i].recyclerView.scrollToTop();
}
}
- mHeaderTop = mHeader.getTop();
}
public void setLastSearchQuery(String query) {
@@ -731,7 +687,6 @@
public static final int MAIN = 0;
public static final int WORK = 1;
- private ItemInfoMatcher mInfoMatcher;
private final boolean mIsWork;
public final AllAppsGridAdapter adapter;
final LinearLayoutManager layoutManager;
@@ -739,17 +694,16 @@
final Rect padding = new Rect();
AllAppsRecyclerView recyclerView;
boolean verticalFadingEdge;
- private View mOverlay;
- boolean mWorkDisabled;
AdapterHolder(boolean isWork) {
mIsWork = isWork;
appsList = new AlphabeticalAppsList(mLauncher, mAllAppsStore,
- isWork ? mWorkAdapterProvider : null);
+ isWork ? mWorkManager.getAdapterProvider() : null);
BaseAdapterProvider[] adapterProviders =
- isWork ? new BaseAdapterProvider[]{mSearchAdapterProvider, mWorkAdapterProvider}
+ isWork ? new BaseAdapterProvider[]{mSearchAdapterProvider,
+ mWorkManager.getAdapterProvider()}
: new BaseAdapterProvider[]{mSearchAdapterProvider};
adapter = new AllAppsGridAdapter(mLauncher, getLayoutInflater(), appsList,
@@ -759,7 +713,6 @@
}
void setup(@NonNull View rv, @Nullable ItemInfoMatcher matcher) {
- mInfoMatcher = matcher;
appsList.updateItemFilter(matcher);
recyclerView = (AllAppsRecyclerView) rv;
recyclerView.setEdgeEffectFactory(createEdgeEffectFactory());
@@ -782,12 +735,10 @@
void applyPadding() {
if (recyclerView != null) {
- Resources res = getResources();
- int switchH = res.getDimensionPixelSize(R.dimen.work_profile_footer_padding) * 2
- + mInsets.bottom + Utilities.calculateTextHeight(
- res.getDimension(R.dimen.work_profile_footer_text_size));
-
- int bottomOffset = mWorkModeSwitch != null && mIsWork ? switchH : 0;
+ int bottomOffset = 0;
+ if (mIsWork && mWorkManager.getWorkModeSwitch() != null) {
+ bottomOffset = mInsets.bottom + mWorkManager.getWorkModeSwitch().getHeight();
+ }
recyclerView.setPadding(padding.left, padding.top, padding.right,
padding.bottom + bottomOffset);
}
diff --git a/src/com/android/launcher3/allapps/WorkAdapterProvider.java b/src/com/android/launcher3/allapps/WorkAdapterProvider.java
index 13444dd..331320d 100644
--- a/src/com/android/launcher3/allapps/WorkAdapterProvider.java
+++ b/src/com/android/launcher3/allapps/WorkAdapterProvider.java
@@ -15,12 +15,11 @@
*/
package com.android.launcher3.allapps;
+import android.content.SharedPreferences;
import android.view.LayoutInflater;
import android.view.ViewGroup;
-import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
import java.util.ArrayList;
@@ -33,13 +32,13 @@
private static final int VIEW_TYPE_WORK_EDU_CARD = 1 << 20;
private static final int VIEW_TYPE_WORK_DISABLED_CARD = 1 << 21;
- private final Runnable mRefreshCB;
- private final BaseDraggingActivity mLauncher;
- private boolean mEnabled;
- WorkAdapterProvider(BaseDraggingActivity launcher, Runnable refreshCallback) {
- mLauncher = launcher;
- mRefreshCB = refreshCallback;
+ @WorkProfileManager.WorkProfileState
+ private int mState;
+ private SharedPreferences mPreferences;
+
+ WorkAdapterProvider(SharedPreferences prefs) {
+ mPreferences = prefs;
}
@Override
@@ -61,19 +60,19 @@
* returns whether or not work apps should be visible in work tab.
*/
public boolean shouldShowWorkApps() {
- return mEnabled;
+ return mState != WorkProfileManager.STATE_DISABLED;
}
/**
* Adds work profile specific adapter items to adapterItems and returns number of items added
*/
public int addWorkItems(ArrayList<AllAppsGridAdapter.AdapterItem> adapterItems) {
- if (!mEnabled) {
+ if (mState == WorkProfileManager.STATE_DISABLED) {
//add disabled card here.
AllAppsGridAdapter.AdapterItem disabledCard = new AllAppsGridAdapter.AdapterItem();
disabledCard.viewType = VIEW_TYPE_WORK_DISABLED_CARD;
adapterItems.add(disabledCard);
- } else if (!isEduSeen()) {
+ } else if (mState == WorkProfileManager.STATE_ENABLED && !isEduSeen()) {
AllAppsGridAdapter.AdapterItem eduCard = new AllAppsGridAdapter.AdapterItem();
eduCard.viewType = VIEW_TYPE_WORK_EDU_CARD;
adapterItems.add(eduCard);
@@ -85,9 +84,8 @@
/**
* Sets the current state of work profile
*/
- public void updateCurrentState(boolean isEnabled) {
- mEnabled = isEnabled;
- mRefreshCB.run();
+ public void updateCurrentState(@WorkProfileManager.WorkProfileState int state) {
+ mState = state;
}
@Override
@@ -101,6 +99,6 @@
}
private boolean isEduSeen() {
- return Utilities.getPrefs(mLauncher).getInt(KEY_WORK_EDU_STEP, 0) != 0;
+ return mPreferences.getInt(KEY_WORK_EDU_STEP, 0) != 0;
}
}
diff --git a/src/com/android/launcher3/allapps/WorkModeSwitch.java b/src/com/android/launcher3/allapps/WorkModeSwitch.java
index 5d3af08..5d64041 100644
--- a/src/com/android/launcher3/allapps/WorkModeSwitch.java
+++ b/src/com/android/launcher3/allapps/WorkModeSwitch.java
@@ -16,43 +16,41 @@
package com.android.launcher3.allapps;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TURN_OFF_WORK_APPS_TAP;
-import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import android.content.Context;
import android.graphics.Insets;
import android.graphics.Rect;
-import android.os.Build;
-import android.os.Process;
-import android.os.UserHandle;
-import android.os.UserManager;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowInsets;
import android.widget.Button;
-import androidx.annotation.Nullable;
-import androidx.annotation.RequiresApi;
-
+import com.android.launcher3.BaseDraggingActivity;
+import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Insettable;
import com.android.launcher3.Launcher;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.KeyboardInsetAnimationCallback;
-import com.android.launcher3.pm.UserCache;
+import com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip;
/**
* Work profile toggle switch shown at the bottom of AllApps work tab
*/
-public class WorkModeSwitch extends Button implements Insettable, View.OnClickListener {
+public class WorkModeSwitch extends Button implements Insettable, View.OnClickListener,
+ KeyboardInsetAnimationCallback.KeyboardInsetListener,
+ PersonalWorkSlidingTabStrip.OnActivePageChangedListener {
- private Rect mInsets = new Rect();
+ private static final int FLAG_FADE_ONGOING = 1 << 1;
+ private static final int FLAG_TRANSLATION_ONGOING = 1 << 2;
+ private static final int FLAG_PROFILE_TOGGLE_ONGOING = 1 << 3;
+
+ private final Rect mInsets = new Rect();
+ private int mFlags;
private boolean mWorkEnabled;
+ private boolean mOnWorkTab;
- @Nullable
- private KeyboardInsetAnimationCallback mKeyboardInsetAnimationCallback;
- private boolean mWorkTabVisible;
-
public WorkModeSwitch(Context context) {
this(context, null, 0);
}
@@ -71,9 +69,12 @@
setSelected(true);
setOnClickListener(this);
if (Utilities.ATLEAST_R) {
- mKeyboardInsetAnimationCallback = new KeyboardInsetAnimationCallback(this);
- setWindowInsetsAnimationCallback(mKeyboardInsetAnimationCallback);
+ KeyboardInsetAnimationCallback keyboardInsetAnimationCallback =
+ new KeyboardInsetAnimationCallback(this);
+ setWindowInsetsAnimationCallback(keyboardInsetAnimationCallback);
}
+ DeviceProfile grid = BaseDraggingActivity.fromContext(getContext()).getDeviceProfile();
+ setInsets(grid.getInsets());
}
@Override
@@ -87,57 +88,57 @@
}
}
- /**
- * Animates in/out work profile toggle panel based on the tab user is on
- */
- public void setWorkTabVisible(boolean workTabVisible) {
- clearAnimation();
- mWorkTabVisible = workTabVisible;
- if (workTabVisible && mWorkEnabled) {
- setEnabled(true);
- setVisibility(VISIBLE);
- setAlpha(0);
- animate().alpha(1).start();
- } else {
- animate().alpha(0).withEndAction(() -> this.setVisibility(GONE)).start();
- }
+
+ @Override
+ public void onActivePageChanged(int page) {
+ mOnWorkTab = page == AllAppsContainerView.AdapterHolder.WORK;
+ updateVisibility();
}
@Override
public void onClick(View view) {
- if (Utilities.ATLEAST_P && mWorkTabVisible) {
- setEnabled(false);
- Launcher.fromContext(getContext()).getStatsLogManager().logger().log(
- LAUNCHER_TURN_OFF_WORK_APPS_TAP);
- UI_HELPER_EXECUTOR.post(() -> setWorkProfileEnabled(getContext(), false));
+ if (Utilities.ATLEAST_P && isEnabled()) {
+ setFlag(FLAG_PROFILE_TOGGLE_ONGOING);
+ Launcher launcher = Launcher.getLauncher(getContext());
+ launcher.getStatsLogManager().logger().log(LAUNCHER_TURN_OFF_WORK_APPS_TAP);
+ launcher.getAppsView().getWorkManager().setWorkProfileEnabled(false);
}
}
+ @Override
+ public boolean isEnabled() {
+ return super.isEnabled() && getVisibility() == VISIBLE && mFlags == 0;
+ }
+
/**
* Sets the enabled or disabled state of the button
*/
public void updateCurrentState(boolean active) {
+ removeFlag(FLAG_PROFILE_TOGGLE_ONGOING);
mWorkEnabled = active;
- setEnabled(true);
- setVisibility(active ? VISIBLE : GONE);
+ updateVisibility();
}
- @RequiresApi(Build.VERSION_CODES.P)
- public static Boolean setWorkProfileEnabled(Context context, boolean enabled) {
- UserManager userManager = context.getSystemService(UserManager.class);
- boolean showConfirm = false;
- for (UserHandle userProfile : UserCache.INSTANCE.get(context).getUserProfiles()) {
- if (Process.myUserHandle().equals(userProfile)) {
- continue;
- }
- showConfirm |= !userManager.requestQuietModeEnabled(!enabled, userProfile);
+
+ private void updateVisibility() {
+ clearAnimation();
+ if (mWorkEnabled && mOnWorkTab) {
+ setFlag(FLAG_FADE_ONGOING);
+ setVisibility(VISIBLE);
+ setAlpha(0);
+ animate().alpha(1).withEndAction(() -> removeFlag(FLAG_FADE_ONGOING)).start();
+ } else if (getVisibility() != GONE) {
+ setFlag(FLAG_FADE_ONGOING);
+ animate().alpha(0).withEndAction(() -> {
+ removeFlag(FLAG_FADE_ONGOING);
+ this.setVisibility(GONE);
+ }).start();
}
- return showConfirm;
}
@Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
- if (Utilities.ATLEAST_R && mWorkTabVisible) {
+ if (Utilities.ATLEAST_R && isEnabled()) {
setTranslationY(0);
if (insets.isVisible(WindowInsets.Type.ime())) {
Insets keyboardInsets = insets.getInsets(WindowInsets.Type.ime());
@@ -146,4 +147,22 @@
}
return insets;
}
+
+ @Override
+ public void onTranslationStart() {
+ setFlag(FLAG_TRANSLATION_ONGOING);
+ }
+
+ @Override
+ public void onTranslationEnd() {
+ removeFlag(FLAG_TRANSLATION_ONGOING);
+ }
+
+ private void setFlag(int flag) {
+ mFlags |= flag;
+ }
+
+ private void removeFlag(int flag) {
+ mFlags &= ~flag;
+ }
}
diff --git a/src/com/android/launcher3/allapps/WorkPausedCard.java b/src/com/android/launcher3/allapps/WorkPausedCard.java
index 7908b63..7593ca7 100644
--- a/src/com/android/launcher3/allapps/WorkPausedCard.java
+++ b/src/com/android/launcher3/allapps/WorkPausedCard.java
@@ -16,7 +16,6 @@
package com.android.launcher3.allapps;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TURN_ON_WORK_APPS_TAP;
-import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import android.content.Context;
import android.content.res.Configuration;
@@ -62,8 +61,8 @@
public void onClick(View view) {
if (Utilities.ATLEAST_P) {
setEnabled(false);
+ mLauncher.getAppsView().getWorkManager().setWorkProfileEnabled(true);
mLauncher.getStatsLogManager().logger().log(LAUNCHER_TURN_ON_WORK_APPS_TAP);
- UI_HELPER_EXECUTOR.post(() -> WorkModeSwitch.setWorkProfileEnabled(getContext(), true));
}
}
diff --git a/src/com/android/launcher3/allapps/WorkProfileManager.java b/src/com/android/launcher3/allapps/WorkProfileManager.java
new file mode 100644
index 0000000..c53360a
--- /dev/null
+++ b/src/com/android/launcher3/allapps/WorkProfileManager.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2021 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.allapps;
+
+import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_HAS_SHORTCUT_PERMISSION;
+import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_QUIET_MODE_CHANGE_PERMISSION;
+import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_QUIET_MODE_ENABLED;
+import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
+
+import android.content.SharedPreferences;
+import android.os.Build;
+import android.os.Process;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.Log;
+
+import androidx.annotation.IntDef;
+import androidx.annotation.RequiresApi;
+
+import com.android.launcher3.R;
+import com.android.launcher3.util.ItemInfoMatcher;
+import com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Companion class for {@link AllAppsContainerView} to manage work tab and personal tab related
+ * logic based on {@link WorkProfileState}?
+ */
+public class WorkProfileManager implements PersonalWorkSlidingTabStrip.OnActivePageChangedListener {
+ private static final String TAG = "WorkProfileManager";
+
+
+ public static final int STATE_ENABLED = 1;
+ public static final int STATE_DISABLED = 2;
+ public static final int STATE_TRANSITION = 3;
+
+
+ private final UserManager mUserManager;
+
+ /**
+ * Work profile manager states
+ */
+ @IntDef(value = {
+ STATE_ENABLED,
+ STATE_DISABLED,
+ STATE_TRANSITION
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface WorkProfileState {
+ }
+
+ private final AllAppsContainerView mAllApps;
+ private final WorkAdapterProvider mAdapterProvider;
+ private final ItemInfoMatcher mMatcher;
+
+ private WorkModeSwitch mWorkModeSwitch;
+
+ @WorkProfileState
+ private int mCurrentState;
+
+
+ public WorkProfileManager(UserManager userManager, AllAppsContainerView allApps,
+ SharedPreferences preferences) {
+ mUserManager = userManager;
+ mAllApps = allApps;
+ mAdapterProvider = new WorkAdapterProvider(preferences);
+ mMatcher = mAllApps.mPersonalMatcher.negate();
+ }
+
+ /**
+ * Posts quite mode enable/disable call for work profile user
+ */
+ @RequiresApi(Build.VERSION_CODES.P)
+ public void setWorkProfileEnabled(boolean enabled) {
+ updateCurrentState(STATE_TRANSITION);
+ UI_HELPER_EXECUTOR.post(() -> {
+ for (UserHandle userProfile : mUserManager.getUserProfiles()) {
+ if (Process.myUserHandle().equals(userProfile)) {
+ continue;
+ }
+ mUserManager.requestQuietModeEnabled(!enabled, userProfile);
+ }
+ });
+ }
+
+ @Override
+ public void onActivePageChanged(int page) {
+ if (mWorkModeSwitch != null) {
+ mWorkModeSwitch.onActivePageChanged(page);
+ }
+ }
+
+ /**
+ * Requests work profile state from {@link AllAppsStore} and updates work profile related views
+ */
+ public void reset() {
+ boolean isEnabled = !mAllApps.getAppsStore().hasModelFlag(FLAG_QUIET_MODE_ENABLED);
+ updateCurrentState(isEnabled ? STATE_ENABLED : STATE_DISABLED);
+ }
+
+ private void updateCurrentState(@WorkProfileState int currentState) {
+ mCurrentState = currentState;
+ mAdapterProvider.updateCurrentState(currentState);
+ if (getAH() != null) {
+ getAH().appsList.updateAdapterItems();
+ }
+ if (mWorkModeSwitch != null) {
+ mWorkModeSwitch.updateCurrentState(currentState == STATE_ENABLED);
+ }
+ }
+
+ /**
+ * Creates and attaches for profile toggle button to {@link AllAppsContainerView}
+ */
+ public void attachWorkModeSwitch() {
+ if (!mAllApps.getAppsStore().hasModelFlag(
+ FLAG_HAS_SHORTCUT_PERMISSION | FLAG_QUIET_MODE_CHANGE_PERMISSION)) {
+ Log.e(TAG, "Unable to attach widget; Missing required permissions");
+ return;
+ }
+ if (mWorkModeSwitch == null) {
+ mWorkModeSwitch = (WorkModeSwitch) mAllApps.getLayoutInflater().inflate(
+ R.layout.work_mode_fab, mAllApps, false);
+ }
+ if (mWorkModeSwitch.getParent() != mAllApps) {
+ mAllApps.addView(mWorkModeSwitch);
+ }
+ if (getAH() != null) {
+ getAH().applyPadding();
+ }
+ mWorkModeSwitch.updateCurrentState(mCurrentState == STATE_ENABLED);
+ }
+
+ /**
+ * Removes work profile toggle button from {@link AllAppsContainerView}
+ */
+ public void detachWorkModeSwitch() {
+ if (mWorkModeSwitch != null && mWorkModeSwitch.getParent() == mAllApps) {
+ mAllApps.removeView(mWorkModeSwitch);
+ }
+ mWorkModeSwitch = null;
+ }
+
+
+ public WorkAdapterProvider getAdapterProvider() {
+ return mAdapterProvider;
+ }
+
+ public ItemInfoMatcher getMatcher() {
+ return mMatcher;
+ }
+
+ public WorkModeSwitch getWorkModeSwitch() {
+ return mWorkModeSwitch;
+ }
+
+ private AllAppsContainerView.AdapterHolder getAH() {
+ return mAllApps.mAH[AllAppsContainerView.AdapterHolder.WORK];
+ }
+}
diff --git a/src/com/android/launcher3/anim/FlingSpringAnim.java b/src/com/android/launcher3/anim/FlingSpringAnim.java
index 6ea38ec..51eab4c 100644
--- a/src/com/android/launcher3/anim/FlingSpringAnim.java
+++ b/src/com/android/launcher3/anim/FlingSpringAnim.java
@@ -40,8 +40,8 @@
private float mTargetPosition;
public <K> FlingSpringAnim(K object, Context context, FloatPropertyCompat<K> property,
- float startPosition, float targetPosition, float startVelocity, float minVisChange,
- float minValue, float maxValue, float springVelocityFactor,
+ float startPosition, float targetPosition, float startVelocityPxPerS,
+ float minVisChange, float minValue, float maxValue,
OnAnimationEndListener onEndListener) {
ResourceProvider rp = DynamicResource.provider(context);
float damping = rp.getFloat(R.dimen.swipe_up_rect_xy_damping_ratio);
@@ -53,19 +53,19 @@
// Have the spring pull towards the target if we've slowed down too much before
// reaching it.
.setMinimumVisibleChange(minVisChange)
- .setStartVelocity(startVelocity)
+ .setStartVelocity(startVelocityPxPerS)
.setMinValue(minValue)
.setMaxValue(maxValue);
mTargetPosition = targetPosition;
// We are already past the fling target, so skip it to avoid losing a frame of the spring.
- mSkipFlingAnim = startPosition <= minValue && startVelocity < 0
- || startPosition >= maxValue && startVelocity > 0;
+ mSkipFlingAnim = startPosition <= minValue && startVelocityPxPerS < 0
+ || startPosition >= maxValue && startVelocityPxPerS > 0;
mFlingAnim.addEndListener(((animation, canceled, value, velocity) -> {
mSpringAnim = new SpringAnimation(object, property)
.setStartValue(value)
- .setStartVelocity(velocity * springVelocityFactor)
+ .setStartVelocity(velocity)
.setSpring(new SpringForce(mTargetPosition)
.setStiffness(stiffness)
.setDampingRatio(damping));
diff --git a/src/com/android/launcher3/anim/KeyboardInsetAnimationCallback.java b/src/com/android/launcher3/anim/KeyboardInsetAnimationCallback.java
index ef4ada3..9d96365 100644
--- a/src/com/android/launcher3/anim/KeyboardInsetAnimationCallback.java
+++ b/src/com/android/launcher3/anim/KeyboardInsetAnimationCallback.java
@@ -65,7 +65,32 @@
public WindowInsetsAnimation.Bounds onStart(WindowInsetsAnimation animation,
WindowInsetsAnimation.Bounds bounds) {
mTerminalTranslation = mView.getTranslationY();
- mView.setTranslationY(mInitialTranslation);
+ if (mView instanceof KeyboardInsetListener) {
+ ((KeyboardInsetListener) mView).onTranslationStart();
+ }
return super.onStart(animation, bounds);
}
+
+ @Override
+ public void onEnd(WindowInsetsAnimation animation) {
+ if (mView instanceof KeyboardInsetListener) {
+ ((KeyboardInsetListener) mView).onTranslationEnd();
+ }
+ super.onEnd(animation);
+ }
+
+ /**
+ * Interface Allowing views to listen for keyboard translation events
+ */
+ public interface KeyboardInsetListener {
+ /**
+ * Called from {@link KeyboardInsetAnimationCallback#onStart}
+ */
+ void onTranslationStart();
+
+ /**
+ * Called from {@link KeyboardInsetAnimationCallback#onEnd}
+ */
+ void onTranslationEnd();
+ }
}
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index c067291..49e0171 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -183,7 +183,7 @@
+ "Ignored if ENABLE_SMARTSPACE_UNIVERSAL is enabled.");
public static final BooleanFlag ENABLE_SMARTSPACE_FEEDBACK = getDebugFlag(
- "ENABLE_SMARTSPACE_FEEDBACK", true,
+ "ENABLE_SMARTSPACE_FEEDBACK", false,
"Adds a menu option to send feedback for Enhanced Smartspace.");
public static final BooleanFlag ENABLE_SMARTSPACE_DISMISS = getDebugFlag(
diff --git a/src/com/android/launcher3/model/PackageInstallStateChangedTask.java b/src/com/android/launcher3/model/PackageInstallStateChangedTask.java
index 9889a80..b74d0fc 100644
--- a/src/com/android/launcher3/model/PackageInstallStateChangedTask.java
+++ b/src/com/android/launcher3/model/PackageInstallStateChangedTask.java
@@ -21,7 +21,6 @@
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.ItemInfo;
-import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.pm.PackageInstallInfo;
import com.android.launcher3.util.InstantAppResolver;
@@ -73,13 +72,7 @@
dataModel.forAllWorkspaceItemInfos(mInstallInfo.user, si -> {
if (si.hasPromiseIconUi()
&& mInstallInfo.packageName.equals(si.getTargetPackage())) {
- int installProgress = mInstallInfo.progress;
-
- si.setProgressLevel(installProgress, PackageInstallInfo.STATUS_INSTALLING);
- if (mInstallInfo.state == PackageInstallInfo.STATUS_FAILED) {
- // Mark this info as broken.
- si.runtimeStatusFlags &= ~ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE;
- }
+ si.setProgressLevel(mInstallInfo);
updates.add(si);
}
});
diff --git a/src/com/android/launcher3/model/data/ItemInfoWithIcon.java b/src/com/android/launcher3/model/data/ItemInfoWithIcon.java
index 6813b97..a74c02f 100644
--- a/src/com/android/launcher3/model/data/ItemInfoWithIcon.java
+++ b/src/com/android/launcher3/model/data/ItemInfoWithIcon.java
@@ -24,6 +24,7 @@
import com.android.launcher3.icons.BitmapInfo;
import com.android.launcher3.icons.FastBitmapDrawable;
+import com.android.launcher3.logging.FileLog;
import com.android.launcher3.pm.PackageInstallInfo;
import com.android.launcher3.util.PackageManagerHelper;
@@ -179,6 +180,12 @@
*/
public void setProgressLevel(PackageInstallInfo installInfo) {
setProgressLevel(installInfo.progress, installInfo.state);
+
+ if (installInfo.state == PackageInstallInfo.STATUS_FAILED) {
+ FileLog.d(TAG,
+ "Icon info: " + this + " marked broken with install info: " + installInfo,
+ new Exception());
+ }
}
/**
diff --git a/src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java b/src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java
index f73d782..c685891 100644
--- a/src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java
+++ b/src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java
@@ -268,9 +268,7 @@
} else {
lp.leftMargin = lp.rightMargin = 0;
lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
- lp.bottomMargin = grid.isTaskbarPresent
- ? grid.workspacePadding.bottom + grid.taskbarSize
- : grid.hotseatBarSizePx + insets.bottom;
+ lp.bottomMargin = grid.hotseatBarSizePx + insets.bottom;
}
setLayoutParams(lp);
}
diff --git a/src/com/android/launcher3/pm/PackageInstallInfo.java b/src/com/android/launcher3/pm/PackageInstallInfo.java
index fad904f..1797c1f 100644
--- a/src/com/android/launcher3/pm/PackageInstallInfo.java
+++ b/src/com/android/launcher3/pm/PackageInstallInfo.java
@@ -57,4 +57,28 @@
public static PackageInstallInfo fromState(int state, String packageName, UserHandle user) {
return new PackageInstallInfo(packageName, state, 0 /* progress */, user);
}
+
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + "(" + dumpProperties() + ")";
+ }
+
+ private String dumpProperties() {
+ return "componentName=" + componentName
+ + "packageName=" + packageName
+ + " state=" + stateToString()
+ + " progress=" + progress
+ + " user=" + user;
+ }
+
+ private String stateToString() {
+ switch (state) {
+ case STATUS_INSTALLED : return "STATUS_INSTALLED";
+ case STATUS_INSTALLING : return "STATUS_INSTALLING";
+ case STATUS_INSTALLED_DOWNLOADING : return "STATUS_INSTALLED_DOWNLOADING";
+ case STATUS_FAILED : return "STATUS_FAILED";
+ default : return "INVALID STATE";
+ }
+ }
}
diff --git a/src/com/android/launcher3/states/SpringLoadedState.java b/src/com/android/launcher3/states/SpringLoadedState.java
index 8db1dbe..5fe5450 100644
--- a/src/com/android/launcher3/states/SpringLoadedState.java
+++ b/src/com/android/launcher3/states/SpringLoadedState.java
@@ -59,11 +59,10 @@
float scale = grid.workspaceSpringLoadShrinkFactor;
Rect insets = launcher.getDragLayer().getInsets();
- int insetsBottom = grid.isTaskbarPresent ? grid.taskbarSize : insets.bottom;
float scaledHeight = scale * ws.getNormalChildHeight();
float shrunkTop = insets.top + grid.dropTargetBarSizePx;
- float shrunkBottom = ws.getMeasuredHeight() - insetsBottom
+ float shrunkBottom = ws.getMeasuredHeight() - insets.bottom
- grid.workspacePadding.bottom
- grid.workspaceSpringLoadedBottomSpace;
float totalShrunkSpace = shrunkBottom - shrunkTop;
diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java
index 86acff7..5a9c074 100644
--- a/src/com/android/launcher3/testing/TestInformationHandler.java
+++ b/src/com/android/launcher3/testing/TestInformationHandler.java
@@ -116,9 +116,7 @@
return getUIProperty(Bundle::putParcelable, activity -> {
WindowInsets insets = activity.getWindow()
.getDecorView().getRootWindowInsets();
- return Insets.subtract(
- insets.getSystemWindowInsets(),
- Insets.of(0, 0, 0, mDeviceProfile.nonOverlappingTaskbarInset));
+ return insets.getSystemWindowInsets();
}, this::getCurrentActivity);
}
diff --git a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
index 0c3ad1d..3ac25f2 100644
--- a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
+++ b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
@@ -20,7 +20,8 @@
import static android.view.Gravity.END;
import static android.view.Gravity.START;
import static android.view.Gravity.TOP;
-import static android.widget.ListPopupWindow.WRAP_CONTENT;
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
@@ -257,26 +258,28 @@
}
@Override
- public float getTaskMenuX(float x, View thumbnailView, int overScroll) {
+ public float getTaskMenuX(float x, View thumbnailView, int overScroll,
+ DeviceProfile deviceProfile) {
return thumbnailView.getMeasuredWidth() + x;
}
@Override
public float getTaskMenuY(float y, View thumbnailView, int overScroll) {
- return y + overScroll;
+ return y + overScroll +
+ (thumbnailView.getMeasuredHeight() - thumbnailView.getMeasuredWidth()) / 2f;
}
@Override
- public int getTaskMenuWidth(View view) {
- return view.getMeasuredHeight();
+ public int getTaskMenuWidth(View view, DeviceProfile deviceProfile) {
+ return view.getMeasuredWidth();
}
@Override
public void setTaskOptionsMenuLayoutOrientation(DeviceProfile deviceProfile,
LinearLayout taskMenuLayout, int dividerSpacing,
ShapeDrawable dividerDrawable) {
- taskMenuLayout.setOrientation(LinearLayout.HORIZONTAL);
- dividerDrawable.setIntrinsicWidth(dividerSpacing);
+ taskMenuLayout.setOrientation(LinearLayout.VERTICAL);
+ dividerDrawable.setIntrinsicHeight(dividerSpacing);
taskMenuLayout.setDividerDrawable(dividerDrawable);
}
@@ -284,12 +287,9 @@
public void setLayoutParamsForTaskMenuOptionItem(LinearLayout.LayoutParams lp,
LinearLayout viewGroup, DeviceProfile deviceProfile) {
// Phone fake landscape
- viewGroup.setOrientation(LinearLayout.VERTICAL);
- lp.width = 0;
+ viewGroup.setOrientation(LinearLayout.HORIZONTAL);
+ lp.width = MATCH_PARENT;
lp.height = WRAP_CONTENT;
- lp.weight = 1;
- Utilities.setStartMarginForView(viewGroup.findViewById(R.id.text), 0);
- Utilities.setStartMarginForView(viewGroup.findViewById(R.id.icon), 0);
}
@Override
diff --git a/src/com/android/launcher3/touch/PagedOrientationHandler.java b/src/com/android/launcher3/touch/PagedOrientationHandler.java
index 494fe22..19d73a8 100644
--- a/src/com/android/launcher3/touch/PagedOrientationHandler.java
+++ b/src/com/android/launcher3/touch/PagedOrientationHandler.java
@@ -171,9 +171,16 @@
void setSplitIconParams(View primaryIconView, View secondaryIconView,
int taskIconHeight, Rect primarySnapshotBounds, Rect secondarySnapshotBounds,
boolean isRtl, DeviceProfile deviceProfile, StagedSplitBounds splitConfig);
- float getTaskMenuX(float x, View thumbnailView, int overScroll);
+
+ /*
+ * The following two methods try to center the TaskMenuView in landscape by finding the center
+ * of the thumbnail view and then subtracting half of the taskMenu width. In this case, the
+ * taskMenu width is the same size as the thumbnail width (what got set below in
+ * getTaskMenuWidth()), so we directly use that in the calculations.
+ */
+ float getTaskMenuX(float x, View thumbnailView, int overScroll, DeviceProfile deviceProfile);
float getTaskMenuY(float y, View thumbnailView, int overScroll);
- int getTaskMenuWidth(View view);
+ int getTaskMenuWidth(View view, DeviceProfile deviceProfile);
/**
* Sets linear layout orientation for {@link com.android.launcher3.popup.SystemShortcut} items
* inside task menu view.
diff --git a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
index a453cae..1b8ebd8 100644
--- a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
+++ b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
@@ -20,6 +20,7 @@
import static android.view.Gravity.CENTER_HORIZONTAL;
import static android.view.Gravity.START;
import static android.view.Gravity.TOP;
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
@@ -264,8 +265,14 @@
}
@Override
- public float getTaskMenuX(float x, View thumbnailView, int overScroll) {
- return x + overScroll;
+ public float getTaskMenuX(float x, View thumbnailView, int overScroll,
+ DeviceProfile deviceProfile) {
+ if (deviceProfile.isLandscape) {
+ return x + overScroll
+ + (thumbnailView.getMeasuredWidth() - thumbnailView.getMeasuredHeight()) / 2f;
+ } else {
+ return x + overScroll;
+ }
}
@Override
@@ -274,43 +281,27 @@
}
@Override
- public int getTaskMenuWidth(View view) {
- return view.getMeasuredWidth();
+ public int getTaskMenuWidth(View view, DeviceProfile deviceProfile) {
+ return deviceProfile.isLandscape && !deviceProfile.overviewShowAsGrid ?
+ view.getMeasuredHeight() :
+ view.getMeasuredWidth();
}
@Override
public void setTaskOptionsMenuLayoutOrientation(DeviceProfile deviceProfile,
LinearLayout taskMenuLayout, int dividerSpacing,
ShapeDrawable dividerDrawable) {
- if (deviceProfile.isLandscape && !deviceProfile.isTablet) {
- // Phone landscape
- taskMenuLayout.setOrientation(LinearLayout.HORIZONTAL);
- dividerDrawable.setIntrinsicWidth(dividerSpacing);
- } else {
- // Phone Portrait, LargeScreen Landscape/Portrait
- taskMenuLayout.setOrientation(LinearLayout.VERTICAL);
- dividerDrawable.setIntrinsicHeight(dividerSpacing);
- }
+ taskMenuLayout.setOrientation(LinearLayout.VERTICAL);
+ dividerDrawable.setIntrinsicHeight(dividerSpacing);
taskMenuLayout.setDividerDrawable(dividerDrawable);
}
@Override
public void setLayoutParamsForTaskMenuOptionItem(LinearLayout.LayoutParams lp,
LinearLayout viewGroup, DeviceProfile deviceProfile) {
- if (deviceProfile.isLandscape && !deviceProfile.isTablet) {
- // Phone landscape
- viewGroup.setOrientation(LinearLayout.VERTICAL);
- lp.width = 0;
- lp.weight = 1;
- Utilities.setStartMarginForView(viewGroup.findViewById(R.id.text), 0);
- Utilities.setStartMarginForView(viewGroup.findViewById(R.id.icon), 0);
- } else {
- // Phone Portrait, LargeScreen Landscape/Portrait
- viewGroup.setOrientation(LinearLayout.HORIZONTAL);
- lp.width = LinearLayout.LayoutParams.MATCH_PARENT;
- }
-
- lp.height = LinearLayout.LayoutParams.WRAP_CONTENT;
+ viewGroup.setOrientation(LinearLayout.HORIZONTAL);
+ lp.width = LinearLayout.LayoutParams.MATCH_PARENT;
+ lp.height = WRAP_CONTENT;
}
@Override
diff --git a/src/com/android/launcher3/touch/SeascapePagedViewHandler.java b/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
index 4f33ff0..d5851c8 100644
--- a/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
+++ b/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
@@ -81,13 +81,15 @@
}
@Override
- public float getTaskMenuX(float x, View thumbnailView, int overScroll) {
+ public float getTaskMenuX(float x, View thumbnailView, int overScroll,
+ DeviceProfile deviceProfile) {
return x;
}
@Override
public float getTaskMenuY(float y, View thumbnailView, int overScroll) {
- return y + thumbnailView.getMeasuredHeight() + overScroll;
+ return y + overScroll +
+ (thumbnailView.getMeasuredHeight() + thumbnailView.getMeasuredWidth()) / 2f;
}
@Override
diff --git a/src/com/android/launcher3/util/MultiValueAlpha.java b/src/com/android/launcher3/util/MultiValueAlpha.java
index 8591872..bd39391 100644
--- a/src/com/android/launcher3/util/MultiValueAlpha.java
+++ b/src/com/android/launcher3/util/MultiValueAlpha.java
@@ -125,10 +125,13 @@
}
/**
- * Creates and returns an Animator from the current value to the given value.
+ * Creates and returns an Animator from the current value to the given value. Future
+ * animator on the same target automatically cancels the previous one.
*/
public Animator animateToValue(float value) {
- return ObjectAnimator.ofFloat(this, VALUE, value);
+ ObjectAnimator animator = ObjectAnimator.ofFloat(this, VALUE, value);
+ animator.setAutoCancel(true);
+ return animator;
}
}
}
diff --git a/src/com/android/launcher3/views/RecyclerViewFastScroller.java b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
index 2b0f707..a982786 100644
--- a/src/com/android/launcher3/views/RecyclerViewFastScroller.java
+++ b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
@@ -113,7 +113,6 @@
private boolean mIsThumbDetached;
private final boolean mCanThumbDetach;
private boolean mIgnoreDragGesture;
- private boolean mIsRecyclerViewFirstChildInParent = true;
private long mDownTimeStampMillis;
// This is the offset from the top of the scrollbar when the user first starts touching. To
@@ -438,9 +437,7 @@
return false;
}
getHitRect(sTempRect);
- if (mIsRecyclerViewFirstChildInParent) {
- sTempRect.top += mRv.getScrollBarTop();
- }
+ sTempRect.top += mRv.getScrollBarTop();
if (outOffset != null) {
outOffset.set(sTempRect.left, sTempRect.top);
}
@@ -453,8 +450,4 @@
// alpha is so low, it does not matter.
return false;
}
-
- public void setIsRecyclerViewFirstChildInParent(boolean isRecyclerViewFirstChildInParent) {
- mIsRecyclerViewFirstChildInParent = isRecyclerViewFirstChildInParent;
- }
}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index 09f0299..9e12f6f 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -198,7 +198,6 @@
.setOnClickListener((View view) -> mViewPager.snapToPage(0));
findViewById(R.id.tab_work)
.setOnClickListener((View view) -> mViewPager.snapToPage(1));
- fastScroller.setIsRecyclerViewFirstChildInParent(false);
mAdapters.get(AdapterHolder.WORK).setup(findViewById(R.id.work_widgets_list_view));
} else {
mViewPager = null;
@@ -334,13 +333,18 @@
setContentViewChildHorizontalMargin(mSearchScrollController.mContainer,
contentHorizontalMarginInPx);
if (mViewPager == null) {
- setContentViewChildHorizontalMargin(
+ setContentViewChildHorizontalPadding(
mAdapters.get(AdapterHolder.PRIMARY).mWidgetsRecyclerView,
contentHorizontalMarginInPx);
} else {
- setContentViewChildHorizontalMargin(mViewPager, contentHorizontalMarginInPx);
+ setContentViewChildHorizontalPadding(
+ mAdapters.get(AdapterHolder.PRIMARY).mWidgetsRecyclerView,
+ contentHorizontalMarginInPx);
+ setContentViewChildHorizontalPadding(
+ mAdapters.get(AdapterHolder.WORK).mWidgetsRecyclerView,
+ contentHorizontalMarginInPx);
}
- setContentViewChildHorizontalMargin(
+ setContentViewChildHorizontalPadding(
mAdapters.get(AdapterHolder.SEARCH).mWidgetsRecyclerView,
contentHorizontalMarginInPx);
}
@@ -352,6 +356,11 @@
layoutParams.setMarginEnd(horizontalMarginInPx);
}
+ private static void setContentViewChildHorizontalPadding(View view, int horizontalPaddingInPx) {
+ view.setPadding(horizontalPaddingInPx, view.getPaddingTop(), horizontalPaddingInPx,
+ view.getPaddingBottom());
+ }
+
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
doMeasure(widthMeasureSpec, heightMeasureSpec);
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index cd0c7f2..1a6ce8c 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -153,6 +153,8 @@
public static String dumpHprofData() {
String result;
if (sDumpWasGenerated) {
+ Log.d("b/195319692", "dump has already been generated by another test",
+ new Exception());
result = "dump has already been generated by another test";
} else {
try {
@@ -167,6 +169,7 @@
"am dumpheap " + device.getLauncherPackageName() + " " + fileName);
}
sDumpWasGenerated = true;
+ Log.d("b/195319692", "sDumpWasGenerated := true", new Exception());
result = "memory dump filename: " + fileName;
} catch (Throwable e) {
Log.e(TAG, "dumpHprofData failed", e);