Snap for 8535289 from 11339c644e to tm-qpr1-release

Change-Id: Iee40ceb087f2a3ee34e893c7c09876b78fde82f3
This commit is contained in:
Android Build Coastguard Worker
2022-05-04 03:08:35 +00:00
64 changed files with 548 additions and 270 deletions
@@ -24,6 +24,9 @@ import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TI
import static com.android.launcher3.config.FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE;
import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID;
import static com.android.launcher3.popup.QuickstepSystemShortcut.getSplitSelectShortcutByPosition;
import static com.android.launcher3.taskbar.LauncherTaskbarUIController.ALL_APPS_PAGE_PROGRESS_INDEX;
import static com.android.launcher3.taskbar.LauncherTaskbarUIController.MINUS_ONE_PAGE_PROGRESS_INDEX;
import static com.android.launcher3.taskbar.LauncherTaskbarUIController.WIDGETS_PAGE_PROGRESS_INDEX;
import static com.android.launcher3.util.DisplayController.CHANGE_ACTIVE_SCREEN;
import static com.android.launcher3.util.DisplayController.CHANGE_NAVIGATION_MODE;
import static com.android.launcher3.util.DisplayController.NavigationMode.TWO_BUTTONS;
@@ -229,6 +232,28 @@ public abstract class BaseQuickstepLauncher extends Launcher {
public void onScrollChanged(float progress) {
super.onScrollChanged(progress);
mDepthController.onOverlayScrollChanged(progress);
onTaskbarInAppDisplayProgressUpdate(progress, MINUS_ONE_PAGE_PROGRESS_INDEX);
}
@Override
public void onAllAppsTransition(float progress) {
super.onAllAppsTransition(progress);
onTaskbarInAppDisplayProgressUpdate(progress, ALL_APPS_PAGE_PROGRESS_INDEX);
}
@Override
public void onWidgetsTransition(float progress) {
super.onWidgetsTransition(progress);
onTaskbarInAppDisplayProgressUpdate(progress, WIDGETS_PAGE_PROGRESS_INDEX);
}
private void onTaskbarInAppDisplayProgressUpdate(float progress, int flag) {
if (mTaskbarManager == null
|| mTaskbarManager.getCurrentActivityContext() == null
|| mTaskbarUIController == null) {
return;
}
mTaskbarUIController.onTaskbarInAppDisplayProgressUpdate(progress, flag);
}
@Override
@@ -55,13 +55,13 @@ import com.android.launcher3.popup.SystemShortcut;
import com.android.launcher3.touch.ItemLongClickListener;
import com.android.launcher3.uioverrides.PredictedAppIcon;
import com.android.launcher3.uioverrides.QuickstepLauncher;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.OnboardingPrefs;
import com.android.launcher3.views.Snackbar;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
/**
@@ -480,8 +480,8 @@ public class HotseatPredictionController implements DragController.DragListener,
*
* @param matcher filter matching items that have been removed
*/
public void onModelItemsRemoved(ItemInfoMatcher matcher) {
if (mPredictedItems.removeIf(matcher::matchesInfo)) {
public void onModelItemsRemoved(Predicate<ItemInfo> matcher) {
if (mPredictedItems.removeIf(matcher)) {
fillGapsWithPrediction(true);
}
}
@@ -70,7 +70,8 @@ public interface QuickstepSystemShortcut {
RecentsView recentsView = mTarget.getOverviewPanel();
recentsView.initiateSplitSelect(
new SplitSelectSource(view, new BitmapDrawable(bitmap), intent, mPosition));
new SplitSelectSource(mOriginalView, new BitmapDrawable(bitmap), intent,
mPosition));
}
}
@@ -39,4 +39,10 @@ public class DesktopTaskbarUIController extends TaskbarUIController {
protected void onDestroy() {
mLauncher.getHotseat().setIconsAlpha(1f);
}
@Override
/** Disable taskbar stashing in desktop environment. */
public boolean supportsVisualStashing() {
return false;
}
}
@@ -22,6 +22,7 @@ import android.animation.Animator;
import android.annotation.ColorInt;
import android.os.RemoteException;
import android.util.Log;
import android.util.SparseArray;
import android.view.MotionEvent;
import android.view.TaskTransitionSpec;
import android.view.WindowManagerGlobal;
@@ -43,6 +44,7 @@ import com.android.launcher3.util.OnboardingPrefs;
import com.android.quickstep.AnimatedFloat;
import com.android.quickstep.RecentsAnimationCallbacks;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Set;
import java.util.stream.Stream;
@@ -54,10 +56,22 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
private static final String TAG = "TaskbarUIController";
public static final int MINUS_ONE_PAGE_PROGRESS_INDEX = 0;
public static final int ALL_APPS_PAGE_PROGRESS_INDEX = 1;
public static final int WIDGETS_PAGE_PROGRESS_INDEX = 2;
public static final int SYSUI_SURFACE_PROGRESS_INDEX = 3;
private final SparseArray<Float> mTaskbarInAppDisplayProgress = new SparseArray<>(4);
private final BaseQuickstepLauncher mLauncher;
private final DeviceProfile.OnDeviceProfileChangeListener mOnDeviceProfileChangeListener =
this::onStashedInAppChanged;
dp -> {
onStashedInAppChanged(dp);
if (mControllers != null && mControllers.taskbarViewController != null) {
mControllers.taskbarViewController.onRotationChanged(dp);
}
};
// Initialized in init.
private AnimatedFloat mTaskbarOverrideBackgroundAlpha;
@@ -65,15 +79,6 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
private final TaskbarLauncherStateController
mTaskbarLauncherStateController = new TaskbarLauncherStateController();
private final DeviceProfile.OnDeviceProfileChangeListener mProfileChangeListener =
new DeviceProfile.OnDeviceProfileChangeListener() {
@Override
public void onDeviceProfileChanged(DeviceProfile dp) {
mControllers.taskbarViewController.onRotationChanged(
mLauncher.getDeviceProfile());
}
};
public LauncherTaskbarUIController(BaseQuickstepLauncher launcher) {
mLauncher = launcher;
}
@@ -93,7 +98,6 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
onStashedInAppChanged(mLauncher.getDeviceProfile());
mLauncher.addOnDeviceProfileChangeListener(mOnDeviceProfileChangeListener);
mLauncher.addOnDeviceProfileChangeListener(mProfileChangeListener);
}
@Override
@@ -102,9 +106,8 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
onLauncherResumedOrPaused(false);
mTaskbarLauncherStateController.onDestroy();
mLauncher.removeOnDeviceProfileChangeListener(mOnDeviceProfileChangeListener);
mLauncher.setTaskbarUIController(null);
mLauncher.removeOnDeviceProfileChangeListener(mProfileChangeListener);
mLauncher.removeOnDeviceProfileChangeListener(mOnDeviceProfileChangeListener);
updateTaskTransitionSpec(true);
}
@@ -271,4 +274,85 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
// gesture ends, start drawing taskbar's background again since launcher might stop drawing.
forceHideBackground(inProgress);
}
/**
* Animates Taskbar elements during a transition to a Launcher state that should use in-app
* layouts.
*
* @param progress [0, 1]
* 0 => use home layout
* 1 => use in-app layout
*/
public void onTaskbarInAppDisplayProgressUpdate(float progress, int progressIndex) {
if (mControllers == null) {
// This method can be called before init() is called.
return;
}
mTaskbarInAppDisplayProgress.put(progressIndex, progress);
if (!mControllers.taskbarStashController.isInApp()
&& !mTaskbarLauncherStateController.isAnimatingToLauncher()) {
// Only animate the nav buttons while home and not animating home, otherwise let
// the TaskbarViewController handle it.
mControllers.navbarButtonsViewController
.getTaskbarNavButtonTranslationYForInAppDisplay()
.updateValue(mLauncher.getDeviceProfile().getTaskbarOffsetY()
* getInAppDisplayProgress());
}
}
/** Returns true iff any in-app display progress > 0. */
public boolean shouldUseInAppLayout() {
return getInAppDisplayProgress() > 0;
}
private float getInAppDisplayProgress(int index) {
if (!mTaskbarInAppDisplayProgress.contains(index)) {
mTaskbarInAppDisplayProgress.put(index, 0f);
}
return mTaskbarInAppDisplayProgress.get(index);
}
private float getInAppDisplayProgress() {
return Stream.of(
getInAppDisplayProgress(MINUS_ONE_PAGE_PROGRESS_INDEX),
getInAppDisplayProgress(ALL_APPS_PAGE_PROGRESS_INDEX),
getInAppDisplayProgress(WIDGETS_PAGE_PROGRESS_INDEX),
getInAppDisplayProgress(SYSUI_SURFACE_PROGRESS_INDEX))
.max(Float::compareTo)
.get();
}
@Override
public void dumpLogs(String prefix, PrintWriter pw) {
super.dumpLogs(prefix, pw);
pw.println(String.format(
"%s\tmTaskbarOverrideBackgroundAlpha=%.2f",
prefix,
mTaskbarOverrideBackgroundAlpha.value));
pw.println(String.format("%s\tTaskbar in-app display progress:", prefix));
if (mControllers == null) {
pw.println(String.format("%s\t\tMissing mControllers", prefix));
} else {
pw.println(String.format(
"%s\t\tprogress at MINUS_ONE_PAGE_PROGRESS_INDEX=%.2f",
prefix,
getInAppDisplayProgress(MINUS_ONE_PAGE_PROGRESS_INDEX)));
pw.println(String.format(
"%s\t\tprogress at ALL_APPS_PAGE_PROGRESS_INDEX=%.2f",
prefix,
getInAppDisplayProgress(ALL_APPS_PAGE_PROGRESS_INDEX)));
pw.println(String.format(
"%s\t\tprogress at WIDGETS_PAGE_PROGRESS_INDEX=%.2f",
prefix,
getInAppDisplayProgress(WIDGETS_PAGE_PROGRESS_INDEX)));
pw.println(String.format(
"%s\t\tprogress at SYSUI_SURFACE_PROGRESS_INDEX=%.2f",
prefix,
getInAppDisplayProgress(SYSUI_SURFACE_PROGRESS_INDEX)));
}
mTaskbarLauncherStateController.dumpLogs(prefix + "\t", pw);
}
}
@@ -16,6 +16,7 @@
package com.android.launcher3.taskbar;
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
import static com.android.launcher3.taskbar.LauncherTaskbarUIController.SYSUI_SURFACE_PROGRESS_INDEX;
import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_A11Y;
import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_BACK;
import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_HOME;
@@ -126,11 +127,13 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT
private final AnimatedFloat mTaskbarNavButtonTranslationY = new AnimatedFloat(
this::updateNavButtonTranslationY);
private final AnimatedFloat mTaskbarNavButtonTranslationYForInAppDisplay = new AnimatedFloat(
this::updateNavButtonTranslationY);
private final AnimatedFloat mTaskbarNavButtonTranslationYForIme = new AnimatedFloat(
this::updateNavButtonTranslationY);
// Only applies to mTaskbarNavButtonTranslationY
private final AnimatedFloat mNavButtonTranslationYMultiplier = new AnimatedFloat(
this::updateNavButtonTranslationY);
// Used for System UI state updates that should translate the nav button for in-app display.
private final AnimatedFloat mNavButtonInAppDisplayProgressForSysui = new AnimatedFloat(
this::updateNavButtonInAppDisplayProgressForSysui);
private final AnimatedFloat mTaskbarNavButtonDarkIntensity = new AnimatedFloat(
this::updateNavButtonDarkIntensity);
private final AnimatedFloat mNavButtonDarkIntensityMultiplier = new AnimatedFloat(
@@ -173,7 +176,6 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT
public void init(TaskbarControllers controllers) {
mControllers = controllers;
mNavButtonsView.getLayoutParams().height = mContext.getDeviceProfile().taskbarSize;
mNavButtonTranslationYMultiplier.value = 1;
boolean isThreeButtonNav = mContext.isThreeButtonNav();
mIsImeRenderingNavButtons =
@@ -205,9 +207,9 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT
// Make sure to remove nav bar buttons translation when notification shade is expanded or
// IME is showing (add separate translation for IME).
int flagsToRemoveTranslation = FLAG_NOTIFICATION_SHADE_EXPANDED | FLAG_IME_VISIBLE;
mPropertyHolders.add(new StatePropertyHolder(mNavButtonTranslationYMultiplier,
mPropertyHolders.add(new StatePropertyHolder(mNavButtonInAppDisplayProgressForSysui,
flags -> (flags & flagsToRemoveTranslation) != 0, AnimatedFloat.VALUE,
0, 1));
1, 0));
// Center nav buttons in new height for IME.
float transForIme = (mContext.getDeviceProfile().taskbarSize
- mControllers.taskbarInsetsController.getTaskbarHeightForIme()) / 2f;
@@ -526,6 +528,11 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT
return mTaskbarNavButtonTranslationY;
}
/** Use to set the translationY for the all nav+contextual buttons when in Launcher */
public AnimatedFloat getTaskbarNavButtonTranslationYForInAppDisplay() {
return mTaskbarNavButtonTranslationYForInAppDisplay;
}
/** Use to set the dark intensity for the all nav+contextual buttons */
public AnimatedFloat getTaskbarNavButtonDarkIntensity() {
return mTaskbarNavButtonDarkIntensity;
@@ -554,11 +561,26 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT
}
}
private void updateNavButtonInAppDisplayProgressForSysui() {
TaskbarUIController uiController = mControllers.uiController;
if (uiController instanceof LauncherTaskbarUIController) {
((LauncherTaskbarUIController) uiController).onTaskbarInAppDisplayProgressUpdate(
mNavButtonInAppDisplayProgressForSysui.value, SYSUI_SURFACE_PROGRESS_INDEX);
}
}
private void updateNavButtonTranslationY() {
float normalTranslationY = mTaskbarNavButtonTranslationY.value
* mNavButtonTranslationYMultiplier.value;
float otherTranslationY = mTaskbarNavButtonTranslationYForIme.value;
mNavButtonsView.setTranslationY(normalTranslationY + otherTranslationY);
final float normalTranslationY = mTaskbarNavButtonTranslationY.value;
final float imeAdjustmentTranslationY = mTaskbarNavButtonTranslationYForIme.value;
TaskbarUIController uiController = mControllers.uiController;
final float inAppDisplayAdjustmentTranslationY =
(uiController instanceof LauncherTaskbarUIController
&& ((LauncherTaskbarUIController) uiController).shouldUseInAppLayout())
? mTaskbarNavButtonTranslationYForInAppDisplay.value : 0;
mNavButtonsView.setTranslationY(normalTranslationY
+ imeAdjustmentTranslationY
+ inAppDisplayAdjustmentTranslationY);
}
private void updateNavButtonDarkIntensity() {
@@ -199,7 +199,7 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
new TaskbarInsetsController(this));
}
public void init(TaskbarSharedState sharedState) {
public void init(@NonNull TaskbarSharedState sharedState) {
mLastRequestedNonFullscreenHeight = getDefaultTaskbarWindowHeight();
mWindowLayoutParams = createDefaultWindowLayoutParams();
@@ -61,6 +61,8 @@ public class TaskbarControllers {
private boolean mAreAllControllersInitialized;
private final List<Runnable> mPostInitCallbacks = new ArrayList<>();
@Nullable private TaskbarSharedState mSharedState = null;
public TaskbarControllers(TaskbarActivityContext taskbarActivityContext,
TaskbarDragController taskbarDragController,
TaskbarNavButtonController navButtonController,
@@ -104,8 +106,9 @@ public class TaskbarControllers {
* TaskbarControllers instance, but should be careful to only access things that were created
* in constructors for now, as some controllers may still be waiting for init().
*/
public void init(TaskbarSharedState sharedState) {
public void init(@NonNull TaskbarSharedState sharedState) {
mAreAllControllersInitialized = false;
mSharedState = sharedState;
taskbarDragController.init(this);
navbarButtonsViewController.init(this);
@@ -116,11 +119,11 @@ public class TaskbarControllers {
taskbarUnfoldAnimationController.init(this);
taskbarKeyguardController.init(navbarButtonsViewController);
stashedHandleViewController.init(this);
taskbarStashController.init(this, sharedState);
taskbarStashController.init(this, sharedState.setupUIVisible);
taskbarEduController.init(this);
taskbarPopupController.init(this);
taskbarForceVisibleImmersiveController.init(this);
taskbarAllAppsController.init(this, sharedState);
taskbarAllAppsController.init(this, sharedState.allAppsVisible);
navButtonController.init(this);
taskbarInsetsController.init(this);
@@ -139,6 +142,12 @@ public class TaskbarControllers {
mPostInitCallbacks.clear();
}
@Nullable
public TaskbarSharedState getSharedState() {
// This should only be null if called before init() and after destroy().
return mSharedState;
}
public void onConfigurationChanged(@Config int configChanges) {
navbarButtonsViewController.onConfigurationChanged(configChanges);
}
@@ -147,6 +156,8 @@ public class TaskbarControllers {
* Cleans up all controllers.
*/
public void onDestroy() {
mSharedState = null;
navbarButtonsViewController.onDestroy();
uiController.onDestroy();
rotationButtonController.onDestroy();
@@ -187,9 +198,12 @@ public class TaskbarControllers {
return;
}
pw.println(String.format(
"%s\tmAreAllControllersInitialized=%b", prefix, mAreAllControllersInitialized));
for (LoggableTaskbarController controller : mControllersToLog) {
controller.dumpLogs(prefix + "\t", pw);
}
uiController.dumpLogs(prefix + "\t", pw);
rotationButtonController.dumpLogs(prefix + "\t", pw);
}
@@ -73,6 +73,7 @@ import com.android.systemui.shared.recents.model.Task;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Collections;
import java.util.function.Predicate;
/**
* Handles long click on Taskbar items to start a system drag and drop operation.
@@ -439,12 +440,12 @@ public class TaskbarDragController extends DragController<BaseTaskbarContext> im
target = taskbarViewController.getAllAppsButtonView();
} else if (item.container >= 0) {
// Since folders close when the drag starts, target the folder icon instead.
ItemInfoMatcher matcher = ItemInfoMatcher.forFolderMatch(
Predicate<ItemInfo> matcher = ItemInfoMatcher.forFolderMatch(
ItemInfoMatcher.ofItemIds(IntSet.wrap(item.id)));
target = taskbarViewController.getFirstIconMatch(matcher);
} else if (item.itemType == ITEM_TYPE_DEEP_SHORTCUT) {
// Find first icon with same package/user as the deep shortcut.
ItemInfoMatcher packageUserMatcher = ItemInfoMatcher.ofPackages(
Predicate<ItemInfo> packageUserMatcher = ItemInfoMatcher.ofPackages(
Collections.singleton(item.getTargetPackage()), item.user);
target = taskbarViewController.getFirstIconMatch(packageUserMatcher);
}
@@ -42,7 +42,9 @@ import com.android.quickstep.views.RecentsView;
import com.android.systemui.animation.ViewRootSync;
import com.android.systemui.shared.recents.model.ThumbnailData;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.StringJoiner;
import java.util.function.Consumer;
import java.util.function.Supplier;
@@ -476,4 +478,48 @@ import java.util.function.Supplier;
controller.applyState();
}
}
private static String getStateString(int flags) {
StringJoiner str = new StringJoiner("|");
str.add((flags & FLAG_RESUMED) != 0 ? "FLAG_RESUMED" : "");
str.add((flags & FLAG_RECENTS_ANIMATION_RUNNING) != 0
? "FLAG_RECENTS_ANIMATION_RUNNING" : "");
str.add((flags & FLAG_TRANSITION_STATE_RUNNING) != 0
? "FLAG_TRANSITION_STATE_RUNNING" : "");
return str.toString();
}
protected void dumpLogs(String prefix, PrintWriter pw) {
pw.println(prefix + "TaskbarLauncherStateController:");
pw.println(String.format(
"%s\tmIconAlignmentForResumedState=%.2f",
prefix,
mIconAlignmentForResumedState.value));
pw.println(String.format(
"%s\tmIconAlignmentForGestureState=%.2f",
prefix,
mIconAlignmentForGestureState.value));
pw.println(String.format(
"%s\tmIconAlignmentForLauncherState=%.2f",
prefix,
mIconAlignmentForLauncherState.value));
pw.println(String.format(
"%s\tmTaskbarBackgroundAlpha=%.2f", prefix, mTaskbarBackgroundAlpha.value));
pw.println(String.format(
"%s\tmIconAlphaForHome=%.2f", prefix, mIconAlphaForHome.getValue()));
pw.println(String.format("%s\tmPrevState=%s", prefix, getStateString(mPrevState)));
pw.println(String.format("%s\tmState=%s", prefix, getStateString(mState)));
pw.println(String.format("%s\tmLauncherState=%s", prefix, mLauncherState));
pw.println(String.format(
"%s\tmIsAnimatingToLauncherViaGesture=%b",
prefix,
mIsAnimatingToLauncherViaGesture));
pw.println(String.format(
"%s\tmIsAnimatingToLauncherViaResume=%b",
prefix,
mIsAnimatingToLauncherViaResume));
pw.println(String.format(
"%s\tmShouldDelayLauncherStateAnim=%b", prefix, mShouldDelayLauncherStateAnim));
}
}
@@ -194,6 +194,9 @@ public class TaskbarManager {
* Sets a {@link StatefulActivity} to act as taskbar callback
*/
public void setActivity(@NonNull StatefulActivity activity) {
if (mActivity == activity) {
return;
}
mActivity = activity;
mUnfoldProgressProvider.setSourceProvider(getUnfoldTransitionProgressProviderForActivity(
activity));
@@ -36,6 +36,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.function.Predicate;
/**
* Launcher model Callbacks for rendering taskbar.
@@ -126,16 +127,16 @@ public class TaskbarModelCallbacks implements
}
@Override
public void bindWorkspaceComponentsRemoved(ItemInfoMatcher matcher) {
public void bindWorkspaceComponentsRemoved(Predicate<ItemInfo> matcher) {
if (handleItemsRemoved(matcher)) {
commitItemsToUI();
}
}
private boolean handleItemsRemoved(ItemInfoMatcher matcher) {
private boolean handleItemsRemoved(Predicate<ItemInfo> matcher) {
boolean modified = false;
for (int i = mHotseatItems.size() - 1; i >= 0; i--) {
if (matcher.matchesInfo(mHotseatItems.valueAt(i))) {
if (matcher.test(mHotseatItems.valueAt(i))) {
modified = true;
mHotseatItems.removeAt(i);
}
@@ -25,5 +25,4 @@ public class TaskbarSharedState {
public boolean setupUIVisible = false;
public boolean allAppsVisible = false;
}
@@ -17,6 +17,7 @@ package com.android.launcher3.taskbar;
import static android.view.HapticFeedbackConstants.LONG_PRESS;
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_LONGPRESS_HIDE;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_LONGPRESS_SHOW;
import static com.android.launcher3.taskbar.Utilities.appendFlag;
@@ -34,7 +35,6 @@ import android.view.WindowInsets;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Utilities;
import com.android.launcher3.taskbar.allapps.TaskbarAllAppsSlideInView;
import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
import com.android.quickstep.AnimatedFloat;
@@ -167,7 +167,7 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba
mStashedHeight = mActivity.getDeviceProfile().stashedTaskbarSize;
}
public void init(TaskbarControllers controllers, TaskbarSharedState sharedState) {
public void init(TaskbarControllers controllers, boolean setupUIVisible) {
mControllers = controllers;
TaskbarDragLayerController dragLayerController = controllers.taskbarDragLayerController;
@@ -188,7 +188,7 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba
boolean isManuallyStashedInApp = supportsManualStashing()
&& mPrefs.getBoolean(SHARED_PREFS_STASHED_KEY, DEFAULT_STASHED_PREF);
boolean isInSetup = !mActivity.isUserSetupComplete() || sharedState.setupUIVisible;
boolean isInSetup = !mActivity.isUserSetupComplete() || setupUIVisible;
updateStateForFlag(FLAG_STASHED_IN_APP_MANUAL, isManuallyStashedInApp);
updateStateForFlag(FLAG_STASHED_IN_APP_SETUP, isInSetup);
updateStateForFlag(FLAG_IN_SETUP, isInSetup);
@@ -202,7 +202,7 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba
* state.
*/
public boolean supportsVisualStashing() {
return !mActivity.isThreeButtonNav();
return mControllers.uiController.supportsVisualStashing();
}
/**
@@ -275,7 +275,7 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba
return !mIsStashed && isInApp();
}
private boolean isInApp() {
public boolean isInApp() {
return hasAnyFlag(FLAGS_IN_APP);
}
@@ -564,7 +564,8 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba
updateStateForFlag(FLAG_STASHED_IN_APP_ALL_APPS, false);
if (applyState) {
applyState(TaskbarAllAppsSlideInView.DEFAULT_CLOSE_DURATION);
applyState(ALL_APPS.getTransitionDuration(
mControllers.taskbarActivityContext, false /* isToState */));
}
}
@@ -22,6 +22,7 @@ import androidx.annotation.CallSuper;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.ItemInfoWithIcon;
import java.io.PrintWriter;
import java.util.stream.Stream;
/**
@@ -48,6 +49,11 @@ public class TaskbarUIController {
return true;
}
public boolean supportsVisualStashing() {
if (mControllers == null) return false;
return !mControllers.taskbarActivityContext.isThreeButtonNav();
}
protected void onStashedInAppChanged() { }
public Stream<ItemInfoWithIcon> getAppIconsForEdu() {
@@ -86,4 +92,12 @@ public class TaskbarUIController {
stashController.applyState();
}
}
@CallSuper
protected void dumpLogs(String prefix, PrintWriter pw) {
pw.println(String.format(
"%sTaskbarUIController: using an instance of %s",
prefix,
getClass().getSimpleName()));
}
}
@@ -41,12 +41,13 @@ import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.uioverrides.ApiWrapper;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.LauncherBindableItemsContainer;
import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.views.AllAppsButton;
import com.android.launcher3.views.DoubleShadowBubbleTextView;
import java.util.function.Predicate;
/**
* Hosts the Taskbar content such as Hotseat and Recent Apps. Drawn on top of other apps.
*/
@@ -424,8 +425,8 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar
* Finds the first icon to match one of the given matchers, from highest to lowest priority.
* @return The first match, or All Apps button if no match was found.
*/
public View getFirstMatch(ItemInfoMatcher... matchers) {
for (ItemInfoMatcher matcher : matchers) {
public View getFirstMatch(Predicate<ItemInfo>... matchers) {
for (Predicate<ItemInfo> matcher : matchers) {
for (int i = 0; i < getChildCount(); i++) {
View item = getChildAt(i);
if (!(item.getTag() instanceof ItemInfo)) {
@@ -433,7 +434,7 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar
continue;
}
ItemInfo info = (ItemInfo) item.getTag();
if (matcher.matchesInfo(info)) {
if (matcher.test(info)) {
return item;
}
}
@@ -47,6 +47,7 @@ import com.android.launcher3.util.MultiValueAlpha;
import com.android.quickstep.AnimatedFloat;
import java.io.PrintWriter;
import java.util.function.Predicate;
/**
* Handles properties/data collection, then passes the results to TaskbarView to render.
@@ -73,6 +74,7 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
private final AnimatedFloat mTaskbarIconTranslationYForStash = new AnimatedFloat(
this::updateTranslationY);
private AnimatedFloat mTaskbarNavButtonTranslationY;
private AnimatedFloat mTaskbarNavButtonTranslationYForInAppDisplay;
private final AnimatedFloat mThemeIconsBackground = new AnimatedFloat(
this::updateIconsBackground);
@@ -112,6 +114,8 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
}
mTaskbarNavButtonTranslationY =
controllers.navbarButtonsViewController.getTaskbarNavButtonTranslationY();
mTaskbarNavButtonTranslationYForInAppDisplay = controllers.navbarButtonsViewController
.getTaskbarNavButtonTranslationYForInAppDisplay();
}
public void onDestroy() {
@@ -242,6 +246,7 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
int offsetY = launcherDp.getTaskbarOffsetY();
setter.setFloat(mTaskbarIconTranslationYForHome, VALUE, -offsetY, LINEAR);
setter.setFloat(mTaskbarNavButtonTranslationY, VALUE, -offsetY, LINEAR);
setter.setFloat(mTaskbarNavButtonTranslationYForInAppDisplay, VALUE, offsetY, LINEAR);
if (Utilities.isDarkTheme(mTaskbarView.getContext())) {
setter.addFloat(mThemeIconsBackground, VALUE, 0f, 1f, LINEAR);
@@ -258,12 +263,14 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
View child = mTaskbarView.getChildAt(i);
int positionInHotseat = -1;
if (FeatureFlags.ENABLE_ALL_APPS_IN_TASKBAR.get() && i == count - 1) {
boolean isRtl = Utilities.isRtl(child.getResources());
if (FeatureFlags.ENABLE_ALL_APPS_IN_TASKBAR.get()
&& ((isRtl && i == 0) || (!isRtl && i == count - 1))) {
// Note that there is no All Apps button in the hotseat, this position is only used
// as its convenient for animation purposes.
positionInHotseat = Utilities.isRtl(child.getResources())
positionInHotseat = isRtl
? -1
: mActivity.getDeviceProfile().inv.numShownHotseatIcons;
: mActivity.getDeviceProfile().numShownHotseatIcons;
setter.setViewAlpha(child, 0, LINEAR);
} else if (child.getTag() instanceof ItemInfo) {
@@ -289,10 +296,12 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
}
public void onRotationChanged(DeviceProfile deviceProfile) {
if (areIconsVisible()) {
if (mControllers.taskbarStashController.isInApp()) {
// We only translate on rotation when on home
return;
}
mActivity.setTaskbarWindowHeight(
deviceProfile.taskbarSize + deviceProfile.getTaskbarOffsetY());
mTaskbarNavButtonTranslationY.updateValue(-deviceProfile.getTaskbarOffsetY());
}
@@ -309,8 +318,8 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
* 2) FolderIcon of the Folder containing the given icon
* 3) All Apps button
*/
public View getFirstIconMatch(ItemInfoMatcher matcher) {
ItemInfoMatcher folderMatcher = ItemInfoMatcher.forFolderMatch(matcher);
public View getFirstIconMatch(Predicate<ItemInfo> matcher) {
Predicate<ItemInfo> folderMatcher = ItemInfoMatcher.forFolderMatch(matcher);
return mTaskbarView.getFirstMatch(matcher, folderMatcher);
}
@@ -38,7 +38,6 @@ import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.taskbar.TaskbarActivityContext;
import com.android.launcher3.taskbar.TaskbarControllers;
import com.android.launcher3.taskbar.TaskbarSharedState;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.TaskStackChangeListeners;
@@ -72,7 +71,6 @@ public final class TaskbarAllAppsController implements OnDeviceProfileChangeList
};
private TaskbarControllers mControllers;
private TaskbarSharedState mSharedState;
/** Window context for all apps if it is open. */
private @Nullable TaskbarAllAppsContext mAllAppsContext;
@@ -88,18 +86,17 @@ public final class TaskbarAllAppsController implements OnDeviceProfileChangeList
}
/** Initialize the controller. */
public void init(TaskbarControllers controllers, TaskbarSharedState sharedState) {
public void init(TaskbarControllers controllers, boolean allAppsVisible) {
if (!FeatureFlags.ENABLE_ALL_APPS_IN_TASKBAR.get()) {
return;
}
mControllers = controllers;
mSharedState = sharedState;
/*
* Recreate All Apps if it was open in the previous Taskbar instance (e.g. the configuration
* changed).
*/
if (mSharedState.allAppsVisible) {
if (allAppsVisible) {
show(false);
}
}
@@ -141,7 +138,9 @@ public final class TaskbarAllAppsController implements OnDeviceProfileChangeList
return;
}
mProxyView.show();
mSharedState.allAppsVisible = true;
// mControllers and getSharedState should never be null here. Do not handle null-pointer
// to catch invalid states.
mControllers.getSharedState().allAppsVisible = true;
mAllAppsContext = new TaskbarAllAppsContext(mTaskbarContext,
this,
@@ -176,7 +175,9 @@ public final class TaskbarAllAppsController implements OnDeviceProfileChangeList
return;
}
mProxyView.close(false);
mSharedState.allAppsVisible = false;
// mControllers and getSharedState should never be null here. Do not handle null-pointer
// to catch invalid states.
mControllers.getSharedState().allAppsVisible = false;
onDestroy();
}
@@ -15,13 +15,16 @@
*/
package com.android.launcher3.taskbar.allapps;
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.anim.Interpolators.AGGRESSIVE_EASE;
import static com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE;
import android.animation.PropertyValuesHolder;
import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.animation.Interpolator;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Insettable;
@@ -33,9 +36,6 @@ import java.util.Optional;
/** Wrapper for taskbar all apps with slide-in behavior. */
public class TaskbarAllAppsSlideInView extends AbstractSlideInView<TaskbarAllAppsContext>
implements Insettable, DeviceProfile.OnDeviceProfileChangeListener {
static final int DEFAULT_OPEN_DURATION = 500;
public static final int DEFAULT_CLOSE_DURATION = 200;
private TaskbarAllAppsContainerView mAppsView;
private OnCloseListener mOnCloseBeginListener;
private float mShiftRange;
@@ -61,7 +61,8 @@ public class TaskbarAllAppsSlideInView extends AbstractSlideInView<TaskbarAllApp
mOpenCloseAnimator.setValues(
PropertyValuesHolder.ofFloat(TRANSLATION_SHIFT, TRANSLATION_SHIFT_OPENED));
mOpenCloseAnimator.setInterpolator(AGGRESSIVE_EASE);
mOpenCloseAnimator.setDuration(DEFAULT_OPEN_DURATION).start();
mOpenCloseAnimator.setDuration(
ALL_APPS.getTransitionDuration(mContext, true /* isToState */)).start();
} else {
mTranslationShift = TRANSLATION_SHIFT_OPENED;
}
@@ -80,7 +81,12 @@ public class TaskbarAllAppsSlideInView extends AbstractSlideInView<TaskbarAllApp
@Override
protected void handleClose(boolean animate) {
Optional.ofNullable(mOnCloseBeginListener).ifPresent(OnCloseListener::onSlideInViewClosed);
handleClose(animate, DEFAULT_CLOSE_DURATION);
handleClose(animate, ALL_APPS.getTransitionDuration(mContext, false /* isToState */));
}
@Override
protected Interpolator getIdleInterpolator() {
return EMPHASIZED_ACCELERATE;
}
@Override
@@ -15,8 +15,8 @@
*/
package com.android.launcher3.taskbar.allapps;
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_STASHED_IN_APP_ALL_APPS;
import static com.android.launcher3.taskbar.allapps.TaskbarAllAppsSlideInView.DEFAULT_OPEN_DURATION;
import static com.android.launcher3.util.OnboardingPrefs.ALL_APPS_VISITED_COUNT;
import com.android.launcher3.AbstractFloatingView;
@@ -81,7 +81,8 @@ final class TaskbarAllAppsViewController {
private void setUpTaskbarStashing() {
mTaskbarStashController.updateStateForFlag(FLAG_STASHED_IN_APP_ALL_APPS, true);
mTaskbarStashController.applyState(DEFAULT_OPEN_DURATION);
mTaskbarStashController.applyState(
ALL_APPS.getTransitionDuration(mContext, true /* isToState */));
mSlideInView.setOnCloseBeginListener(() -> {
AbstractFloatingView.closeOpenContainer(
mContext, AbstractFloatingView.TYPE_ACTION_POPUP);
@@ -70,7 +70,6 @@ import com.android.launcher3.uioverrides.touchcontrollers.TransposedQuickSwitchT
import com.android.launcher3.uioverrides.touchcontrollers.TwoButtonNavbarTouchController;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.DisplayController.NavigationMode;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.PendingRequestArgs;
import com.android.launcher3.util.TouchController;
import com.android.launcher3.util.UiThreadHelper;
@@ -86,6 +85,7 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Objects;
import java.util.function.Predicate;
import java.util.stream.Stream;
public class QuickstepLauncher extends BaseQuickstepLauncher {
@@ -245,7 +245,7 @@ public class QuickstepLauncher extends BaseQuickstepLauncher {
}
@Override
public void bindWorkspaceComponentsRemoved(ItemInfoMatcher matcher) {
public void bindWorkspaceComponentsRemoved(Predicate<ItemInfo> matcher) {
super.bindWorkspaceComponentsRemoved(matcher);
mHotseatPredictionController.onModelItemsRemoved(matcher);
}
@@ -118,7 +118,7 @@ public final class RecentsViewStateController extends
if (toState == OVERVIEW_SPLIT_SELECT) {
// Animation to "dismiss" selected taskView
PendingAnimation splitSelectInitAnimation = mRecentsView.createSplitSelectInitAnimation(
toState.getTransitionDuration(mLauncher));
toState.getTransitionDuration(mLauncher, true /* isToState */));
// Add properties to shift remaining taskViews to get out of placeholder view
splitSelectInitAnimation.setFloat(mRecentsView, taskViewsFloat.first,
toState.getSplitSelectTranslation(mLauncher), LINEAR);
@@ -33,12 +33,12 @@ import com.android.systemui.shared.plugins.PluginInstance;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.shared.plugins.PluginManagerImpl;
import com.android.systemui.shared.plugins.PluginPrefs;
import com.android.systemui.shared.system.UncaughtExceptionPreHandlerManager;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.Set;
public class PluginManagerWrapper {
@@ -48,6 +48,9 @@ public class PluginManagerWrapper {
public static final String PLUGIN_CHANGED = PluginManager.PLUGIN_CHANGED;
private static final UncaughtExceptionPreHandlerManager UNCAUGHT_EXCEPTION_PRE_HANDLER_MANAGER =
new UncaughtExceptionPreHandlerManager();
private final Context mContext;
private final PluginManager mPluginManager;
private final PluginEnablerImpl mPluginEnabler;
@@ -67,7 +70,7 @@ public class PluginManagerWrapper {
mPluginManager = new PluginManagerImpl(c, instanceManagerFactory,
Utilities.IS_DEBUG_DEVICE,
Optional.ofNullable(Thread.getDefaultUncaughtExceptionHandler()), mPluginEnabler,
UNCAUGHT_EXCEPTION_PRE_HANDLER_MANAGER, mPluginEnabler,
new PluginPrefs(c), privilegedPlugins);
}
@@ -38,8 +38,8 @@ public class AllAppsState extends LauncherState {
}
@Override
public int getTransitionDuration(Context context) {
return 150;
public int getTransitionDuration(Context context, boolean isToState) {
return isToState ? 500 : 300;
}
@Override
@@ -40,7 +40,7 @@ public class OverviewModalTaskState extends OverviewState {
}
@Override
public int getTransitionDuration(Context launcher) {
public int getTransitionDuration(Context launcher, boolean isToState) {
return 300;
}
@@ -22,10 +22,12 @@ import android.content.Context;
import android.graphics.Rect;
import android.os.SystemProperties;
import com.android.launcher3.BaseQuickstepLauncher;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.R;
import com.android.launcher3.taskbar.LauncherTaskbarUIController;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.Themes;
import com.android.quickstep.util.LayoutUtils;
@@ -56,7 +58,7 @@ public class OverviewState extends LauncherState {
}
@Override
public int getTransitionDuration(Context context) {
public int getTransitionDuration(Context context, boolean isToState) {
// In gesture modes, overview comes in all the way from the side, so give it more time.
return DisplayController.getNavigationMode(context).hasGestures ? 380 : 250;
}
@@ -93,7 +95,13 @@ public class OverviewState extends LauncherState {
@Override
public boolean isTaskbarStashed(Launcher launcher) {
return true;
if (launcher instanceof BaseQuickstepLauncher) {
LauncherTaskbarUIController uiController =
((BaseQuickstepLauncher) launcher).getTaskbarUIController();
return uiController != null && uiController.supportsVisualStashing();
}
return super.isTaskbarStashed(launcher);
}
@Override
@@ -42,6 +42,7 @@ import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SC
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_X;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_Y;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_SCRIM_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_VERTICAL_PROGRESS;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_SCALE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_TRANSLATE;
@@ -50,6 +51,8 @@ import static com.android.launcher3.uioverrides.touchcontrollers.PortraitStatesT
import static com.android.launcher3.uioverrides.touchcontrollers.PortraitStatesTouchController.ALL_APPS_SCRIM_OPAQUE_THRESHOLD;
import static com.android.launcher3.uioverrides.touchcontrollers.PortraitStatesTouchController.ALL_APPS_SCRIM_VISIBLE_THRESHOLD;
import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
import static com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE;
import static com.android.systemui.animation.Interpolators.EMPHASIZED_DECELERATE;
import android.animation.ValueAnimator;
@@ -179,12 +182,17 @@ public class QuickstepAtomicAnimationFactory extends
}
config.duration = Math.max(config.duration, mHintToNormalDuration);
} else if (fromState == ALL_APPS && toState == NORMAL) {
config.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress(DEACCEL,
1 - ALL_APPS_CONTENT_FADE_MAX_CLAMPING_THRESHOLD,
1 - ALL_APPS_CONTENT_FADE_MIN_CLAMPING_THRESHOLD));
config.setInterpolator(ANIM_SCRIM_FADE, Interpolators.clampToProgress(DEACCEL,
boolean isTablet = mActivity.getDeviceProfile().isTablet;
config.setInterpolator(ANIM_ALL_APPS_FADE,
isTablet ? FINAL_FRAME : Interpolators.clampToProgress(LINEAR,
1 - ALL_APPS_CONTENT_FADE_MAX_CLAMPING_THRESHOLD,
1 - ALL_APPS_CONTENT_FADE_MIN_CLAMPING_THRESHOLD));
config.setInterpolator(ANIM_SCRIM_FADE, Interpolators.clampToProgress(LINEAR,
1 - ALL_APPS_SCRIM_OPAQUE_THRESHOLD,
1 - ALL_APPS_SCRIM_VISIBLE_THRESHOLD));
config.setInterpolator(ANIM_VERTICAL_PROGRESS, EMPHASIZED_ACCELERATE);
} else if (fromState == NORMAL && toState == ALL_APPS) {
config.setInterpolator(ANIM_VERTICAL_PROGRESS, EMPHASIZED_DECELERATE);
}
}
}
@@ -180,7 +180,7 @@ public class NoButtonNavbarToOverviewTouchController extends PortraitStatesTouch
// Normally we compute the duration based on the velocity and distance to the given
// state, but since the hint state tracks the entire screen without a clear endpoint, we
// need to manually set the duration to a reasonable value.
animator.setDuration(HINT_STATE.getTransitionDuration(mLauncher));
animator.setDuration(HINT_STATE.getTransitionDuration(mLauncher, true /* isToState */));
}
}
@@ -21,10 +21,9 @@ import static com.android.launcher3.AbstractFloatingView.getTopOpenViewWithType;
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.anim.Interpolators.ACCEL;
import static com.android.launcher3.anim.Interpolators.DEACCEL;
import static com.android.launcher3.anim.Interpolators.FINAL_FRAME;
import static com.android.launcher3.anim.Interpolators.INSTANT;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_SCRIM_FADE;
@@ -131,10 +130,10 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr
boolean isTablet = mLauncher.getDeviceProfile().isTablet;
builder.setInterpolator(ANIM_ALL_APPS_FADE, isTablet
? INSTANT
: Interpolators.clampToProgress(ACCEL,
: Interpolators.clampToProgress(LINEAR,
ALL_APPS_CONTENT_FADE_MIN_CLAMPING_THRESHOLD,
ALL_APPS_CONTENT_FADE_MAX_CLAMPING_THRESHOLD));
builder.setInterpolator(ANIM_SCRIM_FADE, Interpolators.clampToProgress(ACCEL,
builder.setInterpolator(ANIM_SCRIM_FADE, Interpolators.clampToProgress(LINEAR,
ALL_APPS_SCRIM_VISIBLE_THRESHOLD,
ALL_APPS_SCRIM_OPAQUE_THRESHOLD));
return builder;
@@ -145,10 +144,10 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr
boolean isTablet = mLauncher.getDeviceProfile().isTablet;
builder.setInterpolator(ANIM_ALL_APPS_FADE, isTablet
? FINAL_FRAME
: Interpolators.clampToProgress(DEACCEL,
: Interpolators.clampToProgress(LINEAR,
1 - ALL_APPS_CONTENT_FADE_MAX_CLAMPING_THRESHOLD,
1 - ALL_APPS_CONTENT_FADE_MIN_CLAMPING_THRESHOLD));
builder.setInterpolator(ANIM_SCRIM_FADE, Interpolators.clampToProgress(DEACCEL,
builder.setInterpolator(ANIM_SCRIM_FADE, Interpolators.clampToProgress(LINEAR,
1 - ALL_APPS_SCRIM_OPAQUE_THRESHOLD,
1 - ALL_APPS_SCRIM_VISIBLE_THRESHOLD));
return builder;
@@ -104,8 +104,7 @@ public class RecentsAnimationCallbacks implements
.map(RemoteAnimationTargetCompat::unwrap)
.toArray(RemoteAnimationTarget[]::new);
RemoteAnimationTarget[] nonAppTargets =
mSystemUiProxy.onGoingToRecentsLegacy(mCancelled, nonHomeApps);
RemoteAnimationTarget[] nonAppTargets = mSystemUiProxy.onGoingToRecentsLegacy(nonHomeApps);
RecentsAnimationTargets targets = new RecentsAnimationTargets(appTargets,
wallpaperTargets, RemoteAnimationTargetCompat.wrap(nonAppTargets),
@@ -676,14 +676,12 @@ public class SystemUiProxy implements ISystemUiProxy, DisplayController.DisplayI
* Call this when going to recents so that shell can set-up and provide appropriate leashes
* for animation (eg. DividerBar).
*
* @param cancel true if recents starting is being cancelled.
* @return RemoteAnimationTargets of windows that need to animate but only exist in shell.
*/
public RemoteAnimationTarget[] onGoingToRecentsLegacy(boolean cancel,
RemoteAnimationTarget[] apps) {
public RemoteAnimationTarget[] onGoingToRecentsLegacy(RemoteAnimationTarget[] apps) {
if (mSplitScreen != null) {
try {
return mSplitScreen.onGoingToRecentsLegacy(cancel, apps);
return mSplitScreen.onGoingToRecentsLegacy(apps);
} catch (RemoteException e) {
Log.w(TAG, "Failed call onGoingToRecentsLegacy");
}
@@ -691,6 +689,17 @@ public class SystemUiProxy implements ISystemUiProxy, DisplayController.DisplayI
return null;
}
public RemoteAnimationTarget[] onStartingSplitLegacy(RemoteAnimationTarget[] apps) {
if (mSplitScreen != null) {
try {
return mSplitScreen.onStartingSplitLegacy(apps);
} catch (RemoteException e) {
Log.w(TAG, "Failed call onStartingSplitLegacy");
}
}
return null;
}
//
// One handed
//
@@ -177,8 +177,9 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn
((RecentsActivity) activityInterface.getCreatedActivity()).startHome();
return;
}
RemoteAnimationTarget[] nonAppTargets = SystemUiProxy.INSTANCE.get(mCtx)
.onGoingToRecentsLegacy(false, nonHomeApps);
RemoteAnimationTarget[] nonAppTargets =
SystemUiProxy.INSTANCE.getNoCreate().onStartingSplitLegacy(nonHomeApps);
if (ENABLE_QUICKSTEP_LIVE_TILE.get() && activityInterface.isInLiveTileMode()
&& activityInterface.getCreatedActivity() != null) {
@@ -112,7 +112,7 @@ public class FallbackRecentsStateController implements StateHandler<RecentsState
RecentsState currentState = mActivity.getStateManager().getState();
if (isSplitSelectionState(state) && !isSplitSelectionState(currentState)) {
setter.add(mRecentsView.createSplitSelectInitAnimation(
state.getTransitionDuration(mActivity)).buildAnim());
state.getTransitionDuration(mActivity, true /* isToState */)).buildAnim());
}
Pair<FloatProperty, FloatProperty> taskViewsFloat =
@@ -77,7 +77,7 @@ public class RecentsState implements BaseState<RecentsState> {
}
@Override
public int getTransitionDuration(Context context) {
public int getTransitionDuration(Context context, boolean isToState) {
return 250;
}
@@ -82,7 +82,7 @@ public class OverviewToHomeAnim {
// WorkspaceRevealAnim handles the depth, so don't interfere.
config.animFlags |= StateAnimationConfig.SKIP_DEPTH_CONTROLLER;
}
config.duration = startState.getTransitionDuration(mLauncher);
config.duration = startState.getTransitionDuration(mLauncher, false /* isToState */);
AnimatorSet stateAnim = stateManager.createAtomicAnimation(
startState, NORMAL, config);
stateAnim.addListener(new AnimationSuccessListener() {
@@ -196,6 +196,13 @@ public class FloatingTaskView extends FrameLayout {
0, 1, ACCEL);
animation.addFloat(mThumbnailView, LauncherAnimUtils.VIEW_ALPHA,
1, 0, DEACCEL_3);
} else if (isStagedTask) {
// Fade in the placeholder view when split is initiated from homescreen / all apps
// icons.
if (mSplitPlaceholderView.getAlpha() == 0) {
animation.addFloat(mSplitPlaceholderView, SplitPlaceholderView.ALPHA_FLOAT,
0.3f, 1, ACCEL);
}
}
MultiValueUpdateListener listener = new MultiValueUpdateListener() {
@@ -2757,16 +2757,15 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
mSplitHiddenTaskView.getThumbnail().getThumbnail(),
mSplitHiddenTaskView.getIconView().getDrawable(), startingTaskRect);
mFirstFloatingTaskView.setAlpha(1);
mFirstFloatingTaskView.addAnimation(anim, startingTaskRect,
mTempRect, true /* fadeWithThumbnail */, true /* isStagedTask */);
mFirstFloatingTaskView.addAnimation(anim, startingTaskRect, mTempRect,
true /* fadeWithThumbnail */, true /* isStagedTask */);
} else {
mSplitSelectSource.view.setVisibility(INVISIBLE);
mFirstFloatingTaskView = FloatingTaskView.getFloatingTaskView(mActivity,
mSplitSelectSource.view, null,
mSplitSelectSource.view, null /* thumbnail */,
mSplitSelectSource.drawable, startingTaskRect);
mFirstFloatingTaskView.setAlpha(1);
mFirstFloatingTaskView.addAnimation(anim, startingTaskRect,
mTempRect, true /* fadeWithThumbnail */, true /* isStagedTask */);
mFirstFloatingTaskView.addAnimation(anim, startingTaskRect, mTempRect,
false /* fadeWithThumbnail */, true /* isStagedTask */);
}
InteractionJankMonitorWrapper.begin(this,
InteractionJankMonitorWrapper.CUJ_SPLIT_SCREEN_ENTER, "First tile selected");
@@ -4059,7 +4058,8 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
// TODO(194414938) starting bounds seem slightly off, investigate
Rect firstTaskStartingBounds = new Rect();
Rect firstTaskEndingBounds = mTempRect;
int duration = mActivity.getStateManager().getState().getTransitionDuration(getContext());
int duration = mActivity.getStateManager().getState().getTransitionDuration(getContext(),
false /* isToState */);
PendingAnimation pendingAnimation = new PendingAnimation(duration);
int halfDividerSize = getResources()
+25 -8
View File
@@ -182,7 +182,6 @@ import com.android.launcher3.util.ActivityTracker;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.OnboardingPrefs;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.PackageUserKey;
@@ -2739,9 +2738,9 @@ public class Launcher extends StatefulActivity<LauncherState>
*/
public View getFirstMatchForAppClose(int preferredItemId, String packageName, UserHandle user,
boolean supportsAllAppsState) {
final ItemInfoMatcher preferredItem = (info, cn) ->
final Predicate<ItemInfo> preferredItem = info ->
info != null && info.id == preferredItemId;
final ItemInfoMatcher packageAndUserAndApp = (info, cn) ->
final Predicate<ItemInfo> packageAndUserAndApp = info ->
info != null
&& info.itemType == ITEM_TYPE_APPLICATION
&& info.user.equals(user)
@@ -2770,8 +2769,8 @@ public class Launcher extends StatefulActivity<LauncherState>
* @param operators List of operators, in order starting from best matching operator.
*/
private static View getFirstMatch(Iterable<ViewGroup> containers,
final ItemInfoMatcher... operators) {
for (ItemInfoMatcher operator : operators) {
final Predicate<ItemInfo>... operators) {
for (Predicate<ItemInfo> operator : operators) {
for (ViewGroup container : containers) {
View match = mapOverViewGroup(container, operator);
if (match != null) {
@@ -2786,11 +2785,11 @@ public class Launcher extends StatefulActivity<LauncherState>
* Returns the first view matching the operator in the given ViewGroups, or null if none.
* Forward iteration matters.
*/
private static View mapOverViewGroup(ViewGroup container, ItemInfoMatcher op) {
private static View mapOverViewGroup(ViewGroup container, Predicate<ItemInfo> op) {
final int itemCount = container.getChildCount();
for (int itemIdx = 0; itemIdx < itemCount; itemIdx++) {
View item = container.getChildAt(itemIdx);
if (op.matchesInfo((ItemInfo) item.getTag())) {
if (op.test((ItemInfo) item.getTag())) {
return item;
}
}
@@ -2887,7 +2886,7 @@ public class Launcher extends StatefulActivity<LauncherState>
* package-removal should clear all items by package name.
*/
@Override
public void bindWorkspaceComponentsRemoved(final ItemInfoMatcher matcher) {
public void bindWorkspaceComponentsRemoved(Predicate<ItemInfo> matcher) {
mWorkspace.removeItemsByMatcher(matcher);
mDragController.onAppsRemoved(matcher);
PopupContainerWithArrow.dismissInvalidPopup(this);
@@ -3168,6 +3167,24 @@ public class Launcher extends StatefulActivity<LauncherState>
return new DragOptions();
}
/**
* Animates Launcher elements during a transition to the All Apps page.
*
* @param progress Transition progress from 0 to 1; where 0 => home and 1 => all apps.
*/
public void onAllAppsTransition(float progress) {
// No-Op
}
/**
* Animates Launcher elements during a transition to the Widgets pages.
*
* @param progress Transition progress from 0 to 1; where 0 => home and 1 => widgets.
*/
public void onWidgetsTransition(float progress) {
// No-Op
}
private static class NonConfigInstance {
public Configuration config;
public Bitmap snapshot;
+1 -1
View File
@@ -113,7 +113,7 @@ public abstract class LauncherState implements BaseState<LauncherState> {
FLAG_DISABLE_RESTORE | FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED | FLAG_HIDE_BACK_BUTTON |
FLAG_HAS_SYS_UI_SCRIM) {
@Override
public int getTransitionDuration(Context context) {
public int getTransitionDuration(Context context, boolean isToState) {
// Arbitrary duration, when going to NORMAL we use the state we're coming from instead.
return 0;
}
@@ -31,6 +31,10 @@ public class ResourceUtils {
public static final String NAVBAR_HEIGHT = "navigation_bar_height";
public static final String NAVBAR_HEIGHT_LANDSCAPE = "navigation_bar_height_landscape";
public static final String STATUS_BAR_HEIGHT = "status_bar_height";
public static final String STATUS_BAR_HEIGHT_LANDSCAPE = "status_bar_height_landscape";
public static final String STATUS_BAR_HEIGHT_PORTRAIT = "status_bar_height_portrait";
public static int getNavbarSize(String resName, Resources res) {
return getDimenByName(resName, res, DEFAULT_NAVBAR_VALUE);
}
+5 -6
View File
@@ -102,7 +102,6 @@ import com.android.launcher3.util.Executors;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.IntSparseArrayMap;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.LauncherBindableItemsContainer;
import com.android.launcher3.util.OverlayEdgeEffect;
import com.android.launcher3.util.PackageUserKey;
@@ -2118,7 +2117,7 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T>
final Runnable onCompleteCallback = onCompleteRunnable;
mLauncher.getDragController().animateDragViewToOriginalPosition(
/* onComplete= */ callbackList::executeAllAndDestroy, cell,
SPRING_LOADED.getTransitionDuration(mLauncher));
SPRING_LOADED.getTransitionDuration(mLauncher, true /* isToState */));
mLauncher.getStateManager().goToState(NORMAL, /* delay= */ 0,
onCompleteCallback == null
? null
@@ -3235,7 +3234,7 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T>
* as a part of an update, this is called to ensure that other widgets and application
* shortcuts are not removed.
*/
public void removeItemsByMatcher(final ItemInfoMatcher matcher) {
public void removeItemsByMatcher(final Predicate<ItemInfo> matcher) {
for (CellLayout layout : getWorkspaceAndHotseatCellLayouts()) {
ShortcutAndWidgetContainer container = layout.getShortcutsAndWidgets();
// Iterate in reverse order as we are removing items
@@ -3243,7 +3242,7 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T>
View child = container.getChildAt(i);
ItemInfo info = (ItemInfo) child.getTag();
if (matcher.matchesInfo(info)) {
if (matcher.test(info)) {
layout.removeViewInLayout(child);
if (child instanceof DropTarget) {
mDragController.removeDropTarget((DropTarget) child);
@@ -3251,7 +3250,7 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T>
} else if (child instanceof FolderIcon) {
FolderInfo folderInfo = (FolderInfo) info;
List<WorkspaceItemInfo> matches = folderInfo.contents.stream()
.filter(matcher::matchesInfo)
.filter(matcher)
.collect(Collectors.toList());
if (!matches.isEmpty()) {
folderInfo.removeAll(matches, false);
@@ -3330,7 +3329,7 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T>
*
* @param matcher the matcher generated by the caller.
*/
public void persistRemoveItemsByMatcher(ItemInfoMatcher matcher) {
public void persistRemoveItemsByMatcher(Predicate<ItemInfo> matcher) {
mLauncher.getModelWriter().deleteItemsFromDatabase(matcher);
removeItemsByMatcher(matcher);
}
@@ -190,6 +190,7 @@ public class AllAppsTransitionController
public void setProgress(float progress) {
mProgress = progress;
getAppsViewProgressTranslationY().set(mAppsView, mProgress * mShiftRange);
mLauncher.onAllAppsTransition(1 - progress);
}
public float getProgress() {
@@ -254,8 +255,6 @@ public class AllAppsTransitionController
anim.setInterpolator(verticalProgressInterpolator);
anim.addListener(getProgressAnimatorListener());
builder.add(anim);
// Use ANIM_VERTICAL_PROGRESS's interpolator to determine state transition threshold.
builder.setInterpolator(verticalProgressInterpolator);
setAlphas(toState, config, builder);
@@ -21,17 +21,18 @@ import android.content.Context;
import com.android.launcher3.allapps.BaseAllAppsAdapter.AdapterItem;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.util.LabelComparator;
import com.android.launcher3.views.ActivityContext;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.TreeMap;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* The alphabetically sorted list of applications.
@@ -82,7 +83,7 @@ public class AlphabeticalAppsList<T extends Context & ActivityContext> implement
private AppInfoComparator mAppNameComparator;
private final int mNumAppsPerRowAllApps;
private int mNumAppRowsInAdapter;
private ItemInfoMatcher mItemFilter;
private Predicate<ItemInfo> mItemFilter;
public AlphabeticalAppsList(Context context, AllAppsStore appsStore,
WorkAdapterProvider adapterProvider) {
@@ -94,7 +95,7 @@ public class AlphabeticalAppsList<T extends Context & ActivityContext> implement
mAllAppsStore.addUpdateListener(this);
}
public void updateItemFilter(ItemInfoMatcher itemFilter) {
public void updateItemFilter(Predicate<ItemInfo> itemFilter) {
this.mItemFilter = itemFilter;
onAppsUpdated();
}
@@ -200,13 +201,11 @@ public class AlphabeticalAppsList<T extends Context & ActivityContext> implement
// Sort the list of apps
mApps.clear();
for (AppInfo app : mAllAppsStore.getApps()) {
if (mItemFilter == null || mItemFilter.matches(app, null) || hasFilter()) {
mApps.add(app);
}
Stream<AppInfo> appSteam = Stream.of(mAllAppsStore.getApps());
if (!hasFilter() && mItemFilter != null) {
appSteam = appSteam.filter(mItemFilter);
}
Collections.sort(mApps, mAppNameComparator);
appSteam = appSteam.sorted(mAppNameComparator);
// As a special case for some languages (currently only Simplified Chinese), we may need to
// coalesce sections
@@ -215,27 +214,16 @@ public class AlphabeticalAppsList<T extends Context & ActivityContext> implement
if (localeRequiresSectionSorting) {
// Compute the section headers. We use a TreeMap with the section name comparator to
// ensure that the sections are ordered when we iterate over it later
TreeMap<String, ArrayList<AppInfo>> sectionMap = new TreeMap<>(new LabelComparator());
for (AppInfo info : mApps) {
// Add the section to the cache
String sectionName = info.sectionName;
// Add it to the mapping
ArrayList<AppInfo> sectionApps = sectionMap.get(sectionName);
if (sectionApps == null) {
sectionApps = new ArrayList<>();
sectionMap.put(sectionName, sectionApps);
}
sectionApps.add(info);
}
// Add each of the section apps to the list in order
mApps.clear();
for (Map.Entry<String, ArrayList<AppInfo>> entry : sectionMap.entrySet()) {
mApps.addAll(entry.getValue());
}
appSteam = appSteam.collect(Collectors.groupingBy(
info -> info.sectionName,
() -> new TreeMap<>(new LabelComparator()),
Collectors.toCollection(ArrayList::new)))
.values()
.stream()
.flatMap(ArrayList::stream);
}
appSteam.forEachOrdered(mApps::add);
// Recompose the set of adapter items from the current set of apps
if (mSearchResults.isEmpty()) {
updateAdapterItems();
@@ -58,7 +58,7 @@ import com.android.launcher3.Utilities;
import com.android.launcher3.allapps.search.SearchAdapterProvider;
import com.android.launcher3.keyboard.FocusedItemDecorator;
import com.android.launcher3.model.StringCache;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.ActivityContext;
@@ -69,6 +69,8 @@ import com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip.OnActivePag
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Stream;
/**
* Base all apps view container.
@@ -91,7 +93,7 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte
/** Context of an activity or window that is inflating this container. */
protected final T mActivityContext;
protected final List<AdapterHolder> mAH;
protected final ItemInfoMatcher mPersonalMatcher = ItemInfoMatcher.ofUser(
protected final Predicate<ItemInfo> mPersonalMatcher = ItemInfoMatcher.ofUser(
Process.myUserHandle());
private final SearchAdapterProvider<?> mMainAdapterProvider;
private final AllAppsStore mAllAppsStore = new AllAppsStore();
@@ -229,17 +231,10 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte
}
private void onAppsUpdated() {
boolean hasWorkApps = false;
for (AppInfo app : mAllAppsStore.getApps()) {
if (mWorkManager.getMatcher().matches(app, null)) {
hasWorkApps = true;
break;
}
}
mHasWorkApps = hasWorkApps;
mHasWorkApps = Stream.of(mAllAppsStore.getApps()).anyMatch(mWorkManager.getMatcher());
if (!mAH.get(AdapterHolder.MAIN).mAppsList.hasFilter()) {
rebindAdapters();
if (hasWorkApps) {
if (mHasWorkApps) {
mWorkManager.reset();
}
}
@@ -731,7 +726,7 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte
mLayoutManager = adapter.getLayoutManager();
}
void setup(@NonNull View rv, @Nullable ItemInfoMatcher matcher) {
void setup(@NonNull View rv, @Nullable Predicate<ItemInfo> matcher) {
mAppsList.updateItemFilter(matcher);
mRecyclerView = (AllAppsRecyclerView) rv;
mRecyclerView.setEdgeEffectFactory(createEdgeEffectFactory());
@@ -27,7 +27,6 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.util.Log;
import android.view.ViewGroup;
import android.view.WindowInsets;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
@@ -35,11 +34,12 @@ import androidx.annotation.RequiresApi;
import com.android.launcher3.R;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.function.Predicate;
/**
* Companion class for {@link BaseAllAppsContainerView} to manage work tab and personal tab
@@ -70,7 +70,7 @@ public class WorkProfileManager implements PersonalWorkSlidingTabStrip.OnActiveP
private final BaseAllAppsContainerView<?> mAllApps;
private final WorkAdapterProvider mAdapterProvider;
private final ItemInfoMatcher mMatcher;
private final Predicate<ItemInfo> mMatcher;
private WorkModeSwitch mWorkModeSwitch;
@@ -176,7 +176,7 @@ public class WorkProfileManager implements PersonalWorkSlidingTabStrip.OnActiveP
return mAdapterProvider;
}
public ItemInfoMatcher getMatcher() {
public Predicate<ItemInfo> getMatcher() {
return mMatcher;
}
@@ -47,13 +47,6 @@ public class Interpolators {
public static final Interpolator DEACCEL_2_5 = new DecelerateInterpolator(2.5f);
public static final Interpolator DEACCEL_3 = new DecelerateInterpolator(3f);
/**
* The decelerating emphasized interpolator. Used for hero / emphasized movement of content that
* is appearing e.g. when coming from off screen
*/
public static final Interpolator EMPHASIZED_DECELERATE = new PathInterpolator(
0.05f, 0.7f, 0.1f, 1f);
public static final Interpolator ACCEL_DEACCEL = new AccelerateDecelerateInterpolator();
public static final Interpolator FAST_OUT_SLOW_IN = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
@@ -18,7 +18,6 @@ package com.android.launcher3.dragndrop;
import static com.android.launcher3.Utilities.ATLEAST_Q;
import android.content.ComponentName;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
@@ -36,12 +35,12 @@ import com.android.launcher3.logging.InstanceId;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.TouchController;
import com.android.launcher3.views.ActivityContext;
import java.util.ArrayList;
import java.util.Optional;
import java.util.function.Predicate;
/**
* Class for initiating a drag within a view or across multiple views.
@@ -275,15 +274,12 @@ public abstract class DragController<T extends ActivityContext>
protected abstract void exitDrag();
public void onAppsRemoved(ItemInfoMatcher matcher) {
public void onAppsRemoved(Predicate<ItemInfo> matcher) {
// Cancel the current drag if we are removing an app that we are dragging
if (mDragObject != null) {
ItemInfo dragInfo = mDragObject.dragInfo;
if (dragInfo instanceof WorkspaceItemInfo) {
ComponentName cn = dragInfo.getTargetComponent();
if (cn != null && matcher.matches(dragInfo, cn)) {
cancelDrag();
}
if (dragInfo instanceof WorkspaceItemInfo && matcher.test(dragInfo)) {
cancelDrag();
}
}
}
@@ -87,7 +87,8 @@ class PinShortcutRequestActivityInfo extends ShortcutConfigActivityInfo {
// Total duration for the drop animation to complete.
long duration = mContext.getResources().getInteger(R.integer.config_dropAnimMaxDuration) +
LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY +
LauncherState.SPRING_LOADED.getTransitionDuration(Launcher.getLauncher(mContext));
LauncherState.SPRING_LOADED.getTransitionDuration(Launcher.getLauncher(mContext),
true /* isToState */);
// Delay the actual accept() call until the drop animation is complete.
return PinRequestHelper.createWorkspaceItemFromPinItemRequest(
mContext, mRequest, duration);
@@ -36,9 +36,9 @@ import com.android.launcher3.compat.AlphabeticIndexCompat;
import com.android.launcher3.icons.IconCache;
import com.android.launcher3.model.BgDataModel.Callbacks;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.pm.PackageInstallInfo;
import com.android.launcher3.util.FlagOp;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.SafeCloseable;
@@ -47,6 +47,7 @@ import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;
/**
@@ -257,11 +258,11 @@ public class AllAppsList {
/**
* Updates the disabled flags of apps matching {@param matcher} based on {@param op}.
*/
public void updateDisabledFlags(ItemInfoMatcher matcher, FlagOp op) {
public void updateDisabledFlags(Predicate<ItemInfo> matcher, FlagOp op) {
final List<AppInfo> data = this.data;
for (int i = data.size() - 1; i >= 0; i--) {
AppInfo info = data.get(i);
if (matcher.matches(info, info.componentName)) {
if (matcher.test(info)) {
info.runtimeStatusFlags = op.apply(info.runtimeStatusFlags);
mDataChanged = true;
}
@@ -27,7 +27,6 @@ import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.widget.model.WidgetsListBaseEntry;
import java.util.ArrayList;
@@ -35,6 +34,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.function.Predicate;
import java.util.stream.Collectors;
/**
@@ -128,7 +128,7 @@ public abstract class BaseModelUpdateTask implements ModelUpdateTask {
scheduleCallbackTask(c -> c.bindAllWidgets(widgets));
}
public void deleteAndBindComponentsRemoved(final ItemInfoMatcher matcher) {
public void deleteAndBindComponentsRemoved(final Predicate<ItemInfo> matcher) {
getModelWriter().deleteItemsFromDatabase(matcher);
// Call the components-removed callback
@@ -50,7 +50,6 @@ import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.IntSparseArrayMap;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.RunnableList;
import com.android.launcher3.widget.model.WidgetsListBaseEntry;
@@ -66,6 +65,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -495,7 +495,7 @@ public class BgDataModel {
default void bindWorkspaceItemsChanged(List<WorkspaceItemInfo> updated) { }
default void bindWidgetsRestored(ArrayList<LauncherAppWidgetInfo> widgets) { }
default void bindRestoreItemsChange(HashSet<ItemInfo> updates) { }
default void bindWorkspaceComponentsRemoved(ItemInfoMatcher matcher) { }
default void bindWorkspaceComponentsRemoved(Predicate<ItemInfo> matcher) { }
default void bindAllWidgets(List<WidgetsListBaseEntry> widgets) { }
default void onInitialBindComplete(IntSet boundPages, RunnableList pendingTasks) {
@@ -53,6 +53,7 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
@@ -278,10 +279,9 @@ public class ModelWriter {
/**
* Removes all the items from the database matching {@param matcher}.
*/
public void deleteItemsFromDatabase(ItemInfoMatcher matcher) {
public void deleteItemsFromDatabase(Predicate<ItemInfo> matcher) {
deleteItemsFromDatabase(StreamSupport.stream(mBgDataModel.itemsIdMap.spliterator(), false)
.filter(matcher::matchesInfo)
.collect(Collectors.toList()));
.filter(matcher).collect(Collectors.toList()));
}
/**
@@ -57,6 +57,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.function.Predicate;
/**
* Handles updates due to changes in package manager (app installed/updated/removed)
@@ -95,7 +96,7 @@ public class PackageUpdatedTask extends BaseModelUpdateTask {
final int N = packages.length;
final FlagOp flagOp;
final HashSet<String> packageSet = new HashSet<>(Arrays.asList(packages));
final ItemInfoMatcher matcher = mOp == OP_USER_AVAILABILITY_CHANGE
final Predicate<ItemInfo> matcher = mOp == OP_USER_AVAILABILITY_CHANGE
? ItemInfoMatcher.ofUser(mUser) // We want to update all packages for this user
: ItemInfoMatcher.ofPackages(packageSet, mUser);
final HashSet<ComponentName> removedComponents = new HashSet<>();
@@ -206,7 +207,7 @@ public class PackageUpdatedTask extends BaseModelUpdateTask {
}
ComponentName cn = si.getTargetComponent();
if (cn != null && matcher.matches(si, cn)) {
if (cn != null && matcher.test(si)) {
String packageName = cn.getPackageName();
if (si.hasStatusFlag(WorkspaceItemInfo.FLAG_SUPPORTS_WEB_UI)) {
@@ -336,7 +337,7 @@ public class PackageUpdatedTask extends BaseModelUpdateTask {
}
if (!removedPackages.isEmpty() || !removedComponents.isEmpty()) {
ItemInfoMatcher removeMatch = ItemInfoMatcher.ofPackages(removedPackages, mUser)
Predicate<ItemInfo> removeMatch = ItemInfoMatcher.ofPackages(removedPackages, mUser)
.or(ItemInfoMatcher.ofComponents(removedComponents, mUser))
.and(ItemInfoMatcher.ofItemIds(forceKeepShortcuts).negate());
deleteAndBindComponentsRemoved(removeMatch);
@@ -36,7 +36,7 @@ public interface BaseState<T extends BaseState> {
/**
* @return How long the animation to this state should take (or from this state to NORMAL).
*/
int getTransitionDuration(Context context);
int getTransitionDuration(Context context, boolean isToState);
/**
* Returns the state to go back to from this state
@@ -253,8 +253,8 @@ public class StateManager<STATE_TYPE extends BaseState<STATE_TYPE>> {
// Since state mBaseState can be reached from multiple states, just assume that the
// transition plays in reverse and use the same duration as previous state.
mConfig.duration = state == mBaseState
? fromState.getTransitionDuration(mActivity)
: state.getTransitionDuration(mActivity);
? fromState.getTransitionDuration(mActivity, false /* isToState */)
: state.getTransitionDuration(mActivity, true /* isToState */);
prepareForAtomicAnimation(fromState, state, mConfig);
AnimatorSet animation = createAnimationToNewWorkspaceInternal(state).buildAnim();
if (listener != null) {
@@ -43,7 +43,7 @@ public class HintState extends LauncherState {
}
@Override
public int getTransitionDuration(Context context) {
public int getTransitionDuration(Context context, boolean isToState) {
return 80;
}
@@ -39,7 +39,7 @@ public class SpringLoadedState extends LauncherState {
}
@Override
public int getTransitionDuration(Context context) {
public int getTransitionDuration(Context context, boolean isToState) {
return 150;
}
@@ -19,6 +19,8 @@ package com.android.launcher3.util;
import android.content.ComponentName;
import android.os.UserHandle;
import androidx.annotation.NonNull;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
@@ -27,90 +29,64 @@ import com.android.launcher3.shortcuts.ShortcutKey;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Predicate;
/**
* A utility class to check for {@link ItemInfo}
*/
public interface ItemInfoMatcher {
public abstract class ItemInfoMatcher {
/**
* Empty component used for match testing
*/
ComponentName EMPTY_COMPONENT = new ComponentName("", "");
private static final ComponentName EMPTY_COMPONENT = new ComponentName("", "");
boolean matches(ItemInfo info, ComponentName cn);
/**
* Returns true if the itemInfo matches this check
*/
default boolean matchesInfo(ItemInfo info) {
if (info != null) {
ComponentName cn = info.getTargetComponent();
return matches(info, cn != null ? cn : EMPTY_COMPONENT);
} else {
return false;
}
public static Predicate<ItemInfo> ofUser(UserHandle user) {
return info -> info != null && info.user.equals(user);
}
/**
* Returns a new matcher with returns true if either this or {@param matcher} returns true.
*/
default ItemInfoMatcher or(ItemInfoMatcher matcher) {
return (info, cn) -> matches(info, cn) || matcher.matches(info, cn);
public static Predicate<ItemInfo> ofComponents(
HashSet<ComponentName> components, UserHandle user) {
return info -> info != null && info.user.equals(user)
&& components.contains(getNonNullComponent(info));
}
/**
* Returns a new matcher with returns true if both this and {@param matcher} returns true.
*/
default ItemInfoMatcher and(ItemInfoMatcher matcher) {
return (info, cn) -> matches(info, cn) && matcher.matches(info, cn);
public static Predicate<ItemInfo> ofPackages(Set<String> packageNames, UserHandle user) {
return info -> info != null && info.user.equals(user)
&& packageNames.contains(getNonNullComponent(info).getPackageName());
}
/**
* Returns a new matcher with returns the opposite value of this.
*/
default ItemInfoMatcher negate() {
return (info, cn) -> !matches(info, cn);
}
static ItemInfoMatcher ofUser(UserHandle user) {
return (info, cn) -> info.user.equals(user);
}
static ItemInfoMatcher ofComponents(HashSet<ComponentName> components, UserHandle user) {
return (info, cn) -> components.contains(cn) && info.user.equals(user);
}
static ItemInfoMatcher ofPackages(Set<String> packageNames, UserHandle user) {
return (info, cn) -> packageNames.contains(cn.getPackageName()) && info.user.equals(user);
}
static ItemInfoMatcher ofShortcutKeys(Set<ShortcutKey> keys) {
return (info, cn) -> info.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT
public static Predicate<ItemInfo> ofShortcutKeys(Set<ShortcutKey> keys) {
return info -> info != null && info.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT
&& keys.contains(ShortcutKey.fromItemInfo(info));
}
/**
* Returns a matcher for items within folders.
*/
static ItemInfoMatcher forFolderMatch(ItemInfoMatcher childOperator) {
return (info, cn) -> info instanceof FolderInfo && ((FolderInfo) info).contents.stream()
.anyMatch(childOperator::matchesInfo);
public static Predicate<ItemInfo> forFolderMatch(Predicate<ItemInfo> childOperator) {
return info -> info instanceof FolderInfo && ((FolderInfo) info).contents.stream()
.anyMatch(childOperator);
}
/**
* Returns a matcher for items with provided ids
*/
static ItemInfoMatcher ofItemIds(IntSet ids) {
return (info, cn) -> ids.contains(info.id);
public static Predicate<ItemInfo> ofItemIds(IntSet ids) {
return info -> info != null && ids.contains(info.id);
}
/**
* Returns a matcher for items with provided items
*/
static ItemInfoMatcher ofItems(Collection<? extends ItemInfo> items) {
public static Predicate<ItemInfo> ofItems(Collection<? extends ItemInfo> items) {
IntSet ids = new IntSet();
items.forEach(item -> ids.add(item.id));
return ofItemIds(ids);
}
private static ComponentName getNonNullComponent(@NonNull ItemInfo info) {
ComponentName cn = info.getTargetComponent();
return cn != null ? cn : EMPTY_COMPONENT;
}
}
@@ -22,6 +22,9 @@ import static com.android.launcher3.ResourceUtils.INVALID_RESOURCE_HANDLE;
import static com.android.launcher3.ResourceUtils.NAVBAR_HEIGHT;
import static com.android.launcher3.ResourceUtils.NAVBAR_HEIGHT_LANDSCAPE;
import static com.android.launcher3.ResourceUtils.NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE;
import static com.android.launcher3.ResourceUtils.STATUS_BAR_HEIGHT;
import static com.android.launcher3.ResourceUtils.STATUS_BAR_HEIGHT_LANDSCAPE;
import static com.android.launcher3.ResourceUtils.STATUS_BAR_HEIGHT_PORTRAIT;
import static com.android.launcher3.Utilities.dpiFromPx;
import static com.android.launcher3.util.MainThreadInitializedObject.forOverride;
import static com.android.launcher3.util.RotationUtils.deltaRotation;
@@ -152,20 +155,26 @@ public class WindowManagerProxy implements ResourceBasedOverride {
boolean isTablet = config.smallestScreenWidthDp > MIN_TABLET_WIDTH;
boolean isGesture = isGestureNav(context);
boolean isPortrait = config.screenHeightDp > config.screenWidthDp;
int bottomNav = isTablet
? 0
: (config.screenHeightDp > config.screenWidthDp
? getDimenByName(NAVBAR_HEIGHT, systemRes)
: (isPortrait
? getDimenByName(systemRes, NAVBAR_HEIGHT)
: (isGesture
? getDimenByName(NAVBAR_HEIGHT_LANDSCAPE, systemRes)
? getDimenByName(systemRes, NAVBAR_HEIGHT_LANDSCAPE)
: 0));
Insets newNavInsets = Insets.of(navInsets.left, navInsets.top, navInsets.right, bottomNav);
insetsBuilder.setInsets(WindowInsets.Type.navigationBars(), newNavInsets);
insetsBuilder.setInsetsIgnoringVisibility(WindowInsets.Type.navigationBars(), newNavInsets);
Insets statusBarInsets = oldInsets.getInsets(WindowInsets.Type.statusBars());
int statusBarHeight = getDimenByName("status_bar_height", systemRes);
int statusBarHeight = getDimenByName(systemRes,
(isPortrait) ? STATUS_BAR_HEIGHT_PORTRAIT : STATUS_BAR_HEIGHT_LANDSCAPE,
STATUS_BAR_HEIGHT);
Insets newStatusBarInsets = Insets.of(
statusBarInsets.left,
Math.max(statusBarInsets.top, statusBarHeight),
@@ -221,23 +230,26 @@ public class WindowManagerProxy implements ResourceBasedOverride {
boolean isTabletOrGesture = isTablet
|| (Utilities.ATLEAST_R && isGestureNav(context));
int statusBarHeight = getDimenByName("status_bar_height", systemRes);
int statusBarHeightPortrait = getDimenByName(systemRes,
STATUS_BAR_HEIGHT_PORTRAIT, STATUS_BAR_HEIGHT);
int statusBarHeightLandscape = getDimenByName(systemRes,
STATUS_BAR_HEIGHT_LANDSCAPE, STATUS_BAR_HEIGHT);
int navBarHeightPortrait, navBarHeightLandscape, navbarWidthLandscape;
navBarHeightPortrait = isTablet
? (mTaskbarDrawnInProcess
? 0 : systemRes.getDimensionPixelSize(R.dimen.taskbar_size))
: getDimenByName(NAVBAR_HEIGHT, systemRes);
: getDimenByName(systemRes, NAVBAR_HEIGHT);
navBarHeightLandscape = isTablet
? (mTaskbarDrawnInProcess
? 0 : systemRes.getDimensionPixelSize(R.dimen.taskbar_size))
: (isTabletOrGesture
? getDimenByName(NAVBAR_HEIGHT_LANDSCAPE, systemRes) : 0);
? getDimenByName(systemRes, NAVBAR_HEIGHT_LANDSCAPE) : 0);
navbarWidthLandscape = isTabletOrGesture
? 0
: getDimenByName(NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE, systemRes);
: getDimenByName(systemRes, NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE);
WindowBounds[] result = new WindowBounds[4];
Point tempSize = new Point();
@@ -247,13 +259,15 @@ public class WindowManagerProxy implements ResourceBasedOverride {
rotateSize(tempSize, rotationChange);
Rect bounds = new Rect(0, 0, tempSize.x, tempSize.y);
int navBarHeight, navbarWidth;
int navBarHeight, navbarWidth, statusBarHeight;
if (tempSize.y > tempSize.x) {
navBarHeight = navBarHeightPortrait;
navbarWidth = 0;
statusBarHeight = statusBarHeightPortrait;
} else {
navBarHeight = navBarHeightLandscape;
navbarWidth = navbarWidthLandscape;
statusBarHeight = statusBarHeightLandscape;
}
Rect insets = new Rect(safeCutout);
@@ -276,10 +290,18 @@ public class WindowManagerProxy implements ResourceBasedOverride {
/**
* Wrapper around the utility method for easier emulation
*/
protected int getDimenByName(String resName, Resources res) {
protected int getDimenByName(Resources res, String resName) {
return ResourceUtils.getDimenByName(resName, res, 0);
}
/**
* Wrapper around the utility method for easier emulation
*/
protected int getDimenByName(Resources res, String resName, String fallback) {
int dimen = ResourceUtils.getDimenByName(resName, res, -1);
return dimen > -1 ? dimen : getDimenByName(res, fallback);
}
protected boolean isGestureNav(Context context) {
return ResourceUtils.getIntegerByName("config_navBarInteractionMode",
context.getResources(), INVALID_RESOURCE_HANDLE) == 2;
@@ -231,13 +231,17 @@ public abstract class AbstractSlideInView<T extends Context & ActivityContext>
if (mSwipeDetector.isIdleState()) {
mOpenCloseAnimator
.setDuration(defaultDuration)
.setInterpolator(Interpolators.ACCEL);
.setInterpolator(getIdleInterpolator());
} else {
mOpenCloseAnimator.setInterpolator(mScrollInterpolator);
}
mOpenCloseAnimator.start();
}
protected Interpolator getIdleInterpolator() {
return Interpolators.ACCEL;
}
protected void onCloseComplete() {
mIsOpen = false;
getPopupContainer().removeView(this);
@@ -44,6 +44,7 @@ import com.android.launcher3.touch.ItemLongClickListener;
import com.android.launcher3.util.SystemUiController;
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.AbstractSlideInView;
import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.views.ArrowTipView;
/**
@@ -306,4 +307,11 @@ public abstract class BaseWidgetSheet extends AbstractSlideInView<Launcher>
return mActivityContext.getSharedPrefs().getBoolean(KEY_WIDGETS_EDUCATION_TIP_SEEN, false)
|| Utilities.IS_RUNNING_IN_TEST_HARNESS;
}
@Override
protected void setTranslationShift(float translationShift) {
super.setTranslationShift(translationShift);
Launcher launcher = ActivityContext.lookupContext(getContext());
launcher.onWidgetsTransition(1 - translationShift);
}
}
@@ -39,8 +39,8 @@ public class AllAppsState extends LauncherState {
}
@Override
public int getTransitionDuration(Context context) {
return 320;
public int getTransitionDuration(Context context, boolean isToState) {
return isToState ? 500 : 300;
}
@Override
@@ -34,7 +34,7 @@ public class OverviewState extends LauncherState {
}
@Override
public int getTransitionDuration(Context context) {
public int getTransitionDuration(Context context, boolean isToState) {
return 250;
}
@@ -43,9 +43,14 @@ public class TestWindowManagerProxy extends WindowManagerProxy {
}
@Override
protected int getDimenByName(String resName, Resources res) {
protected int getDimenByName(Resources res, String resName) {
Integer mock = mDevice.resourceOverrides.get(resName);
return mock != null ? mock : super.getDimenByName(resName, res);
return mock != null ? mock : super.getDimenByName(res, resName);
}
@Override
protected int getDimenByName(Resources res, String resName, String fallback) {
return getDimenByName(res, resName);
}
@Override