Merge "Clean up IllegalStateException for page pairing" into sc-v2-dev
diff --git a/quickstep/res/layout/activity_allset.xml b/quickstep/res/layout/activity_allset.xml
index 4fbb8a0..b4ee482 100644
--- a/quickstep/res/layout/activity_allset.xml
+++ b/quickstep/res/layout/activity_allset.xml
@@ -14,81 +14,93 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<FrameLayout
+ 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"
- android:paddingEnd="@dimen/allset_page_margin_horizontal"
- android:layoutDirection="locale"
- android:textDirection="locale">
+ android:id="@+id/root_view"
+ android:background="@color/all_set_page_background" >
- <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"
+ <androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/allset_title_margin_top"
- app:layout_constraintTop_toBottomOf="@id/icon"
- app:layout_constraintStart_toStartOf="parent"
- android:gravity="start"
- android:text="@string/allset_title"/>
+ android:layout_height="match_parent"
+ android:layout_marginStart="@dimen/allset_page_margin_horizontal"
+ android:layout_marginEnd="@dimen/allset_page_margin_horizontal"
+ android:layoutDirection="locale"
+ android:textDirection="locale"
+ android:id="@+id/content_view"
+ android:forceHasOverlappingRendering="false"
+ android:fitsSystemWindows="true" >
- <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"/>
+ <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"/>
- <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/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"
+ app:layout_constraintTop_toBottomOf="@id/icon"
+ app:layout_constraintStart_toStartOf="parent"
+ android:gravity="start"
+ android:text="@string/allset_title"/>
- <TextView
- android:id="@+id/navigation_settings"
- style="@style/TextAppearance.GestureTutorial.LinkText"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- 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" />
+ <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"/>
- <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" />
+ <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/hint"
- style="@style/TextAppearance.GestureTutorial.Feedback.Subtitle"
- android:textSize="14sp"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintBottom_toBottomOf="@id/hint_guideline_bottom"
- android:text="@string/allset_hint"/>
-</androidx.constraintlayout.widget.ConstraintLayout>
+ <TextView
+ android:id="@+id/navigation_settings"
+ style="@style/TextAppearance.GestureTutorial.LinkText"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ 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"
+ style="@style/TextAppearance.GestureTutorial.Feedback.Subtitle"
+ android:textSize="14sp"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintBottom_toBottomOf="@id/hint_guideline_bottom"
+ android:text="@string/allset_hint"/>
+ </androidx.constraintlayout.widget.ConstraintLayout>
+
+</FrameLayout>
\ No newline at end of file
diff --git a/quickstep/res/layout/fallback_recents_activity.xml b/quickstep/res/layout/fallback_recents_activity.xml
index a43296f..bfeb82d 100644
--- a/quickstep/res/layout/fallback_recents_activity.xml
+++ b/quickstep/res/layout/fallback_recents_activity.xml
@@ -45,8 +45,7 @@
android:layout_height="match_parent"
android:clipChildren="false"
android:clipToPadding="false"
- android:outlineProvider="none"
- android:theme="@style/HomeScreenElementTheme" />
+ android:outlineProvider="none" />
<include
android:id="@+id/overview_actions_view"
diff --git a/quickstep/res/values-night/colors.xml b/quickstep/res/values-night/colors.xml
index c3b2536..af6e064 100644
--- a/quickstep/res/values-night/colors.xml
+++ b/quickstep/res/values-night/colors.xml
@@ -22,4 +22,6 @@
<color name="mock_webpage_url_bar">#202124</color>
<color name="mock_webpage_url_bar_item">#3c4043</color>
+ <color name="all_set_page_background">#FF000000</color>
+
</resources>
\ No newline at end of file
diff --git a/quickstep/res/values-night/styles.xml b/quickstep/res/values-night/styles.xml
index 1bd3f5d..e6b3450 100644
--- a/quickstep/res/values-night/styles.xml
+++ b/quickstep/res/values-night/styles.xml
@@ -21,7 +21,7 @@
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:enforceNavigationBarContrast">false</item>
<item name="android:windowLightStatusBar">false</item>
- <item name="android:windowBackground">#FF000000</item>
+ <item name="android:windowBackground">@android:color/transparent</item>
</style>
</resources>
\ No newline at end of file
diff --git a/quickstep/res/values/colors.xml b/quickstep/res/values/colors.xml
index 5edcc9d..1bddb57 100644
--- a/quickstep/res/values/colors.xml
+++ b/quickstep/res/values/colors.xml
@@ -72,4 +72,7 @@
<color name="mock_webpage_top_bar">#e8eaed</color>
<color name="mock_webpage_top_bar_item">#80868b</color>
<color name="mock_webpage_page_text">#bdc1c6</color>
+
+ <color name="all_set_page_background">#FFFFFFFF</color>
+
</resources>
\ No newline at end of file
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index e08eda8..fa21b0a 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -161,6 +161,7 @@
<dimen name="allset_title_icon_margin_top">32dp</dimen>
<dimen name="allset_subtitle_margin_top">24dp</dimen>
<dimen name="allset_subtitle_width_max">348dp</dimen>
+ <dimen name="allset_swipe_up_shift">10dp</dimen>
<!-- All Apps Education tutorial -->
<dimen name="swipe_edu_padding">8dp</dimen>
diff --git a/quickstep/res/values/styles.xml b/quickstep/res/values/styles.xml
index b5444b5..40e18ec 100644
--- a/quickstep/res/values/styles.xml
+++ b/quickstep/res/values/styles.xml
@@ -115,7 +115,7 @@
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:enforceNavigationBarContrast">false</item>
<item name="android:windowLightStatusBar">true</item>
- <item name="android:windowBackground">#FFFFFFFF</item>
+ <item name="android:windowBackground">@android:color/transparent</item>
</style>
<!--
diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
index e8ea671..6e2d2a9 100644
--- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
@@ -57,7 +57,6 @@
import com.android.launcher3.statemanager.StateManager.StateHandler;
import com.android.launcher3.taskbar.LauncherTaskbarUIController;
import com.android.launcher3.taskbar.TaskbarManager;
-import com.android.launcher3.taskbar.TaskbarStateHandler;
import com.android.launcher3.uioverrides.RecentsViewStateController;
import com.android.launcher3.util.ActivityOptionsWrapper;
import com.android.launcher3.util.DisplayController;
@@ -115,8 +114,6 @@
private @Nullable OverviewCommandHelper mOverviewCommandHelper;
private @Nullable LauncherTaskbarUIController mTaskbarUIController;
- private final TaskbarStateHandler mTaskbarStateHandler = new TaskbarStateHandler(this);
-
// Will be updated when dragging from taskbar.
private @Nullable DragOptions mNextWorkspaceDragOptions = null;
@@ -368,17 +365,12 @@
out.add(getDepthController());
out.add(new RecentsViewStateController(this));
out.add(new BackButtonAlphaHandler(this));
- out.add(getTaskbarStateHandler());
}
public DepthController getDepthController() {
return mDepthController;
}
- public TaskbarStateHandler getTaskbarStateHandler() {
- return mTaskbarStateHandler;
- }
-
@Nullable
public UnfoldTransitionProgressProvider getUnfoldTransitionProgressProvider() {
return mUnfoldTransitionProgressProvider;
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index ddb20a1..8a05533 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -439,9 +439,9 @@
4 - rotationChange);
}
}
- // TODO(b/196637509): don't do this for immersive apps.
if (mDeviceProfile.isTaskbarPresentInApps) {
- bounds.bottom -= mDeviceProfile.taskbarSize;
+ // Animate to above the taskbar.
+ bounds.bottom -= target.contentInsets.bottom;
}
return bounds;
}
diff --git a/quickstep/src/com/android/launcher3/model/WidgetsPredictionUpdateTask.java b/quickstep/src/com/android/launcher3/model/WidgetsPredictionUpdateTask.java
index 3d891e8..4be83dc 100644
--- a/quickstep/src/com/android/launcher3/model/WidgetsPredictionUpdateTask.java
+++ b/quickstep/src/com/android/launcher3/model/WidgetsPredictionUpdateTask.java
@@ -83,7 +83,7 @@
}
} else {
Map<ComponentKey, WidgetItem> widgetItems =
- allWidgets.values().stream().flatMap(List::stream)
+ allWidgets.values().stream().flatMap(List::stream).distinct()
.collect(Collectors.toMap(widget -> (ComponentKey) widget,
widget -> widget));
for (AppTarget app : mTargets) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index f206252..648a16e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -21,14 +21,20 @@
import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_STASHED_LAUNCHER_STATE;
import static com.android.launcher3.taskbar.TaskbarStashController.TASKBAR_STASH_DURATION;
import static com.android.launcher3.taskbar.TaskbarViewController.ALPHA_INDEX_HOME;
+import static com.android.systemui.shared.system.WindowManagerWrapper.ITYPE_EXTRA_NAVIGATION_BAR;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
+import android.annotation.ColorInt;
import android.graphics.Rect;
+import android.os.RemoteException;
+import android.util.Log;
import android.view.MotionEvent;
+import android.view.TaskTransitionSpec;
import android.view.View;
+import android.view.WindowManagerGlobal;
import androidx.annotation.NonNull;
@@ -36,6 +42,7 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.LauncherState;
import com.android.launcher3.QuickstepTransitionManager;
+import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatorListeners;
import com.android.launcher3.anim.PendingAnimation;
@@ -56,6 +63,7 @@
import com.android.systemui.shared.recents.model.ThumbnailData;
import java.util.Arrays;
+import java.util.Set;
import java.util.function.Supplier;
import java.util.stream.Stream;
@@ -64,6 +72,8 @@
*/
public class LauncherTaskbarUIController extends TaskbarUIController {
+ private static final String TAG = "TaskbarUIController";
+
private final BaseQuickstepLauncher mLauncher;
private final AnimatedFloat mIconAlignmentForResumedState =
@@ -193,6 +203,7 @@
mLauncher.getHotseat().setIconsAlpha(1f);
mLauncher.setTaskbarUIController(null);
mLauncher.removeOnDeviceProfileChangeListener(mProfileChangeListener);
+ updateTaskTransitionSpec(true);
}
@Override
@@ -367,6 +378,32 @@
private void onStashedInAppChanged(DeviceProfile deviceProfile) {
boolean taskbarStashedInApps = mControllers.taskbarStashController.isStashedInApp();
deviceProfile.isTaskbarPresentInApps = !taskbarStashedInApps;
+ updateTaskTransitionSpec(taskbarStashedInApps);
+ }
+
+ private void updateTaskTransitionSpec(boolean taskbarIsHidden) {
+ try {
+ if (taskbarIsHidden) {
+ // Clear custom task transition settings when the taskbar is stashed
+ WindowManagerGlobal.getWindowManagerService().clearTaskTransitionSpec();
+ } else {
+ // Adjust task transition spec to account for taskbar being visible
+ @ColorInt int taskAnimationBackgroundColor =
+ mLauncher.getColor(R.color.taskbar_background);
+
+ TaskTransitionSpec customTaskAnimationSpec = new TaskTransitionSpec(
+ taskAnimationBackgroundColor,
+ Set.of(ITYPE_EXTRA_NAVIGATION_BAR)
+ );
+ WindowManagerGlobal.getWindowManagerService()
+ .setTaskTransitionSpec(customTaskAnimationSpec);
+ }
+ } catch (RemoteException e) {
+ // This shouldn't happen but if it does task animations won't look good until the
+ // taskbar stashing state is changed.
+ Log.e(TAG, "Failed to update task transition spec to account for new taskbar state",
+ e);
+ }
}
/**
diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
index b768d60..69804bd 100644
--- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
@@ -30,7 +30,9 @@
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_HOME_DISABLED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SHOWING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SWITCHER_SHOWING;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
import android.animation.ObjectAnimator;
import android.annotation.DrawableRes;
@@ -81,6 +83,7 @@
private static final int FLAG_DISABLE_HOME = 1 << 7;
private static final int FLAG_DISABLE_RECENTS = 1 << 8;
private static final int FLAG_DISABLE_BACK = 1 << 9;
+ private static final int FLAG_NOTIFICATION_SHADE_EXPANDED = 1 << 10;
private static final int MASK_IME_SWITCHER_VISIBLE = FLAG_SWITCHER_SUPPORTED | FLAG_IME_VISIBLE;
@@ -98,6 +101,8 @@
private final AnimatedFloat mTaskbarNavButtonTranslationY = new AnimatedFloat(
this::updateNavButtonTranslationY);
+ private final AnimatedFloat mNavButtonTranslationYMultiplier = new AnimatedFloat(
+ this::updateNavButtonTranslationY);
// Initialized in init.
private TaskbarControllers mControllers;
@@ -120,6 +125,7 @@
mControllers = controllers;
mNavButtonsView.getLayoutParams().height = mContext.getDeviceProfile().taskbarSize;
parseSystemUiFlags(sharedState.sysuiStateFlags);
+ mNavButtonTranslationYMultiplier.value = 1;
mA11yLongClickListener = view -> {
mControllers.navButtonController.onButtonClick(BUTTON_A11Y_LONG_CLICK);
@@ -149,6 +155,11 @@
.getKeyguardBgTaskbar(),
flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0, AnimatedFloat.VALUE, 1, 0));
+ // Make sure to remove nav bar buttons translation when notification shade is expanded.
+ mPropertyHolders.add(new StatePropertyHolder(mNavButtonTranslationYMultiplier,
+ flags -> (flags & FLAG_NOTIFICATION_SHADE_EXPANDED) != 0, AnimatedFloat.VALUE,
+ 0, 1));
+
// Force nav buttons (specifically back button) to be visible during setup wizard.
boolean isInSetup = !mContext.isUserSetupComplete();
if (isThreeButtonNav || isInSetup) {
@@ -176,12 +187,12 @@
}
}
- // Animate taskbar background when IME shows
+ // Animate taskbar background when any of these flags are enabled
+ int flagsToShowBg = FLAG_IME_VISIBLE | FLAG_ONLY_BACK_FOR_BOUNCER_VISIBLE
+ | FLAG_NOTIFICATION_SHADE_EXPANDED;
mPropertyHolders.add(new StatePropertyHolder(
mControllers.taskbarDragLayerController.getNavbarBackgroundAlpha(),
- flags -> (flags & FLAG_IME_VISIBLE) != 0 ||
- (flags & FLAG_ONLY_BACK_FOR_BOUNCER_VISIBLE) != 0,
- AnimatedFloat.VALUE, 1, 0));
+ flags -> (flags & flagsToShowBg) != 0, AnimatedFloat.VALUE, 1, 0));
// Rotation button
RotationButton rotationButton = new RotationButtonImpl(
@@ -258,6 +269,9 @@
boolean isHomeDisabled = (sysUiStateFlags & SYSUI_STATE_HOME_DISABLED) != 0;
boolean isRecentsDisabled = (sysUiStateFlags & SYSUI_STATE_OVERVIEW_DISABLED) != 0;
boolean isBackDisabled = (sysUiStateFlags & SYSUI_STATE_BACK_DISABLED) != 0;
+ int shadeExpandedFlags = SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED
+ | SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
+ boolean isNotificationShadeExpanded = (sysUiStateFlags & shadeExpandedFlags) != 0;
// TODO(b/202218289) we're getting IME as not visible on lockscreen from system
updateStateForFlag(FLAG_IME_VISIBLE, isImeVisible);
@@ -266,6 +280,7 @@
updateStateForFlag(FLAG_DISABLE_HOME, isHomeDisabled);
updateStateForFlag(FLAG_DISABLE_RECENTS, isRecentsDisabled);
updateStateForFlag(FLAG_DISABLE_BACK, isBackDisabled);
+ updateStateForFlag(FLAG_NOTIFICATION_SHADE_EXPANDED, isNotificationShadeExpanded);
if (mA11yButton != null) {
// Only used in 3 button
@@ -360,7 +375,8 @@
}
private void updateNavButtonTranslationY() {
- mNavButtonsView.setTranslationY(mTaskbarNavButtonTranslationY.value);
+ mNavButtonsView.setTranslationY(mTaskbarNavButtonTranslationY.value
+ * mNavButtonTranslationYMultiplier.value);
}
private ImageView addButton(@DrawableRes int drawableId, @TaskbarButton int buttonType,
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 370496a..8ae661f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -25,6 +25,7 @@
import static com.android.systemui.shared.system.WindowManagerWrapper.ITYPE_BOTTOM_TAPPABLE_ELEMENT;
import static com.android.systemui.shared.system.WindowManagerWrapper.ITYPE_EXTRA_NAVIGATION_BAR;
+import android.animation.AnimatorSet;
import android.app.ActivityOptions;
import android.content.ActivityNotFoundException;
import android.content.Context;
@@ -328,10 +329,9 @@
mControllers.navbarButtonsViewController.updateStateForSysuiFlags(systemUiStateFlags);
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);
+ int shadeExpandedFlags = SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED
+ | SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
+ onNotificationShadeExpandChanged((systemUiStateFlags & shadeExpandedFlags) != 0);
mControllers.taskbarViewController.setRecentsButtonDisabled(
mControllers.navbarButtonsViewController.isRecentsDisabled());
mControllers.stashedHandleViewController.setIsHomeButtonDisabled(
@@ -341,6 +341,21 @@
mControllers.taskbarScrimViewController.updateStateForSysuiFlags(systemUiStateFlags);
}
+ /**
+ * Hides the taskbar icons and background when the notication shade is expanded.
+ */
+ private void onNotificationShadeExpandChanged(boolean isExpanded) {
+ float alpha = isExpanded ? 0 : 1;
+ AnimatorSet anim = new AnimatorSet();
+ anim.play(mControllers.taskbarViewController.getTaskbarIconAlpha().getProperty(
+ TaskbarViewController.ALPHA_INDEX_NOTIFICATION_EXPANDED).animateToValue(alpha));
+ if (!isThreeButtonNav()) {
+ anim.play(mControllers.taskbarDragLayerController.getNotificationShadeBgTaskbar()
+ .animateToValue(alpha));
+ }
+ anim.start();
+ }
+
public void onRotationProposal(int rotation, boolean isValid) {
mControllers.rotationButtonController.onRotationProposal(rotation, isValid);
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
index 05b0a11..cec892f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
@@ -42,6 +42,8 @@
private final AnimatedFloat mBgTaskbar = new AnimatedFloat(this::updateBackgroundAlpha);
private final AnimatedFloat mBgNavbar = new AnimatedFloat(this::updateBackgroundAlpha);
private final AnimatedFloat mKeyguardBgTaskbar = new AnimatedFloat(this::updateBackgroundAlpha);
+ private final AnimatedFloat mNotificationShadeBgTaskbar = new AnimatedFloat(
+ this::updateBackgroundAlpha);
// Used to hide our background color when someone else (e.g. ScrimView) is handling it.
private final AnimatedFloat mBgOverride = new AnimatedFloat(this::updateBackgroundAlpha);
@@ -65,6 +67,7 @@
mBgTaskbar.value = 1;
mKeyguardBgTaskbar.value = 1;
+ mNotificationShadeBgTaskbar.value = 1;
mBgOverride.value = 1;
updateBackgroundAlpha();
}
@@ -95,6 +98,10 @@
return mKeyguardBgTaskbar;
}
+ public AnimatedFloat getNotificationShadeBgTaskbar() {
+ return mNotificationShadeBgTaskbar;
+ }
+
public AnimatedFloat getOverrideBackgroundAlpha() {
return mBgOverride;
}
@@ -105,7 +112,8 @@
private void updateBackgroundAlpha() {
final float bgNavbar = mBgNavbar.value;
- final float bgTaskbar = mBgTaskbar.value * mKeyguardBgTaskbar.value;
+ final float bgTaskbar = mBgTaskbar.value * mKeyguardBgTaskbar.value
+ * mNotificationShadeBgTaskbar.value;
mTaskbarDragLayer.setTaskbarBackgroundAlpha(
mBgOverride.value * Math.max(bgNavbar, bgTaskbar)
);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStateHandler.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStateHandler.java
deleted file mode 100644
index edd2a22..0000000
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStateHandler.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * 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.taskbar;
-
-import static com.android.launcher3.LauncherState.TASKBAR;
-import static com.android.launcher3.anim.Interpolators.LINEAR;
-
-import com.android.launcher3.BaseQuickstepLauncher;
-import com.android.launcher3.LauncherState;
-import com.android.launcher3.anim.PendingAnimation;
-import com.android.launcher3.anim.PropertySetter;
-import com.android.launcher3.statemanager.StateManager;
-import com.android.launcher3.states.StateAnimationConfig;
-import com.android.quickstep.AnimatedFloat;
-import com.android.quickstep.SystemUiProxy;
-
-/**
- * StateHandler to animate Taskbar according to Launcher's state machine.
- */
-public class TaskbarStateHandler implements StateManager.StateHandler<LauncherState> {
-
- private final BaseQuickstepLauncher mLauncher;
-
- private AnimatedFloat mNavbarButtonAlpha = new AnimatedFloat(this::updateNavbarButtonAlpha);
-
- public TaskbarStateHandler(BaseQuickstepLauncher launcher) {
- mLauncher = launcher;
- }
-
- @Override
- public void setState(LauncherState state) {
- setState(state, PropertySetter.NO_ANIM_PROPERTY_SETTER);
- // Force update the alpha in case it was not initialized properly
- updateNavbarButtonAlpha();
- }
-
- @Override
- public void setStateWithAnimation(LauncherState toState, StateAnimationConfig config,
- PendingAnimation animation) {
- setState(toState, animation);
- }
-
- /**
- * Sets the provided state
- */
- public void setState(LauncherState toState, PropertySetter setter) {
- boolean isTaskbarVisible = (toState.getVisibleElements(mLauncher) & TASKBAR) != 0;
- // Make the nav bar visible in states that taskbar isn't visible.
- // TODO: We should draw our own handle instead of showing the nav bar.
- float navbarButtonAlpha = isTaskbarVisible ? 0f : 1f;
- setter.setFloat(mNavbarButtonAlpha, AnimatedFloat.VALUE, navbarButtonAlpha, LINEAR);
- }
-
-
- private void updateNavbarButtonAlpha() {
- SystemUiProxy.INSTANCE.get(mLauncher).setNavBarButtonAlpha(mNavbarButtonAlpha.value, false);
- }
-}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index 08d2a06..09197c3 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -116,16 +116,6 @@
}
/**
- * 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/launcher3/uioverrides/states/SplitScreenSelectState.java b/quickstep/src/com/android/launcher3/uioverrides/states/SplitScreenSelectState.java
index d0d7f31..106375a 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/SplitScreenSelectState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/SplitScreenSelectState.java
@@ -44,7 +44,7 @@
public float getSplitSelectTranslation(Launcher launcher) {
RecentsView recentsView = launcher.getOverviewPanel();
int splitPosition = recentsView.getSplitPlaceholder().getActiveSplitStagePosition();
- if (!recentsView.shouldShiftThumbnailsForSplitSelect(splitPosition)) {
+ if (!recentsView.shouldShiftThumbnailsForSplitSelect()) {
return 0f;
}
PagedOrientationHandler orientationHandler = recentsView.getPagedOrientationHandler();
diff --git a/quickstep/src/com/android/quickstep/InputConsumer.java b/quickstep/src/com/android/quickstep/InputConsumer.java
index 3580ee5..0b09323 100644
--- a/quickstep/src/com/android/quickstep/InputConsumer.java
+++ b/quickstep/src/com/android/quickstep/InputConsumer.java
@@ -36,7 +36,7 @@
int TYPE_SCREEN_PINNED = 1 << 6;
int TYPE_OVERVIEW_WITHOUT_FOCUS = 1 << 7;
int TYPE_RESET_GESTURE = 1 << 8;
- int TYPE_OVERSCROLL = 1 << 9;
+ int TYPE_PROGRESS_DELEGATE = 1 << 9;
int TYPE_SYSUI_OVERLAY = 1 << 10;
int TYPE_ONE_HANDED = 1 << 11;
int TYPE_TASKBAR_STASH = 1 << 12;
@@ -51,7 +51,7 @@
"TYPE_SCREEN_PINNED", // 6
"TYPE_OVERVIEW_WITHOUT_FOCUS", // 7
"TYPE_RESET_GESTURE", // 8
- "TYPE_OVERSCROLL", // 9
+ "TYPE_PROGRESS_DELEGATE", // 9
"TYPE_SYSUI_OVERLAY", // 10
"TYPE_ONE_HANDED", // 11
"TYPE_TASKBAR_STASH", // 12
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 1516b7a..ecc4b2b 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -90,6 +90,7 @@
import com.android.quickstep.inputconsumers.OtherActivityInputConsumer;
import com.android.quickstep.inputconsumers.OverviewInputConsumer;
import com.android.quickstep.inputconsumers.OverviewWithoutFocusInputConsumer;
+import com.android.quickstep.inputconsumers.ProgressDelegateInputConsumer;
import com.android.quickstep.inputconsumers.ResetGestureInputConsumer;
import com.android.quickstep.inputconsumers.ScreenPinnedInputConsumer;
import com.android.quickstep.inputconsumers.SysUiOverlayInputConsumer;
@@ -119,6 +120,7 @@
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.LinkedList;
+import java.util.function.Function;
/**
* Service connected by system-UI for handling touch interaction.
@@ -298,6 +300,13 @@
public OverviewCommandHelper getOverviewCommandHelper() {
return mOverviewCommandHelper;
}
+
+ /**
+ * Sets a proxy to bypass swipe up behavior
+ */
+ public void setSwipeUpProxy(Function<GestureState, AnimatedFloat> proxy) {
+ mSwipeUpProxyProvider = proxy != null ? proxy : (i -> null);
+ }
}
private static boolean sConnected = false;
@@ -336,6 +345,7 @@
private DisplayManager mDisplayManager;
private TaskbarManager mTaskbarManager;
+ private Function<GestureState, AnimatedFloat> mSwipeUpProxyProvider = i -> null;
@Override
public void onCreate() {
@@ -653,6 +663,12 @@
private InputConsumer newConsumer(GestureState previousGestureState,
GestureState newGestureState, MotionEvent event) {
+ AnimatedFloat progressProxy = mSwipeUpProxyProvider.apply(mGestureState);
+ if (progressProxy != null) {
+ return new ProgressDelegateInputConsumer(this, mTaskAnimationManager,
+ mGestureState, mInputMonitorCompat, progressProxy);
+ }
+
boolean canStartSystemGesture = mDeviceState.canStartSystemGesture();
if (!mDeviceState.isUserUnlocked()) {
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
index 765480c..7e8b83e 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
@@ -202,6 +202,10 @@
@Override
public void onStateTransitionStart(RecentsState toState) {
+ if (toState == HOME) {
+ // Clean-up logic that occurs when recents is no longer in use/visible.
+ reset();
+ }
setOverviewStateEnabled(true);
setOverviewGridEnabled(toState.displayOverviewTasksAsGrid(mActivity.getDeviceProfile()));
setOverviewFullscreenEnabled(toState.isFullScreen());
@@ -210,10 +214,6 @@
@Override
public void onStateTransitionComplete(RecentsState finalState) {
- if (finalState == HOME) {
- // Clean-up logic that occurs when recents is no longer in use/visible.
- reset();
- }
setOverlayEnabled(finalState == DEFAULT || finalState == MODAL_TASK);
setFreezeViewVisibility(false);
}
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/ProgressDelegateInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/ProgressDelegateInputConsumer.java
new file mode 100644
index 0000000..c69b510
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/inputconsumers/ProgressDelegateInputConsumer.java
@@ -0,0 +1,194 @@
+/*
+ * 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.quickstep.inputconsumers;
+
+import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity;
+import static com.android.launcher3.touch.BaseSwipeDetector.calculateDuration;
+import static com.android.launcher3.touch.SingleAxisSwipeDetector.DIRECTION_POSITIVE;
+import static com.android.launcher3.touch.SingleAxisSwipeDetector.VERTICAL;
+import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
+import static com.android.quickstep.util.ActiveGestureLog.INTENT_EXTRA_LOG_TRACE_ID;
+
+import android.animation.ObjectAnimator;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Point;
+import android.view.MotionEvent;
+
+import com.android.launcher3.anim.AnimatorListeners;
+import com.android.launcher3.testing.TestLogging;
+import com.android.launcher3.testing.TestProtocol;
+import com.android.launcher3.touch.SingleAxisSwipeDetector;
+import com.android.launcher3.util.DisplayController;
+import com.android.quickstep.AnimatedFloat;
+import com.android.quickstep.GestureState;
+import com.android.quickstep.InputConsumer;
+import com.android.quickstep.MultiStateCallback;
+import com.android.quickstep.RecentsAnimationCallbacks;
+import com.android.quickstep.RecentsAnimationController;
+import com.android.quickstep.RecentsAnimationTargets;
+import com.android.quickstep.TaskAnimationManager;
+import com.android.systemui.shared.recents.model.ThumbnailData;
+import com.android.systemui.shared.system.InputMonitorCompat;
+
+/**
+ * Input consumer which delegates the swipe-progress handling
+ */
+public class ProgressDelegateInputConsumer implements InputConsumer,
+ RecentsAnimationCallbacks.RecentsAnimationListener,
+ SingleAxisSwipeDetector.Listener {
+
+ private static final float SWIPE_DISTANCE_THRESHOLD = 0.2f;
+
+ private static final String[] STATE_NAMES = DEBUG_STATES ? new String[3] : null;
+ private static int getFlagForIndex(int index, String name) {
+ if (DEBUG_STATES) {
+ STATE_NAMES[index] = name;
+ }
+ return 1 << index;
+ }
+
+ private static final int STATE_TARGET_RECEIVED =
+ getFlagForIndex(0, "STATE_TARGET_RECEIVED");
+ private static final int STATE_HANDLER_INVALIDATED =
+ getFlagForIndex(1, "STATE_HANDLER_INVALIDATED");
+ private static final int STATE_FLING_FINISHED =
+ getFlagForIndex(2, "STATE_FLING_FINISHED");
+
+ private final Context mContext;
+ private final TaskAnimationManager mTaskAnimationManager;
+ private final GestureState mGestureState;
+ private final InputMonitorCompat mInputMonitorCompat;
+ private final MultiStateCallback mStateCallback;
+
+ private final Point mDisplaySize;
+ private final SingleAxisSwipeDetector mSwipeDetector;
+
+ private final AnimatedFloat mProgress;
+
+ private boolean mDragStarted = false;
+
+ private RecentsAnimationController mRecentsAnimationController;
+ private Boolean mFlingEndsOnHome;
+
+ public ProgressDelegateInputConsumer(Context context,
+ TaskAnimationManager taskAnimationManager, GestureState gestureState,
+ InputMonitorCompat inputMonitorCompat, AnimatedFloat progress) {
+ mContext = context;
+ mTaskAnimationManager = taskAnimationManager;
+ mGestureState = gestureState;
+ mInputMonitorCompat = inputMonitorCompat;
+ mProgress = progress;
+
+ // Do not use DeviceProfile as the user data might be locked
+ mDisplaySize = DisplayController.INSTANCE.get(context).getInfo().currentSize;
+
+ // Init states
+ mStateCallback = new MultiStateCallback(STATE_NAMES);
+ mStateCallback.runOnceAtState(STATE_TARGET_RECEIVED | STATE_HANDLER_INVALIDATED,
+ this::endRemoteAnimation);
+ mStateCallback.runOnceAtState(STATE_TARGET_RECEIVED | STATE_FLING_FINISHED,
+ this::onFlingFinished);
+
+ mSwipeDetector = new SingleAxisSwipeDetector(mContext, this, VERTICAL);
+ mSwipeDetector.setDetectableScrollConditions(DIRECTION_POSITIVE, false);
+ }
+
+ @Override
+ public int getType() {
+ return TYPE_PROGRESS_DELEGATE;
+ }
+
+ @Override
+ public void onMotionEvent(MotionEvent ev) {
+ if (mFlingEndsOnHome == null) {
+ mSwipeDetector.onTouchEvent(ev);
+ }
+ }
+
+ @Override
+ public void onDragStart(boolean start, float startDisplacement) {
+ mDragStarted = true;
+ TestLogging.recordEvent(TestProtocol.SEQUENCE_PILFER, "pilferPointers");
+ mInputMonitorCompat.pilferPointers();
+ Intent intent = mGestureState.getHomeIntent()
+ .putExtra(INTENT_EXTRA_LOG_TRACE_ID, mGestureState.getGestureId());
+ mTaskAnimationManager.startRecentsAnimation(mGestureState, intent, this);
+ }
+
+ @Override
+ public boolean onDrag(float displacement) {
+ if (mDisplaySize.y > 0) {
+ mProgress.updateValue(displacement / -mDisplaySize.y);
+ }
+ return true;
+ }
+
+ @Override
+ public void onDragEnd(float velocity) {
+ final boolean willExit;
+ if (mSwipeDetector.isFling(velocity)) {
+ willExit = velocity < 0;
+ } else {
+ willExit = mProgress.value > SWIPE_DISTANCE_THRESHOLD;
+ }
+ float endValue = willExit ? 1 : 0;
+ long duration = calculateDuration(velocity, endValue - mProgress.value);
+ mFlingEndsOnHome = willExit;
+
+ ObjectAnimator anim = mProgress.animateToValue(endValue);
+ anim.setDuration(duration).setInterpolator(scrollInterpolatorForVelocity(velocity));
+ if (mRecentsAnimationController != null) {
+ anim.addListener(AnimatorListeners.forSuccessCallback(
+ () -> mStateCallback.setState(STATE_FLING_FINISHED)));
+ }
+ anim.start();
+ }
+
+ private void onFlingFinished() {
+ if (mRecentsAnimationController != null) {
+ boolean endToRecents = mFlingEndsOnHome == null ? true : mFlingEndsOnHome;
+ mRecentsAnimationController.finishController(endToRecents /* toRecents */,
+ null /* callback */, false /* sendUserLeaveHint */);
+ }
+ }
+
+ @Override
+ public void onRecentsAnimationStart(RecentsAnimationController controller,
+ RecentsAnimationTargets targets) {
+ mRecentsAnimationController = controller;
+ mStateCallback.setState(STATE_TARGET_RECEIVED);
+ }
+
+ @Override
+ public void onRecentsAnimationCanceled(ThumbnailData thumbnailData) {
+ mRecentsAnimationController = null;
+ }
+
+ private void endRemoteAnimation() {
+ onDragEnd(Float.MIN_VALUE);
+ }
+
+ @Override
+ public void onConsumerAboutToBeSwitched() {
+ mStateCallback.setState(STATE_HANDLER_INVALIDATED);
+ }
+
+ @Override
+ public boolean allowInterceptByParent() {
+ return !mDragStarted;
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
index f731cb3..272a9a1 100644
--- a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
+++ b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
@@ -15,10 +15,28 @@
*/
package com.android.quickstep.interaction;
+import static com.android.launcher3.Utilities.mapBoundToRange;
+import static com.android.launcher3.Utilities.mapRange;
+import static com.android.launcher3.anim.Interpolators.LINEAR;
+
import android.app.Activity;
+import android.app.ActivityManager.RunningTaskInfo;
+import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
+import android.graphics.Canvas;
import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.PointF;
+import android.graphics.RadialGradient;
+import android.graphics.Rect;
+import android.graphics.Shader.TileMode;
+import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
@@ -29,9 +47,12 @@
import android.widget.TextView;
import androidx.annotation.Nullable;
+import androidx.core.graphics.ColorUtils;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
+import com.android.quickstep.AnimatedFloat;
+import com.android.quickstep.GestureState;
import com.android.quickstep.TouchInteractionService.TISBinder;
import com.android.quickstep.util.TISBindHelper;
@@ -49,13 +70,23 @@
private static final String EXTRA_ACCENT_COLOR_DARK_MODE = "suwColorAccentDark";
private static final String EXTRA_ACCENT_COLOR_LIGHT_MODE = "suwColorAccentLight";
+ private static final float HINT_BOTTOM_FACTOR = 1 - .94f;
+
private TISBindHelper mTISBindHelper;
private TISBinder mBinder;
+ private final AnimatedFloat mSwipeProgress = new AnimatedFloat(this::onSwipeProgressUpdate);
+ private BgDrawable mBackground;
+ private View mContentView;
+ private float mSwipeUpShift;
+
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_allset);
+ findViewById(R.id.root_view).setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+ | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+ | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
int mode = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
boolean isDarkTheme = mode == Configuration.UI_MODE_NIGHT_YES;
@@ -65,6 +96,11 @@
((ImageView) findViewById(R.id.icon)).getDrawable().mutate().setTint(accentColor);
+ mBackground = new BgDrawable(this);
+ findViewById(R.id.root_view).setBackground(mBackground);
+ mContentView = findViewById(R.id.content_view);
+ mSwipeUpShift = getResources().getDimension(R.dimen.allset_swipe_up_shift);
+
TextView tv = findViewById(R.id.navigation_settings);
tv.setTextColor(accentColor);
tv.setOnClickListener(v -> {
@@ -86,19 +122,26 @@
super.onResume();
if (mBinder != null) {
mBinder.getTaskbarManager().setSetupUIVisible(true);
+ mBinder.setSwipeUpProxy(this::createSwipeUpProxy);
}
}
private void onTISConnected(TISBinder binder) {
mBinder = binder;
mBinder.getTaskbarManager().setSetupUIVisible(isResumed());
+ mBinder.setSwipeUpProxy(isResumed() ? this::createSwipeUpProxy : null);
}
@Override
protected void onPause() {
super.onPause();
+ clearBinderOverride();
+ }
+
+ private void clearBinderOverride() {
if (mBinder != null) {
mBinder.getTaskbarManager().setSetupUIVisible(false);
+ mBinder.setSwipeUpProxy(null);
}
}
@@ -106,6 +149,27 @@
protected void onDestroy() {
super.onDestroy();
mTISBindHelper.onDestroy();
+ clearBinderOverride();
+ }
+
+ private AnimatedFloat createSwipeUpProxy(GestureState state) {
+ if (!state.getHomeIntent().getComponent().getPackageName().equals(getPackageName())) {
+ return null;
+ }
+ RunningTaskInfo rti = state.getRunningTask();
+ if (rti == null || !rti.topActivity.equals(getComponentName())) {
+ return null;
+ }
+ mSwipeProgress.updateValue(0);
+ return mSwipeProgress;
+ }
+
+ private void onSwipeProgressUpdate() {
+ mBackground.setProgress(mSwipeProgress.value);
+ float alpha = Utilities.mapBoundToRange(mSwipeProgress.value, 0, HINT_BOTTOM_FACTOR,
+ 1, 0, LINEAR);
+ mContentView.setAlpha(alpha);
+ mContentView.setTranslationY((alpha - 1) * mSwipeUpShift);
}
/**
@@ -132,4 +196,79 @@
return super.performAccessibilityAction(host, action, args);
}
}
+
+ private static class BgDrawable extends Drawable {
+
+ private static final float START_SIZE_FACTOR = .5f;
+ private static final float END_SIZE_FACTOR = 2;
+ private static final float GRADIENT_END_PROGRESS = .5f;
+
+ private final Paint mPaint = new Paint();
+ private final RadialGradient mMaskGrad;
+ private final Matrix mMatrix = new Matrix();
+
+ private final ColorMatrix mColorMatrix = new ColorMatrix();
+ private final ColorMatrixColorFilter mColorFilter =
+ new ColorMatrixColorFilter(mColorMatrix);
+
+ private final int mColor;
+ private float mProgress = 0;
+
+ BgDrawable(Context context) {
+ mColor = context.getColor(R.color.all_set_page_background);
+ mMaskGrad = new RadialGradient(0, 0, 1,
+ new int[] {ColorUtils.setAlphaComponent(mColor, 0), mColor},
+ new float[]{0, 1}, TileMode.CLAMP);
+
+ mPaint.setShader(mMaskGrad);
+ mPaint.setColorFilter(mColorFilter);
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ if (mProgress <= 0) {
+ canvas.drawColor(mColor);
+ return;
+ }
+
+ // Update the progress to half the size only.
+ float progress = mapBoundToRange(mProgress,
+ 0, GRADIENT_END_PROGRESS, 0, 1, LINEAR);
+ Rect bounds = getBounds();
+ float x = bounds.exactCenterX();
+ float height = bounds.height();
+
+ float size = PointF.length(x, height);
+ float radius = size * mapRange(progress, START_SIZE_FACTOR, END_SIZE_FACTOR);
+ float y = mapRange(progress, height + radius , height / 2);
+ mMatrix.setTranslate(x, y);
+ mMatrix.postScale(radius, radius, x, y);
+ mMaskGrad.setLocalMatrix(mMatrix);
+
+ // Change the alpha-addition-component (index 19) so that every pixel is updated
+ // accordingly
+ mColorMatrix.getArray()[19] = mapBoundToRange(mProgress, 0, 1, 0, -255, LINEAR);
+ mColorFilter.setColorMatrix(mColorMatrix);
+
+ canvas.drawPaint(mPaint);
+ }
+
+ public void setProgress(float progress) {
+ if (mProgress != progress) {
+ mProgress = progress;
+ invalidateSelf();
+ }
+ }
+
+ @Override
+ public int getOpacity() {
+ return PixelFormat.TRANSLUCENT;
+ }
+
+ @Override
+ public void setAlpha(int i) { }
+
+ @Override
+ public void setColorFilter(ColorFilter colorFilter) { }
+ }
}
diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
index 5ca5c94..715d30e 100644
--- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -90,6 +90,10 @@
@Override
public void onStateTransitionStart(LauncherState toState) {
+ if (toState == NORMAL || toState == SPRING_LOADED) {
+ // Clean-up logic that occurs when recents is no longer in use/visible.
+ reset();
+ }
setOverviewStateEnabled(toState.overviewUi);
setOverviewGridEnabled(toState.displayOverviewTasksAsGrid(mActivity.getDeviceProfile()));
setOverviewFullscreenEnabled(toState.getOverviewFullscreenProgress() == 1);
@@ -98,10 +102,6 @@
@Override
public void onStateTransitionComplete(LauncherState finalState) {
- if (finalState == NORMAL || finalState == SPRING_LOADED) {
- // Clean-up logic that occurs when recents is no longer in use/visible.
- reset();
- }
setOverlayEnabled(finalState == OVERVIEW || finalState == OVERVIEW_MODAL_TASK);
setFreezeViewVisibility(false);
}
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index f7a9562..5a455c1 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -47,6 +47,8 @@
import static com.android.launcher3.touch.PagedOrientationHandler.CANVAS_TRANSLATE;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_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 static com.android.launcher3.util.SystemUiController.UI_STATE_FULLSCREEN_TASK;
import static com.android.quickstep.TaskUtils.checkCurrentOrManagedUserId;
import static com.android.quickstep.views.ClearAllButton.DISMISS_ALPHA;
@@ -1012,11 +1014,6 @@
}
}
- private boolean isLastGridTaskVisible() {
- TaskView lastTaskView = getLastGridTaskView();
- return lastTaskView != null && lastTaskView.isVisibleToUser();
- }
-
private TaskView getLastGridTaskView() {
IntArray topRowIdArray = getTopRowIdArray();
IntArray bottomRowIdArray = getBottomRowIdArray();
@@ -1898,6 +1895,7 @@
public void reset() {
setCurrentTask(-1);
+ mCurrentPageScrollDiff = 0;
mIgnoreResetTaskId = -1;
mTaskListChangeId = -1;
mFocusedTaskViewId = -1;
@@ -2756,7 +2754,13 @@
float dismissTranslationInterpolationEnd = 1;
boolean closeGapBetweenClearAll = false;
boolean isClearAllHidden = isClearAllHidden();
- if (showAsGrid && isLastGridTaskVisible()) {
+ boolean snapToLastTask = false;
+ boolean isLandscapeSplit =
+ mActivity.getDeviceProfile().isLandscape && isSplitSelectionActive();
+ boolean isSplitPlaceholderFirstInGrid = isSplitPlaceholderFirstInGrid();
+ boolean isSplitPlaceholderLastInGrid = isSplitPlaceholderLastInGrid();
+ TaskView lastGridTaskView = showAsGrid ? getLastGridTaskView() : null;
+ if (lastGridTaskView != null && lastGridTaskView.isVisibleToUser()) {
// After dismissal, animate translation of the remaining tasks to fill any gap left
// between the end of the grid and the clear all button. Only animate if the clear
// all button is visible or would become visible after dismissal.
@@ -2782,13 +2786,29 @@
longGridRowWidthDiff += mIsRtl ? -gapWidth : gapWidth;
if (isClearAllHidden) {
// If ClearAllButton isn't fully shown, snap to the last task.
- longGridRowWidthDiff += getSnapToLastTaskScrollDiff();
+ snapToLastTask = true;
}
} else {
// If only focused task will be left, snap to focused task instead.
longGridRowWidthDiff += getSnapToFocusedTaskScrollDiff(isClearAllHidden);
}
}
+ if (mClearAllButton.getAlpha() != 0f && isLandscapeSplit) {
+ // ClearAllButton will not be available in split select, snap to last task instead.
+ snapToLastTask = true;
+ }
+ if (snapToLastTask) {
+ longGridRowWidthDiff += getSnapToLastTaskScrollDiff();
+ if (isSplitPlaceholderLastInGrid) {
+ // Shift all the tasks to make space for split placeholder.
+ longGridRowWidthDiff += mIsRtl ? mSplitPlaceholderSize : -mSplitPlaceholderSize;
+ }
+ } else if (isLandscapeSplit && getScrollForPage(mCurrentPage)
+ == getScrollForPage(indexOfChild(lastGridTaskView))) {
+ // Use last task as reference point for scroll diff and snapping calculation as it's
+ // the only invariant point in landscape split screen.
+ snapToLastTask = true;
+ }
// If we need to animate the grid to compensate the clear all gap, we split the second
// half of the dismiss pending animation (in which the non-dismissed tasks slide into
@@ -2945,6 +2965,20 @@
} else {
float primaryTranslation =
nextFocusedTaskView != null ? nextFocusedTaskWidth : dismissedTaskWidth;
+ if (isFocusedTaskDismissed && nextFocusedTaskView == null) {
+ // Moves less if focused task is not in scroll position.
+ int focusedTaskScroll = getScrollForPage(dismissedIndex);
+ int primaryScroll = mOrientationHandler.getPrimaryScroll(this);
+ int focusedTaskScrollDiff = primaryScroll - focusedTaskScroll;
+ primaryTranslation +=
+ mIsRtl ? focusedTaskScrollDiff : -focusedTaskScrollDiff;
+ if (isSplitPlaceholderFirstInGrid) {
+ // Moves less if split placeholder is at the start.
+ primaryTranslation +=
+ mIsRtl ? -mSplitPlaceholderSize : mSplitPlaceholderSize;
+ }
+ }
+
anim.setFloat(taskView, taskView.getPrimaryDismissTranslationProperty(),
mIsRtl ? primaryTranslation : -primaryTranslation,
clampToProgress(LINEAR, animationStartProgress,
@@ -2965,6 +2999,8 @@
mPendingAnimation = anim;
final TaskView finalNextFocusedTaskView = nextFocusedTaskView;
final boolean finalCloseGapBetweenClearAll = closeGapBetweenClearAll;
+ final boolean finalSnapToLastTask = snapToLastTask;
+ final boolean finalIsFocusedTaskDismissed = isFocusedTaskDismissed;
mPendingAnimation.addEndListener(new Consumer<Boolean>() {
@Override
public void accept(Boolean success) {
@@ -3004,14 +3040,11 @@
int taskViewIdToSnapTo = -1;
if (showAsGrid) {
if (finalCloseGapBetweenClearAll) {
- if (taskCount > 2) {
+ if (finalSnapToLastTask) {
+ // Last task will be determined after removing dismissed task.
+ pageToSnapTo = -1;
+ } else if (taskCount > 2) {
pageToSnapTo = indexOfChild(mClearAllButton);
- if (isClearAllHidden) {
- int clearAllWidth = mOrientationHandler.getPrimarySize(
- mClearAllButton);
- mCurrentPageScrollDiff =
- isRtl() ? clearAllWidth : -clearAllWidth;
- }
} else if (isClearAllHidden) {
// Snap to focused task if clear all is hidden.
pageToSnapTo = 0;
@@ -3021,13 +3054,19 @@
// page's relative position as the order of indices change over time due
// to dismissals.
TaskView snappedTaskView = getTaskViewAt(mCurrentPage);
- if (snappedTaskView != null) {
+ boolean calculateScrollDiff = true;
+ if (snappedTaskView != null && !finalSnapToLastTask) {
if (snappedTaskView.getTaskViewId() == mFocusedTaskViewId) {
if (finalNextFocusedTaskView != null) {
taskViewIdToSnapTo =
finalNextFocusedTaskView.getTaskViewId();
- } else {
+ } else if (dismissedTaskViewId != mFocusedTaskViewId) {
taskViewIdToSnapTo = mFocusedTaskViewId;
+ } else {
+ // Won't focus next task in split select, so snap to the
+ // first task.
+ pageToSnapTo = 0;
+ calculateScrollDiff = false;
}
} else {
int snappedTaskViewId = snappedTaskView.getTaskViewId();
@@ -3059,10 +3098,20 @@
}
}
- int primaryScroll = mOrientationHandler.getPrimaryScroll(
- RecentsView.this);
- int currentPageScroll = getScrollForPage(pageToSnapTo);
- mCurrentPageScrollDiff = primaryScroll - currentPageScroll;
+ if (calculateScrollDiff) {
+ int primaryScroll = mOrientationHandler.getPrimaryScroll(
+ RecentsView.this);
+ int currentPageScroll = getScrollForPage(mCurrentPage);
+ mCurrentPageScrollDiff = primaryScroll - currentPageScroll;
+ // Compensate for coordinate shift by split placeholder.
+ if (isSplitPlaceholderFirstInGrid && !finalSnapToLastTask) {
+ mCurrentPageScrollDiff +=
+ mIsRtl ? -mSplitPlaceholderSize : mSplitPlaceholderSize;
+ } else if (isSplitPlaceholderLastInGrid && finalSnapToLastTask) {
+ mCurrentPageScrollDiff +=
+ mIsRtl ? mSplitPlaceholderSize : -mSplitPlaceholderSize;
+ }
+ }
}
} else if (dismissedIndex < pageToSnapTo || pageToSnapTo == taskCount - 1) {
pageToSnapTo--;
@@ -3075,10 +3124,14 @@
startHome();
} else {
// Update focus task and its size.
- if (finalNextFocusedTaskView != null) {
- mFocusedTaskViewId = finalNextFocusedTaskView.getTaskViewId();
- mTopRowIdSet.remove(mFocusedTaskViewId);
- finalNextFocusedTaskView.animateIconScaleAndDimIntoView();
+ if (finalIsFocusedTaskDismissed) {
+ if (finalNextFocusedTaskView != null) {
+ mFocusedTaskViewId = finalNextFocusedTaskView.getTaskViewId();
+ mTopRowIdSet.remove(mFocusedTaskViewId);
+ finalNextFocusedTaskView.animateIconScaleAndDimIntoView();
+ } else {
+ mFocusedTaskViewId = -1;
+ }
}
updateTaskSize(/*isTaskDismissal=*/ true);
updateChildTaskOrientations();
@@ -3091,7 +3144,7 @@
if (highestVisibleTaskIndex < Integer.MAX_VALUE) {
TaskView taskView = getTaskViewAt(highestVisibleTaskIndex);
- boolean shouldRebalance = false;
+ boolean shouldRebalance;
int screenStart = mOrientationHandler.getPrimaryScroll(
RecentsView.this);
int taskStart = mOrientationHandler.getChildStart(taskView)
@@ -3122,9 +3175,12 @@
}
}
- // If snapping to another page due to indices rearranging, find the new
- // index after dismissal & rearrange using the task view id.
- if (taskViewIdToSnapTo != -1) {
+ if (finalSnapToLastTask) {
+ // If snapping to last task, find the last task after dismissal.
+ pageToSnapTo = indexOfChild(getLastGridTaskView());
+ } else if (taskViewIdToSnapTo != -1) {
+ // If snapping to another page due to indices rearranging, find
+ // the new index after dismissal & rearrange using the task view id.
pageToSnapTo = indexOfChild(
getTaskViewFromTaskViewId(taskViewIdToSnapTo));
}
@@ -3243,43 +3299,11 @@
}
/**
- * @return {@code true} if one of the task thumbnails would intersect/overlap with the
- * {@link #mFirstFloatingTaskView}
+ * Returns {@code true} if one of the task thumbnails would intersect/overlap with the
+ * {@link #mFirstFloatingTaskView}.
*/
- public boolean shouldShiftThumbnailsForSplitSelect(@StagePosition int stagePosition) {
- if (!mActivity.getDeviceProfile().isTablet) {
- // Never enough space on phones
- return true;
- } else if (!mActivity.getDeviceProfile().isLandscape) {
- return true;
- }
-
- Rect splitBounds = new Rect();
- // This acts as a best approximation on where the splitplaceholder view would be,
- // doesn't need to be exact necessarily. This also doesn't need to take translations
- // into account since placeholder view is not translated
- if (stagePosition == SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT) {
- splitBounds.set(getWidth() - mSplitPlaceholderSize, 0, getWidth(), getHeight());
- } else {
- splitBounds.set(0, 0, mSplitPlaceholderSize, getHeight());
- }
- Rect taskBounds = new Rect();
- int taskCount = getTaskViewCount();
- for (int i = 0; i < taskCount; i++) {
- TaskView taskView = getTaskViewAt(i);
- if (taskView == mSplitHiddenTaskView
- && !(showAsGrid() && taskView == getFocusedTaskView())) {
- // Case where the hidden task view would have overlapped w/ placeholder,
- // but because it's going to hide we don't care
- // TODO (b/187312247) edge case for thumbnails that are off screen but scroll on
- continue;
- }
- taskView.getBoundsOnScreen(taskBounds);
- if (Rect.intersects(taskBounds, splitBounds)) {
- return true;
- }
- }
- return false;
+ public boolean shouldShiftThumbnailsForSplitSelect() {
+ return !mActivity.getDeviceProfile().isTablet;
}
protected void onDismissAnimationEnds() {
@@ -3771,37 +3795,44 @@
* Apply scroll offset to children of RecentsView when entering split select.
*/
public void applySplitPrimaryScrollOffset() {
- if (!mActivity.getDeviceProfile().isLandscape || !showAsGrid()) {
- return;
- }
-
- @StagePosition int position = mSplitSelectStateController.getActiveSplitStagePosition();
- boolean shouldShiftThumbnailsForSplitSelect = shouldShiftThumbnailsForSplitSelect(
- position);
- boolean expandLeft = false;
- boolean expandRight = false;
- if (mIsRtl) {
- if (position == SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT
- && shouldShiftThumbnailsForSplitSelect) {
- expandLeft = true;
- } else if (position == SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT) {
- if (shouldShiftThumbnailsForSplitSelect) {
- expandRight = true;
- } else {
- expandLeft = true;
- }
- }
- } // TODO(b/200537659): Handle system RTL.
- if (expandRight) {
+ if (isSplitPlaceholderFirstInGrid()) {
for (int i = 0; i < getTaskViewCount(); i++) {
getTaskViewAt(i).setSplitScrollOffsetPrimary(mSplitPlaceholderSize);
}
- } else if (expandLeft) {
+ } else if (isSplitPlaceholderLastInGrid()) {
mClearAllButton.setSplitSelectScrollOffsetPrimary(-mSplitPlaceholderSize);
}
}
/**
+ * Returns if split placeholder is at the beginning of RecentsView. Always returns {@code false}
+ * if RecentsView is in portrait or RecentsView isn't shown as grid.
+ */
+ private boolean isSplitPlaceholderFirstInGrid() {
+ if (!mActivity.getDeviceProfile().isLandscape || !showAsGrid()) {
+ return false;
+ }
+ @StagePosition int position = mSplitSelectStateController.getActiveSplitStagePosition();
+ return mIsRtl
+ ? position == STAGE_POSITION_BOTTOM_OR_RIGHT
+ : position == STAGE_POSITION_TOP_OR_LEFT;
+ }
+
+ /**
+ * Returns if split placeholder is at the end of RecentsView. Always returns {@code false} if
+ * RecentsView is in portrait or RecentsView isn't shown as grid.
+ */
+ private boolean isSplitPlaceholderLastInGrid() {
+ if (!mActivity.getDeviceProfile().isLandscape || !showAsGrid()) {
+ return false;
+ }
+ @StagePosition int position = mSplitSelectStateController.getActiveSplitStagePosition();
+ return mIsRtl
+ ? position == STAGE_POSITION_TOP_OR_LEFT
+ : position == STAGE_POSITION_BOTTOM_OR_RIGHT;
+ }
+
+ /**
* Reset scroll offset on children of RecentsView when exiting split select.
*/
public void resetSplitPrimaryScrollOffset() {
@@ -4431,36 +4462,34 @@
@Override
protected int computeMinScroll() {
- if (getTaskViewCount() > 0) {
- if (mIsRtl) {
- // If we aren't showing the clear all button, use the rightmost task as the min
- // scroll.
- return getScrollForPage(mDisallowScrollToClearAll ? indexOfChild(
- getTaskViewAt(getTaskViewCount() - 1)) : indexOfChild(mClearAllButton));
- } else {
- TaskView focusedTaskView = mShowAsGridLastOnLayout ? getFocusedTaskView() : null;
- return getScrollForPage(focusedTaskView != null ? indexOfChild(focusedTaskView)
- : 0);
- }
+ if (getTaskViewCount() <= 0) {
+ return super.computeMinScroll();
}
- return super.computeMinScroll();
+
+ return getScrollForPage(mIsRtl ? getLastViewIndex() : getFirstViewIndex());
}
@Override
protected int computeMaxScroll() {
- if (getTaskViewCount() > 0) {
- if (mIsRtl) {
- TaskView focusedTaskView = mShowAsGridLastOnLayout ? getFocusedTaskView() : null;
- return getScrollForPage(focusedTaskView != null ? indexOfChild(focusedTaskView)
- : 0);
- } else {
- // If we aren't showing the clear all button, use the leftmost task as the min
- // scroll.
- return getScrollForPage(mDisallowScrollToClearAll ? indexOfChild(
- getTaskViewAt(getTaskViewCount() - 1)) : indexOfChild(mClearAllButton));
- }
+ if (getTaskViewCount() <= 0) {
+ return super.computeMaxScroll();
}
- return super.computeMaxScroll();
+
+ return getScrollForPage(mIsRtl ? getFirstViewIndex() : getLastViewIndex());
+ }
+
+ private int getFirstViewIndex() {
+ return mShowAsGridLastOnLayout && mFocusedTaskViewId != -1
+ ? indexOfChild(getFocusedTaskView())
+ : 0;
+ }
+
+ private int getLastViewIndex() {
+ return mDisallowScrollToClearAll
+ ? mShowAsGridLastOnLayout
+ ? indexOfChild(getLastGridTaskView())
+ : getTaskViewCount() - 1
+ : indexOfChild(mClearAllButton);
}
/**
diff --git a/src/com/android/launcher3/ButtonDropTarget.java b/src/com/android/launcher3/ButtonDropTarget.java
index 477dcf8..38d5077 100644
--- a/src/com/android/launcher3/ButtonDropTarget.java
+++ b/src/com/android/launcher3/ButtonDropTarget.java
@@ -108,8 +108,8 @@
// We do not set the drawable in the xml as that inflates two drawables corresponding to
// drawableLeft and drawableStart.
mDrawable = getContext().getDrawable(resId).mutate();
- mDrawable.setBounds(0, 0, mDrawableSize, mDrawableSize);
mDrawable.setTintList(getTextColors());
+ centerIcon();
setCompoundDrawablesRelative(mDrawable, null, null, null);
}
@@ -277,7 +277,7 @@
}
final int top = to.top + (getMeasuredHeight() - height) / 2;
- final int bottom = top + height;
+ final int bottom = top + height;
to.set(left, top, right, bottom);
@@ -289,6 +289,12 @@
return to;
}
+ private void centerIcon() {
+ int x = mTextVisible ? 0
+ : (getWidth() - getPaddingLeft() - getPaddingRight()) / 2 - mDrawableSize / 2;
+ mDrawable.setBounds(x, 0, x + mDrawableSize, mDrawableSize);
+ }
+
@Override
public void onClick(View v) {
mLauncher.getAccessibilityDelegate().handleAccessibleDrop(this, null, null);
@@ -299,12 +305,19 @@
if (mTextVisible != isVisible || !TextUtils.equals(newText, getText())) {
mTextVisible = isVisible;
setText(newText);
+ centerIcon();
setCompoundDrawablesRelative(mDrawable, null, null, null);
int drawablePadding = mTextVisible ? mDrawablePadding : 0;
setCompoundDrawablePadding(drawablePadding);
}
}
+ @Override
+ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+ super.onSizeChanged(w, h, oldw, oldh);
+ centerIcon();
+ }
+
public void setToolTipLocation(int location) {
mToolTipLocation = location;
hideTooltip();
diff --git a/src/com/android/launcher3/model/LoaderCursor.java b/src/com/android/launcher3/model/LoaderCursor.java
index 8a5a9bf..47df538 100644
--- a/src/com/android/launcher3/model/LoaderCursor.java
+++ b/src/com/android/launcher3/model/LoaderCursor.java
@@ -190,6 +190,7 @@
String resourceName = itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT
? getString(iconResourceIndex) : null;
byte[] iconBlob = itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT
+ || itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT
|| restoreFlag != 0
? getBlob(iconIndex) : null;
diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java
index 872adec..8b7ad46 100644
--- a/src/com/android/launcher3/views/FloatingIconView.java
+++ b/src/com/android/launcher3/views/FloatingIconView.java
@@ -70,6 +70,8 @@
// Manages loading the icon on a worker thread
private static @Nullable IconLoadResult sIconLoadResult;
+ private static long sFetchIconId = 0;
+ private static long sRecycledFetchIconId = sFetchIconId;
public static final float SHAPE_PROGRESS_DURATION = 0.10f;
private static final RectF sTmpRectF = new RectF();
@@ -519,8 +521,13 @@
IconLoadResult result = new IconLoadResult(info,
btvIcon == null ? false : btvIcon.isThemed());
- MODEL_EXECUTOR.getHandler().postAtFrontOfQueue(() ->
- getIconResult(l, v, info, position, btvIcon, result));
+ final long fetchIconId = sFetchIconId++;
+ MODEL_EXECUTOR.getHandler().postAtFrontOfQueue(() -> {
+ if (fetchIconId < sRecycledFetchIconId) {
+ return;
+ }
+ getIconResult(l, v, info, position, btvIcon, result);
+ });
sIconLoadResult = result;
return result;
@@ -622,6 +629,7 @@
mOnTargetChangeRunnable = null;
mBadge = null;
sTmpObjArray[0] = null;
+ sRecycledFetchIconId = sFetchIconId;
mIconLoadResult = null;
mClipIconView.recycle();
mBtvDrawable.setBackground(null);