mirror of
https://github.com/LawnchairLauncher/lawnchair.git
synced 2026-02-28 07:46:55 +00:00
Merge "Play return to icon animation if user swipes back to All Apps." into sc-v2-dev
This commit is contained in:
@@ -1214,14 +1214,14 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns view on the workspace that corresponds to the closing app in the list of app targets
|
||||
* Returns view on launcher that corresponds to the closing app in the list of app targets
|
||||
*/
|
||||
private @Nullable View findWorkspaceView(RemoteAnimationTargetCompat[] appTargets) {
|
||||
private @Nullable View findLauncherView(RemoteAnimationTargetCompat[] appTargets) {
|
||||
for (RemoteAnimationTargetCompat appTarget : appTargets) {
|
||||
if (appTarget.mode == MODE_CLOSING) {
|
||||
View workspaceView = findWorkspaceView(appTarget);
|
||||
if (workspaceView != null) {
|
||||
return workspaceView;
|
||||
View launcherView = findLauncherView(appTarget);
|
||||
if (launcherView != null) {
|
||||
return launcherView;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1229,9 +1229,9 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns view on the workspace that corresponds to the {@param runningTaskTarget}.
|
||||
* Returns view on launcher that corresponds to the {@param runningTaskTarget}.
|
||||
*/
|
||||
private @Nullable View findWorkspaceView(RemoteAnimationTargetCompat runningTaskTarget) {
|
||||
private @Nullable View findLauncherView(RemoteAnimationTargetCompat runningTaskTarget) {
|
||||
if (runningTaskTarget == null || runningTaskTarget.taskInfo == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -1269,7 +1269,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
|
||||
}
|
||||
}
|
||||
|
||||
return mLauncher.getWorkspace().getFirstMatchForAppClose(launchCookieItemId,
|
||||
return mLauncher.getFirstMatchForAppClose(launchCookieItemId,
|
||||
packageName, UserHandle.of(runningTaskTarget.taskInfo.userId));
|
||||
}
|
||||
|
||||
@@ -1292,7 +1292,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
|
||||
* Closing animator that animates the window into its final location on the workspace.
|
||||
*/
|
||||
private void getClosingWindowAnimators(AnimatorSet animation,
|
||||
RemoteAnimationTargetCompat[] targets, View workspaceView) {
|
||||
RemoteAnimationTargetCompat[] targets, View launcherView, PointF velocityPxPerS) {
|
||||
FloatingIconView floatingIconView = null;
|
||||
FloatingWidgetView floatingWidget = null;
|
||||
RectF targetRect = new RectF();
|
||||
@@ -1308,17 +1308,17 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
|
||||
}
|
||||
|
||||
// Get floating view and target rect.
|
||||
if (workspaceView instanceof LauncherAppWidgetHostView) {
|
||||
if (launcherView instanceof LauncherAppWidgetHostView) {
|
||||
Size windowSize = new Size(mDeviceProfile.availableWidthPx,
|
||||
mDeviceProfile.availableHeightPx);
|
||||
int fallbackBackgroundColor =
|
||||
FloatingWidgetView.getDefaultBackgroundColor(mLauncher, runningTaskTarget);
|
||||
floatingWidget = FloatingWidgetView.getFloatingWidgetView(mLauncher,
|
||||
(LauncherAppWidgetHostView) workspaceView, targetRect, windowSize,
|
||||
(LauncherAppWidgetHostView) launcherView, targetRect, windowSize,
|
||||
mDeviceProfile.isMultiWindowMode ? 0 : getWindowCornerRadius(mLauncher),
|
||||
isTransluscent, fallbackBackgroundColor);
|
||||
} else if (workspaceView != null) {
|
||||
floatingIconView = getFloatingIconView(mLauncher, workspaceView,
|
||||
} else if (launcherView != null) {
|
||||
floatingIconView = getFloatingIconView(mLauncher, launcherView,
|
||||
true /* hideOriginal */, targetRect, false /* isOpening */);
|
||||
} else {
|
||||
targetRect.set(getDefaultWindowTargetRect());
|
||||
@@ -1373,15 +1373,10 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
|
||||
}
|
||||
|
||||
// Use a fixed velocity to start the animation.
|
||||
float velocityPxPerS = DynamicResource.provider(mLauncher)
|
||||
.getDimension(R.dimen.unlock_staggered_velocity_dp_per_s);
|
||||
PointF velocity = new PointF(0, -velocityPxPerS);
|
||||
animation.play(new StaggeredWorkspaceAnim(mLauncher, velocity.y,
|
||||
true /* animateOverviewScrim */, workspaceView).getAnimators());
|
||||
animation.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
anim.start(mLauncher, velocity);
|
||||
anim.start(mLauncher, velocityPxPerS);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1556,22 +1551,30 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
|
||||
if (anim == null) {
|
||||
anim = new AnimatorSet();
|
||||
|
||||
View workspaceView = findWorkspaceView(appTargets);
|
||||
boolean isWorkspaceViewVisible = workspaceView != null
|
||||
&& !mLauncher.isInState(LauncherState.ALL_APPS)
|
||||
&& !mLauncher.getWorkspace().isOverlayShown();
|
||||
boolean playFallBackAnimation = !isWorkspaceViewVisible
|
||||
&& (launcherIsATargetWithMode(appTargets, MODE_OPENING)
|
||||
|| mLauncher.isForceInvisible());
|
||||
final boolean launcherIsForceInvisibleOrOpening = mLauncher.isForceInvisible()
|
||||
|| launcherIsATargetWithMode(appTargets, MODE_OPENING);
|
||||
|
||||
View launcherView = findLauncherView(appTargets);
|
||||
boolean playFallBackAnimation = (launcherView == null
|
||||
&& launcherIsForceInvisibleOrOpening)
|
||||
|| mLauncher.getWorkspace().isOverlayShown();
|
||||
|
||||
boolean playWorkspaceReveal = true;
|
||||
if (mFromUnlock) {
|
||||
anim.play(getUnlockWindowAnimator(appTargets, wallpaperTargets));
|
||||
} else if (ENABLE_BACK_SWIPE_HOME_ANIMATION.get()
|
||||
&& !playFallBackAnimation) {
|
||||
getClosingWindowAnimators(anim, appTargets, workspaceView);
|
||||
// We play StaggeredWorkspaceAnim as a part of the closing window animation.
|
||||
playWorkspaceReveal = false;
|
||||
// Use a fixed velocity to start the animation.
|
||||
float velocityPxPerS = DynamicResource.provider(mLauncher)
|
||||
.getDimension(R.dimen.unlock_staggered_velocity_dp_per_s);
|
||||
PointF velocity = new PointF(0, -velocityPxPerS);
|
||||
getClosingWindowAnimators(anim, appTargets, launcherView, velocity);
|
||||
if (!mLauncher.isInState(LauncherState.ALL_APPS)) {
|
||||
anim.play(new StaggeredWorkspaceAnim(mLauncher, velocity.y,
|
||||
true /* animateOverviewScrim */, launcherView).getAnimators());
|
||||
// We play StaggeredWorkspaceAnim as a part of the closing window animation.
|
||||
playWorkspaceReveal = false;
|
||||
}
|
||||
} else {
|
||||
anim.play(getFallbackClosingWindowAnimators(appTargets));
|
||||
}
|
||||
@@ -1584,8 +1587,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
|
||||
// targets list because it is already visible). In that case, we force
|
||||
// invisibility on touch down, and only reset it after the animation to home
|
||||
// is initialized.
|
||||
if (launcherIsATargetWithMode(appTargets, MODE_OPENING)
|
||||
|| mLauncher.isForceInvisible()) {
|
||||
if (launcherIsForceInvisibleOrOpening) {
|
||||
addCujInstrumentation(
|
||||
anim, InteractionJankMonitorWrapper.CUJ_APP_CLOSE_TO_HOME);
|
||||
// Only register the content animation for cancellation when state changes
|
||||
|
||||
@@ -244,7 +244,7 @@ public class LauncherSwipeHandlerV2 extends
|
||||
}
|
||||
}
|
||||
|
||||
return mActivity.getWorkspace().getFirstMatchForAppClose(launchCookieItemId,
|
||||
return mActivity.getFirstMatchForAppClose(launchCookieItemId,
|
||||
runningTaskView.getTask().key.getComponent().getPackageName(),
|
||||
UserHandle.of(runningTaskView.getTask().key.userId));
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import static com.android.launcher3.AbstractFloatingView.TYPE_REBIND_SAFE;
|
||||
import static com.android.launcher3.AbstractFloatingView.TYPE_SNACKBAR;
|
||||
import static com.android.launcher3.AbstractFloatingView.getTopOpenViewWithType;
|
||||
import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
|
||||
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
|
||||
import static com.android.launcher3.LauncherState.ALL_APPS;
|
||||
import static com.android.launcher3.LauncherState.FLAG_CLOSE_POPUPS;
|
||||
import static com.android.launcher3.LauncherState.FLAG_MULTI_PAGE;
|
||||
@@ -39,6 +40,7 @@ import static com.android.launcher3.LauncherState.NO_SCALE;
|
||||
import static com.android.launcher3.LauncherState.SPRING_LOADED;
|
||||
import static com.android.launcher3.Utilities.postAsyncCallback;
|
||||
import static com.android.launcher3.accessibility.LauncherAccessibilityDelegate.getSupportedActions;
|
||||
import static com.android.launcher3.config.FeatureFlags.ADAPTIVE_ICON_WINDOW_ANIM;
|
||||
import static com.android.launcher3.dragndrop.DragLayer.ALPHA_INDEX_LAUNCHER_LOAD;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME;
|
||||
@@ -55,6 +57,7 @@ import static com.android.launcher3.popup.SystemShortcut.INSTALL;
|
||||
import static com.android.launcher3.popup.SystemShortcut.WIDGETS;
|
||||
import static com.android.launcher3.states.RotationHelper.REQUEST_LOCK;
|
||||
import static com.android.launcher3.states.RotationHelper.REQUEST_NONE;
|
||||
import static com.android.launcher3.util.ItemInfoMatcher.forFolderMatch;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
@@ -90,6 +93,7 @@ import android.os.Process;
|
||||
import android.os.StrictMode;
|
||||
import android.os.SystemClock;
|
||||
import android.os.Trace;
|
||||
import android.os.UserHandle;
|
||||
import android.text.TextUtils;
|
||||
import android.text.method.TextKeyListener;
|
||||
import android.util.Log;
|
||||
@@ -215,6 +219,7 @@ import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@@ -2674,6 +2679,79 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to {@link #getFirstMatch} but optimized to finding a suitable view for the app close
|
||||
* animation.
|
||||
*
|
||||
* @param preferredItemId The id of the preferred item to match to if it exists.
|
||||
* @param packageName The package name of the app to match.
|
||||
* @param user The user of the app to match.
|
||||
*/
|
||||
public View getFirstMatchForAppClose(int preferredItemId, String packageName, UserHandle user) {
|
||||
final ItemInfoMatcher preferredItem = (info, cn) ->
|
||||
info != null && info.id == preferredItemId;
|
||||
final ItemInfoMatcher packageAndUserAndApp = (info, cn) ->
|
||||
info != null
|
||||
&& info.itemType == ITEM_TYPE_APPLICATION
|
||||
&& info.user.equals(user)
|
||||
&& info.getTargetComponent() != null
|
||||
&& TextUtils.equals(info.getTargetComponent().getPackageName(),
|
||||
packageName);
|
||||
|
||||
if (isInState(LauncherState.ALL_APPS)) {
|
||||
return getFirstMatch(Collections.singletonList(mAppsView.getActiveRecyclerView()),
|
||||
preferredItem, packageAndUserAndApp);
|
||||
} else {
|
||||
List<ViewGroup> containers = new ArrayList<>(mWorkspace.getPanelCount() + 1);
|
||||
containers.add(mWorkspace.getHotseat().getShortcutsAndWidgets());
|
||||
mWorkspace.forEachVisiblePage(page
|
||||
-> containers.add(((CellLayout) page).getShortcutsAndWidgets()));
|
||||
|
||||
// Order: Preferred item by itself or in folder, then by matching package/user
|
||||
if (ADAPTIVE_ICON_WINDOW_ANIM.get()) {
|
||||
return getFirstMatch(containers, preferredItem, forFolderMatch(preferredItem),
|
||||
packageAndUserAndApp, forFolderMatch(packageAndUserAndApp));
|
||||
} else {
|
||||
// Do not use Folder as a criteria, since it'll cause a crash when trying to draw
|
||||
// FolderAdaptiveIcon as the background.
|
||||
return getFirstMatch(containers, preferredItem, packageAndUserAndApp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the first view matching the ordered operators across the given viewgroups in order.
|
||||
* @param containers List of ViewGroups to scan, in order of preference.
|
||||
* @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) {
|
||||
for (ViewGroup container : containers) {
|
||||
View match = mapOverViewGroup(container, operator);
|
||||
if (match != null) {
|
||||
return match;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
final int itemCount = container.getChildCount();
|
||||
for (int itemIdx = 0; itemIdx < itemCount; itemIdx++) {
|
||||
View item = container.getChildAt(itemIdx);
|
||||
if (op.matchesInfo((ItemInfo) item.getTag())) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private ValueAnimator createNewAppBounceAnimation(View v, int i) {
|
||||
ValueAnimator bounceAnim = new PropertyListBuilder().alpha(1).scale(1).build(v)
|
||||
.setDuration(ItemInstallQueue.NEW_SHORTCUT_BOUNCE_DURATION);
|
||||
|
||||
@@ -26,7 +26,6 @@ import static com.android.launcher3.LauncherState.HINT_STATE;
|
||||
import static com.android.launcher3.LauncherState.NORMAL;
|
||||
import static com.android.launcher3.LauncherState.SPRING_LOADED;
|
||||
import static com.android.launcher3.anim.AnimatorListeners.forSuccessCallback;
|
||||
import static com.android.launcher3.config.FeatureFlags.ADAPTIVE_ICON_WINDOW_ANIM;
|
||||
import static com.android.launcher3.dragndrop.DragLayer.ALPHA_INDEX_OVERLAY;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SWIPELEFT;
|
||||
@@ -51,7 +50,6 @@ import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.os.Parcelable;
|
||||
import android.os.UserHandle;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
@@ -3146,62 +3144,6 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
||||
return layouts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to {@link #getFirstMatch} but optimized to finding a suitable view for the app close
|
||||
* animation.
|
||||
*
|
||||
* @param preferredItemId The id of the preferred item to match to if it exists.
|
||||
* @param packageName The package name of the app to match.
|
||||
* @param user The user of the app to match.
|
||||
*/
|
||||
public View getFirstMatchForAppClose(int preferredItemId, String packageName, UserHandle user) {
|
||||
final ItemOperator preferredItem = (ItemInfo info, View view) ->
|
||||
info != null && info.id == preferredItemId;
|
||||
final ItemOperator preferredItemInFolder = (info, view) -> {
|
||||
if (info instanceof FolderInfo) {
|
||||
FolderInfo folderInfo = (FolderInfo) info;
|
||||
for (WorkspaceItemInfo shortcutInfo : folderInfo.contents) {
|
||||
if (preferredItem.evaluate(shortcutInfo, view)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
final ItemOperator packageAndUserAndApp = (ItemInfo info, View view) ->
|
||||
info != null
|
||||
&& info.itemType == ITEM_TYPE_APPLICATION
|
||||
&& info.user.equals(user)
|
||||
&& info.getTargetComponent() != null
|
||||
&& TextUtils.equals(info.getTargetComponent().getPackageName(),
|
||||
packageName);
|
||||
final ItemOperator packageAndUserAndAppInFolder = (info, view) -> {
|
||||
if (info instanceof FolderInfo) {
|
||||
FolderInfo folderInfo = (FolderInfo) info;
|
||||
for (WorkspaceItemInfo shortcutInfo : folderInfo.contents) {
|
||||
if (packageAndUserAndApp.evaluate(shortcutInfo, view)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
List<CellLayout> cellLayouts = new ArrayList<>(getPanelCount() + 1);
|
||||
cellLayouts.add(getHotseat());
|
||||
forEachVisiblePage(page -> cellLayouts.add((CellLayout) page));
|
||||
|
||||
// Order: Preferred item, App icons in hotseat/workspace, app in folder in hotseat/workspace
|
||||
if (ADAPTIVE_ICON_WINDOW_ANIM.get()) {
|
||||
return getFirstMatch(cellLayouts, preferredItem, preferredItemInFolder,
|
||||
packageAndUserAndApp, packageAndUserAndAppInFolder);
|
||||
} else {
|
||||
// Do not use Folder as a criteria, since it'll cause a crash when trying to draw
|
||||
// FolderAdaptiveIcon as the background.
|
||||
return getFirstMatch(cellLayouts, preferredItem, packageAndUserAndApp);
|
||||
}
|
||||
}
|
||||
|
||||
public View getHomescreenIconByItemId(final int id) {
|
||||
return getFirstMatch((info, v) -> info != null && info.id == id);
|
||||
}
|
||||
@@ -3227,23 +3169,6 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
||||
return value[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the first view matching the ordered operators across the given cell layouts by order.
|
||||
* @param cellLayouts List of CellLayouts to scan, in order of preference.
|
||||
* @param operators List of operators, in order starting from best matching operator.
|
||||
*/
|
||||
View getFirstMatch(Iterable<CellLayout> cellLayouts, final ItemOperator... operators) {
|
||||
for (ItemOperator operator : operators) {
|
||||
for (CellLayout cellLayout : cellLayouts) {
|
||||
View match = mapOverCellLayout(cellLayout, operator);
|
||||
if (match != null) {
|
||||
return match;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
void clearDropTargets() {
|
||||
mapOverItems(new ItemOperator() {
|
||||
@Override
|
||||
|
||||
@@ -20,6 +20,7 @@ import android.content.ComponentName;
|
||||
import android.os.UserHandle;
|
||||
|
||||
import com.android.launcher3.LauncherSettings.Favorites;
|
||||
import com.android.launcher3.model.data.FolderInfo;
|
||||
import com.android.launcher3.model.data.ItemInfo;
|
||||
import com.android.launcher3.shortcuts.ShortcutKey;
|
||||
|
||||
@@ -85,8 +86,16 @@ public interface ItemInfoMatcher {
|
||||
}
|
||||
|
||||
static ItemInfoMatcher ofShortcutKeys(Set<ShortcutKey> keys) {
|
||||
return (info, cn) -> info.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT &&
|
||||
keys.contains(ShortcutKey.fromItemInfo(info));
|
||||
return (info, cn) -> 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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -158,7 +158,7 @@ public class FloatingSurfaceView extends AbstractFloatingView implements
|
||||
if (mContract == null) {
|
||||
return;
|
||||
}
|
||||
View icon = mLauncher.getWorkspace().getFirstMatchForAppClose(-1,
|
||||
View icon = mLauncher.getFirstMatchForAppClose(-1,
|
||||
mContract.componentName.getPackageName(), mContract.user);
|
||||
|
||||
boolean iconChanged = mIcon != icon;
|
||||
@@ -182,7 +182,7 @@ public class FloatingSurfaceView extends AbstractFloatingView implements
|
||||
lp.topMargin = Math.round(mIconPosition.top);
|
||||
}
|
||||
}
|
||||
if (iconChanged && !mIconBounds.isEmpty()) {
|
||||
if (mIcon != null && iconChanged && !mIconBounds.isEmpty()) {
|
||||
// Record the icon display
|
||||
setCurrentIconVisible(true);
|
||||
Canvas c = mPicture.beginRecording(mIconBounds.width(), mIconBounds.height());
|
||||
|
||||
Reference in New Issue
Block a user