diff options
Diffstat (limited to 'quickstep/src')
13 files changed, 271 insertions, 294 deletions
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java index bd7a4780b1..5bb76d6a67 100644 --- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java +++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java @@ -983,7 +983,13 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener depthController.setSurface(dimLayer); backgroundRadiusAnim.addListener(new AnimatorListenerAdapter() { @Override + public void onAnimationStart(Animator animation) { + depthController.setIsInLaunchTransition(true); + } + + @Override public void onAnimationEnd(Animator animation) { + depthController.setIsInLaunchTransition(false); depthController.setSurface(null); if (dimLayer != null) { new SurfaceControl.Transaction() diff --git a/quickstep/src/com/android/launcher3/model/WidgetsPredictionUpdateTask.java b/quickstep/src/com/android/launcher3/model/WidgetsPredictionUpdateTask.java index 22a8c9b1d0..3d891e8748 100644 --- a/quickstep/src/com/android/launcher3/model/WidgetsPredictionUpdateTask.java +++ b/quickstep/src/com/android/launcher3/model/WidgetsPredictionUpdateTask.java @@ -15,6 +15,8 @@ */ package com.android.launcher3.model; +import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WIDGETS_PREDICTION; + import android.app.prediction.AppTarget; import android.content.ComponentName; import android.text.TextUtils; @@ -73,7 +75,9 @@ public final class WidgetsPredictionUpdateTask extends BaseModelUpdateTask { if (notAddedWidgets.size() > 0) { // Even an apps have more than one widgets, we only include one widget. fixedContainerItems.items.add( - new PendingAddWidgetInfo(notAddedWidgets.get(0).widgetInfo)); + new PendingAddWidgetInfo( + notAddedWidgets.get(0).widgetInfo, + CONTAINER_WIDGETS_PREDICTION)); } } } @@ -90,7 +94,9 @@ public final class WidgetsPredictionUpdateTask extends BaseModelUpdateTask { new ComponentName(app.getPackageName(), app.getClassName()), app.getUser()); if (widgetItems.containsKey(targetWidget)) { fixedContainerItems.items.add( - new PendingAddWidgetInfo(widgetItems.get(targetWidget).widgetInfo)); + new PendingAddWidgetInfo(widgetItems.get( + targetWidget).widgetInfo, + CONTAINER_WIDGETS_PREDICTION)); } } } diff --git a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java index 4503e308e6..bb8b62db71 100644 --- a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java +++ b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java @@ -24,6 +24,7 @@ import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.os.IBinder; +import android.os.SystemProperties; import android.util.FloatProperty; import android.view.CrossWindowBlurListeners; import android.view.SurfaceControl; @@ -117,6 +118,10 @@ public class DepthController implements StateHandler<LauncherState>, * @see android.service.wallpaper.WallpaperService.Engine#onZoomChanged(float) */ private float mDepth; + /** + * If we're launching and app and should not be blurring the screen for performance reasons. + */ + private boolean mBlurDisabledForAppLaunch; // Workaround for animating the depth when multiwindow mode changes. private boolean mIgnoreStateChangesDuringMultiWindowAnimation = false; @@ -211,6 +216,19 @@ public class DepthController implements StateHandler<LauncherState>, } } + /** + * If we're launching an app from the home screen. + */ + public void setIsInLaunchTransition(boolean inLaunchTransition) { + boolean blurEnabled = SystemProperties.getBoolean("ro.launcher.blur.appLaunch", true); + mBlurDisabledForAppLaunch = inLaunchTransition && !blurEnabled; + if (!inLaunchTransition) { + // Reset depth at the end of the launch animation, so the wallpaper won't be + // zoomed out if an app crashes. + setDepth(0f); + } + } + private void setDepth(float depth) { depth = Utilities.boundToRange(depth, 0, 1); // Round out the depth to dedupe frequent, non-perceptable updates @@ -238,7 +256,7 @@ public class DepthController implements StateHandler<LauncherState>, boolean opaque = mLauncher.getScrimView().isFullyOpaque() && !isOverview; int blur = opaque || isOverview || !mCrossWindowBlursEnabled - ? 0 : (int) (mDepth * mMaxBlurRadius); + || mBlurDisabledForAppLaunch ? 0 : (int) (mDepth * mMaxBlurRadius); new SurfaceControl.Transaction() .setBackgroundBlurRadius(mSurface, blur) .setOpaque(mSurface, opaque) diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java b/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java index 01c9e765a8..fe5a3475ff 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java +++ b/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java @@ -19,7 +19,6 @@ import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKG import android.content.Context; import android.graphics.Color; -import android.os.SystemProperties; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.DeviceProfile; @@ -85,8 +84,7 @@ public class BackgroundAppState extends OverviewState { @Override protected float getDepthUnchecked(Context context) { - //TODO revert when b/178661709 is fixed - return SystemProperties.getBoolean("ro.launcher.depth.appLaunch", true) ? 1 : 0; + return 1; } @Override diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java index 7f38923671..ea4b08d3bd 100644 --- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java +++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java @@ -61,6 +61,7 @@ import android.content.Intent; import android.graphics.Matrix; import android.graphics.PointF; import android.graphics.Rect; +import android.graphics.RectF; import android.os.Build; import android.os.IBinder; import android.os.SystemClock; @@ -140,7 +141,8 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, private final ArrayList<Runnable> mRecentsAnimationStartCallbacks = new ArrayList<>(); private final OnScrollChangedListener mOnRecentsScrollListener = this::onRecentsViewScroll; - protected RecentsAnimationController mRecentsAnimationController; + // Null if the recents animation hasn't started yet or has been canceled or finished. + protected @Nullable RecentsAnimationController mRecentsAnimationController; protected RecentsAnimationTargets mRecentsAnimationTargets; protected T mActivity; protected Q mRecentsView; @@ -382,10 +384,10 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, // Set up a entire animation lifecycle callback to notify the current recents view when // the animation is canceled mGestureState.runOnceAtState(STATE_RECENTS_ANIMATION_CANCELED, () -> { - ThumbnailData snapshot = mGestureState.getRecentsAnimationCanceledSnapshot(); + ThumbnailData snapshot = mGestureState.consumeRecentsAnimationCanceledSnapshot(); if (snapshot != null) { - RecentsModel.INSTANCE.get(mContext).onTaskSnapshotChanged( - mRecentsView.getRunningTaskId(), snapshot); + mRecentsView.switchToScreenshot(snapshot, + () -> mRecentsAnimationController.cleanupScreenshot()); mRecentsView.onRecentsAnimationComplete(); } }); @@ -1232,30 +1234,40 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, final RecentsOrientedState orientationState = mTaskViewSimulator.getOrientationState(); final int windowRotation = orientationState.getDisplayRotation(); final int homeRotation = orientationState.getRecentsActivityRotation(); + + final Matrix homeToWindowPositionMap = new Matrix(); + final RectF startRect = updateProgressForStartRect(homeToWindowPositionMap, startProgress); + // Move the startRect to Launcher space as floatingIconView runs in Launcher + final Matrix windowToHomePositionMap = new Matrix(); + homeToWindowPositionMap.invert(windowToHomePositionMap); + windowToHomePositionMap.mapRect(startRect); + final Rect destinationBounds = SystemUiProxy.INSTANCE.get(mContext) .startSwipePipToHome(taskInfo.topActivity, TaskInfoCompat.getTopActivityInfo(taskInfo), runningTaskTarget.taskInfo.pictureInPictureParams, homeRotation, mDp.hotseatBarSizePx); - final SwipePipToHomeAnimator swipePipToHomeAnimator = new SwipePipToHomeAnimator( - mContext, - runningTaskTarget.taskId, - taskInfo.topActivity, - runningTaskTarget.leash.getSurfaceControl(), - TaskInfoCompat.getPipSourceRectHint( - runningTaskTarget.taskInfo.pictureInPictureParams), - TaskInfoCompat.getWindowConfigurationBounds(taskInfo), - updateProgressForStartRect(new Matrix(), startProgress), - destinationBounds, - mRecentsView.getPipCornerRadius(), - mRecentsView); + final SwipePipToHomeAnimator.Builder builder = new SwipePipToHomeAnimator.Builder() + .setContext(mContext) + .setTaskId(runningTaskTarget.taskId) + .setComponentName(taskInfo.topActivity) + .setLeash(runningTaskTarget.leash.getSurfaceControl()) + .setSourceRectHint(TaskInfoCompat.getPipSourceRectHint( + runningTaskTarget.taskInfo.pictureInPictureParams)) + .setAppBounds(TaskInfoCompat.getWindowConfigurationBounds(taskInfo)) + .setHomeToWindowPositionMap(homeToWindowPositionMap) + .setStartBounds(startRect) + .setDestinationBounds(destinationBounds) + .setCornerRadius(mRecentsView.getPipCornerRadius()) + .setAttachedView(mRecentsView); // We would assume home and app window always in the same rotation While homeRotation // is not ROTATION_0 (which implies the rotation is turned on in launcher settings). if (homeRotation == ROTATION_0 && (windowRotation == ROTATION_90 || windowRotation == ROTATION_270)) { - swipePipToHomeAnimator.setFromRotation(mTaskViewSimulator, windowRotation); + builder.setFromRotation(mTaskViewSimulator, windowRotation); } + final SwipePipToHomeAnimator swipePipToHomeAnimator = builder.build(); AnimatorPlaybackController activityAnimationToHome = homeAnimFactory.createActivityAnimationToHome(); swipePipToHomeAnimator.addAnimatorListener(new AnimatorListenerAdapter() { @@ -1282,6 +1294,7 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, mGestureState.setState(STATE_END_TARGET_ANIMATION_FINISHED); } }); + setupWindowAnimation(swipePipToHomeAnimator); return swipePipToHomeAnimator; } @@ -1312,6 +1325,11 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, HomeAnimationFactory homeAnimationFactory) { RectFSpringAnim anim = super.createWindowAnimationToHome(startProgress, homeAnimationFactory); + setupWindowAnimation(anim); + return anim; + } + + private void setupWindowAnimation(RectFSpringAnim anim) { anim.addOnUpdateListener((v, r, p) -> { updateSysUiFlags(Math.max(p, mCurrentShift.value)); }); @@ -1329,7 +1347,6 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, if (mRecentsAnimationTargets != null) { mRecentsAnimationTargets.addReleaseCheck(anim); } - return anim; } public void onConsumerAboutToBeSwitched() { @@ -1353,8 +1370,10 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, @UiThread private void resumeLastTask() { - mRecentsAnimationController.finish(false /* toRecents */, null); - ActiveGestureLog.INSTANCE.addLog("finishRecentsAnimation", false); + if (mRecentsAnimationController != null) { + mRecentsAnimationController.finish(false /* toRecents */, null); + ActiveGestureLog.INSTANCE.addLog("finishRecentsAnimation", false); + } doLogGesture(LAST_TASK, null); reset(); } @@ -1662,13 +1681,17 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, } } else { mActivityInterface.onLaunchTaskFailed(); - mRecentsAnimationController.finish(true /* toRecents */, null); + if (mRecentsAnimationController != null) { + mRecentsAnimationController.finish(true /* toRecents */, null); + } } }, true /* freezeTaskList */); } else { mActivityInterface.onLaunchTaskFailed(); Toast.makeText(mContext, R.string.activity_not_available, LENGTH_SHORT).show(); - mRecentsAnimationController.finish(true /* toRecents */, null); + if (mRecentsAnimationController != null) { + mRecentsAnimationController.finish(true /* toRecents */, null); + } } } mCanceled = false; diff --git a/quickstep/src/com/android/quickstep/GestureState.java b/quickstep/src/com/android/quickstep/GestureState.java index a302a07bca..015002f0e1 100644 --- a/quickstep/src/com/android/quickstep/GestureState.java +++ b/quickstep/src/com/android/quickstep/GestureState.java @@ -376,11 +376,14 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL } /** - * Returns the canceled animation thumbnail data. This call only returns a value while - * STATE_RECENTS_ANIMATION_CANCELED state is being set. + * Returns and clears the canceled animation thumbnail data. This call only returns a value + * while STATE_RECENTS_ANIMATION_CANCELED state is being set, and the caller is responsible for + * calling {@link RecentsAnimationController#cleanupScreenshot()}. */ - ThumbnailData getRecentsAnimationCanceledSnapshot() { - return mRecentsAnimationCanceledSnapshot; + ThumbnailData consumeRecentsAnimationCanceledSnapshot() { + ThumbnailData data = mRecentsAnimationCanceledSnapshot; + mRecentsAnimationCanceledSnapshot = null; + return data; } void setSwipeUpStartTimeMs(long uptimeMs) { diff --git a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java index 6f681b33f1..4472bdcf73 100644 --- a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java +++ b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java @@ -16,23 +16,22 @@ package com.android.quickstep.interaction; import android.app.Activity; -import android.content.Context; import android.content.Intent; import android.content.res.Configuration; -import android.content.res.TypedArray; import android.graphics.Color; -import android.graphics.Typeface; import android.os.Bundle; -import android.text.TextPaint; -import android.text.method.LinkMovementMethod; import android.util.Log; import android.view.View; +import android.view.View.AccessibilityDelegate; +import android.view.accessibility.AccessibilityNodeInfo; +import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; import android.widget.ImageView; import android.widget.TextView; import androidx.annotation.Nullable; import com.android.launcher3.R; +import com.android.launcher3.Utilities; import java.net.URISyntaxException; @@ -48,86 +47,56 @@ public class AllSetActivity extends Activity { private static final String EXTRA_ACCENT_COLOR_DARK_MODE = "suwColorAccentDark"; private static final String EXTRA_ACCENT_COLOR_LIGHT_MODE = "suwColorAccentLight"; - private int mAccentColor; - @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_allset); - setTitle(R.string.allset_title); - - final int mode = - getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK; - mAccentColor = getIntent().getIntExtra( - mode == Configuration.UI_MODE_NIGHT_YES - ? EXTRA_ACCENT_COLOR_DARK_MODE : EXTRA_ACCENT_COLOR_LIGHT_MODE, - /* defValue= */ Color.BLACK); - - ((ImageView) findViewById(R.id.icon)).getDrawable().mutate().setTint(mAccentColor); - TextView navigationSettings = findViewById(R.id.navigation_settings); - navigationSettings.setMovementMethod(LinkMovementMethod.getInstance()); - AnnotationSpan.LinkInfo linkInfo = new AnnotationSpan.LinkInfo( - AnnotationSpan.LinkInfo.DEFAULT_ANNOTATION, - new AllSetLinkSpan( - /* context= */ this, - view -> { - try { - startActivityForResult( - Intent.parseUri(URI_SYSTEM_NAVIGATION_SETTING, 0), 0); - } catch (URISyntaxException e) { - Log.e(LOG_TAG, "Failed to parse system nav settings intent", e); - } - finish(); - })); - navigationSettings.setText( - AnnotationSpan.linkify(getText(R.string.allset_navigation_settings), linkInfo)); - } - - @Override - public void onWindowFocusChanged(boolean hasFocus) { - super.onWindowFocusChanged(hasFocus); - if (hasFocus) { - hideSystemUI(); - } - } + int mode = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK; + boolean isDarkTheme = mode == Configuration.UI_MODE_NIGHT_YES; + int accentColor = getIntent().getIntExtra( + isDarkTheme ? EXTRA_ACCENT_COLOR_DARK_MODE : EXTRA_ACCENT_COLOR_LIGHT_MODE, + isDarkTheme ? Color.WHITE : Color.BLACK); + + ((ImageView) findViewById(R.id.icon)).getDrawable().mutate().setTint(accentColor); + + TextView tv = findViewById(R.id.navigation_settings); + tv.setTextColor(accentColor); + tv.setOnClickListener(v -> { + try { + startActivityForResult( + Intent.parseUri(URI_SYSTEM_NAVIGATION_SETTING, 0), 0); + } catch (URISyntaxException e) { + Log.e(LOG_TAG, "Failed to parse system nav settings intent", e); + } + finish(); + }); - private void hideSystemUI() { - getWindow().getDecorView().setSystemUiVisibility( - View.SYSTEM_UI_FLAG_LAYOUT_STABLE - | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_FULLSCREEN); - getWindow().setNavigationBarColor(Color.TRANSPARENT); + findViewById(R.id.hint).setAccessibilityDelegate(new SkipButtonAccessibilityDelegate()); } - private final class AllSetLinkSpan extends AnnotationSpan { + /** + * Accessibility delegate which exposes a click event without making the view + * clickable in touch mode + */ + private class SkipButtonAccessibilityDelegate extends AccessibilityDelegate { - private final String mFontFamily; - private final int mTextSize; - - AllSetLinkSpan(Context context, View.OnClickListener listener) { - super(listener); - TypedArray typedArray = - context.obtainStyledAttributes(R.style.TextAppearance_GestureTutorial_LinkText, - R.styleable.AllSetLinkSpan); - mFontFamily = typedArray.getString(R.styleable.AllSetLinkSpan_android_fontFamily); - mTextSize = - typedArray.getDimensionPixelSize( - R.styleable.AllSetLinkSpan_android_textSize, /* defValue= */ -1); - typedArray.recycle(); + @Override + public AccessibilityNodeInfo createAccessibilityNodeInfo(View host) { + AccessibilityNodeInfo info = super.createAccessibilityNodeInfo(host); + info.addAction(AccessibilityAction.ACTION_CLICK); + info.setClickable(true); + return info; } @Override - public void updateDrawState(TextPaint ds) { - super.updateDrawState(ds); - ds.setColor(mAccentColor); - ds.setTypeface(Typeface.create(mFontFamily, Typeface.NORMAL)); - ds.setUnderlineText(false); - if (mTextSize != -1) { - ds.setTextSize(mTextSize); + public boolean performAccessibilityAction(View host, int action, Bundle args) { + if (action == AccessibilityAction.ACTION_CLICK.getId()) { + startActivity(Utilities.createHomeIntent()); + finish(); + return true; } + return super.performAccessibilityAction(host, action, args); } } - } diff --git a/quickstep/src/com/android/quickstep/interaction/AnnotationSpan.java b/quickstep/src/com/android/quickstep/interaction/AnnotationSpan.java deleted file mode 100644 index fea5078e56..0000000000 --- a/quickstep/src/com/android/quickstep/interaction/AnnotationSpan.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.quickstep.interaction; - -import android.content.ActivityNotFoundException; -import android.content.Context; -import android.content.Intent; -import android.text.Annotation; -import android.text.SpannableString; -import android.text.SpannableStringBuilder; -import android.text.style.URLSpan; -import android.util.Log; -import android.view.View; - -import java.util.Arrays; -import java.util.Comparator; - -/** - * This class is used to add {@link View.OnClickListener} for the text been wrapped by - * annotation. - * - * Copied from packages/apps/Settings/src/com/android/settings/utils/AnnotationSpan.java. - */ -public class AnnotationSpan extends URLSpan { - - private final View.OnClickListener mClickListener; - - AnnotationSpan(View.OnClickListener lsn) { - super((String) null); - mClickListener = lsn; - } - - @Override - public void onClick(View widget) { - if (mClickListener != null) { - mClickListener.onClick(widget); - } - } - - public static CharSequence linkify(CharSequence rawText, LinkInfo... linkInfos) { - SpannableString msg = new SpannableString(rawText); - Annotation[] spans = msg.getSpans(0, msg.length(), Annotation.class); - SpannableStringBuilder builder = new SpannableStringBuilder(msg); - for (Annotation annotation : spans) { - final String key = annotation.getValue(); - int start = msg.getSpanStart(annotation); - int end = msg.getSpanEnd(annotation); - AnnotationSpan link = null; - for (LinkInfo linkInfo : linkInfos) { - if (linkInfo.mAnnotation.equals(key)) { - link = linkInfo.mCustomizedSpan != null ? linkInfo.mCustomizedSpan - : new AnnotationSpan(linkInfo.mClickListener); - break; - } - } - if (link != null) { - builder.setSpan(link, start, end, msg.getSpanFlags(link)); - } - } - return builder; - } - - /** - * get the text part without having text for link part - */ - public static CharSequence textWithoutLink(CharSequence encodedText) { - SpannableString msg = new SpannableString(encodedText); - Annotation[] spans = msg.getSpans(0, msg.length(), Annotation.class); - if (spans == null) { - return encodedText; - } - Arrays.sort(spans, Comparator.comparingInt(span -> -msg.getSpanStart(span))); - StringBuilder msgWithoutLink = new StringBuilder(msg.toString()); - for (Annotation span : spans) { - msgWithoutLink.delete(msg.getSpanStart(span), msg.getSpanEnd(span)); - } - return msgWithoutLink.toString(); - } - - /** Data class to store the annotation and the click action. */ - public static class LinkInfo { - public static final String DEFAULT_ANNOTATION = "link"; - private static final String TAG = "AnnotationSpan.LinkInfo"; - private final String mAnnotation; - private final Boolean mActionable; - private final View.OnClickListener mClickListener; - private final AnnotationSpan mCustomizedSpan; - - public LinkInfo(String annotation, View.OnClickListener listener) { - mAnnotation = annotation; - mClickListener = listener; - mActionable = true; // assume actionable - mCustomizedSpan = null; - } - - public LinkInfo(String annotation, AnnotationSpan customizedSpan) { - mAnnotation = annotation; - mClickListener = null; - mActionable = customizedSpan != null; - mCustomizedSpan = customizedSpan; - } - - public LinkInfo(Context context, String annotation, Intent intent) { - mAnnotation = annotation; - mCustomizedSpan = null; - if (intent != null) { - mActionable = context.getPackageManager().resolveActivity(intent, 0) != null; - } else { - mActionable = false; - } - if (mActionable) { - mClickListener = - view -> { - try { - context.startActivity(intent); - } catch (ActivityNotFoundException e) { - Log.w(TAG, "Activity was not found for intent, " + intent); - } - }; - } else { - mClickListener = null; - } - } - - public boolean isActionable() { - return mActionable; - } - } -} diff --git a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java index b1c9ed0361..6575996d69 100644 --- a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java +++ b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java @@ -130,7 +130,8 @@ public class StatsLogCompatManager extends StatsLogManager { info.getAttribute().getNumber() /* origin */, getCardinality(info) /* cardinality */, info.getWidget().getSpanX(), - info.getWidget().getSpanY()); + info.getWidget().getSpanY(), + getFeatures(info)); } /** @@ -365,15 +366,12 @@ public class StatsLogCompatManager extends StatsLogManager { atomInfo.getFolderIcon().getFromLabelState().getNumber() /* fromState */, atomInfo.getFolderIcon().getToLabelState().getNumber() /* toState */, atomInfo.getFolderIcon().getLabelInfo() /* edittext */, - getCardinality(atomInfo) /* cardinality */); + getCardinality(atomInfo) /* cardinality */, + getFeatures(atomInfo) /* features */); } } private static int getCardinality(LauncherAtom.ItemInfo info) { - // TODO(b/187734511): Implement a unified solution for 1x1 widgets in folders/hotseat. - if (info.getItemCase().equals(LauncherAtom.ItemInfo.ItemCase.WIDGET)) { - return info.getWidget().getWidgetFeatures(); - } switch (info.getContainerInfo().getContainerCase()) { case PREDICTED_HOTSEAT_CONTAINER: return info.getContainerInfo().getPredictedHotseatContainer().getCardinality(); @@ -514,6 +512,13 @@ public class StatsLogCompatManager extends StatsLogManager { } } + private static int getFeatures(LauncherAtom.ItemInfo info) { + if (info.getItemCase().equals(LauncherAtom.ItemInfo.ItemCase.WIDGET)) { + return info.getWidget().getWidgetFeatures(); + } + return 0; + } + /** * Interface to get stats log while it is dispatched to the system diff --git a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java index 67a635b70b..7488649eb7 100644 --- a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java +++ b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java @@ -56,7 +56,9 @@ public class SwipePipToHomeAnimator extends RectFSpringAnim { private final ComponentName mComponentName; private final SurfaceControl mLeash; private final Rect mAppBounds = new Rect(); + private final Matrix mHomeToWindowPositionMap = new Matrix(); private final Rect mStartBounds = new Rect(); + private final RectF mCurrentBoundsF = new RectF(); private final Rect mCurrentBounds = new Rect(); private final Rect mDestinationBounds = new Rect(); private final PipSurfaceTransactionHelper mSurfaceTransactionHelper; @@ -66,10 +68,9 @@ public class SwipePipToHomeAnimator extends RectFSpringAnim { private final Rect mSourceHintRectInsets; private final Rect mSourceInsets = new Rect(); - /** for rotation via {@link #setFromRotation(TaskViewSimulator, int)} */ - private @RecentsOrientedState.SurfaceRotation int mFromRotation = Surface.ROTATION_0; + /** for rotation calculations */ + private final @RecentsOrientedState.SurfaceRotation int mFromRotation; private final Rect mDestinationBoundsTransformed = new Rect(); - private final Rect mDestinationBoundsAnimation = new Rect(); /** * Flag to avoid the double-end problem since the leash would have been released @@ -91,31 +92,39 @@ public class SwipePipToHomeAnimator extends RectFSpringAnim { * @param leash {@link SurfaceControl} this animator operates on * @param sourceRectHint See the definition in {@link android.app.PictureInPictureParams} * @param appBounds Bounds of the application, sourceRectHint is based on this bounds + * @param homeToWindowPositionMap {@link Matrix} to map a Rect from home to window space * @param startBounds Bounds of the application when this animator starts. This can be * different from the appBounds if user has swiped a certain distance and * Launcher has performed transform on the leash. * @param destinationBounds Bounds of the destination this animator ends to + * @param fromRotation From rotation if different from final rotation, ROTATION_0 otherwise + * @param destinationBoundsTransformed Destination bounds in window space * @param cornerRadius Corner radius in pixel value for PiP window + * @param view Attached view for logging purpose */ - public SwipePipToHomeAnimator(@NonNull Context context, + private SwipePipToHomeAnimator(@NonNull Context context, int taskId, @NonNull ComponentName componentName, @NonNull SurfaceControl leash, @Nullable Rect sourceRectHint, @NonNull Rect appBounds, + @NonNull Matrix homeToWindowPositionMap, @NonNull RectF startBounds, @NonNull Rect destinationBounds, + @RecentsOrientedState.SurfaceRotation int fromRotation, + @NonNull Rect destinationBoundsTransformed, int cornerRadius, @NonNull View view) { - super(startBounds, new RectF(destinationBounds), context); + super(startBounds, new RectF(destinationBoundsTransformed), context); mTaskId = taskId; mComponentName = componentName; mLeash = leash; mAppBounds.set(appBounds); + mHomeToWindowPositionMap.set(homeToWindowPositionMap); startBounds.round(mStartBounds); mDestinationBounds.set(destinationBounds); - mDestinationBoundsTransformed.set(mDestinationBounds); - mDestinationBoundsAnimation.set(mDestinationBounds); + mFromRotation = fromRotation; + mDestinationBoundsTransformed.set(destinationBoundsTransformed); mSurfaceTransactionHelper = new PipSurfaceTransactionHelper(cornerRadius); if (sourceRectHint != null && (sourceRectHint.width() < destinationBounds.width() @@ -191,37 +200,13 @@ public class SwipePipToHomeAnimator extends RectFSpringAnim { addOnUpdateListener(this::onAnimationUpdate); } - /** sets the from rotation if it's different from the target rotation. */ - public void setFromRotation(TaskViewSimulator taskViewSimulator, - @RecentsOrientedState.SurfaceRotation int fromRotation) { - if (fromRotation != Surface.ROTATION_90 && fromRotation != Surface.ROTATION_270) { - Log.wtf(TAG, "Not a supported rotation, rotation=" + fromRotation); - return; - } - mFromRotation = fromRotation; - final Matrix matrix = new Matrix(); - taskViewSimulator.applyWindowToHomeRotation(matrix); - - // map the destination bounds into window space. mDestinationBounds is always calculated - // in the final home space and the animation runs in original window space. - final RectF transformed = new RectF(mDestinationBounds); - matrix.mapRect(transformed, new RectF(mDestinationBounds)); - transformed.round(mDestinationBoundsTransformed); - - // set the animation destination bounds for RectEvaluator calculation. - // bounds and insets are calculated as if the transition is from mAppBounds to - // mDestinationBoundsAnimation, separated from rotate / scale / position. - mDestinationBoundsAnimation.set(mAppBounds.left, mAppBounds.top, - mAppBounds.left + mDestinationBounds.width(), - mAppBounds.top + mDestinationBounds.height()); - } - private void onAnimationUpdate(@Nullable AppCloseConfig values, RectF currentRect, float progress) { if (mHasAnimationEnded) return; final SurfaceControl.Transaction tx = PipSurfaceTransactionHelper.newSurfaceControlTransaction(); - onAnimationUpdate(tx, currentRect, progress); + mHomeToWindowPositionMap.mapRect(mCurrentBoundsF, currentRect); + onAnimationUpdate(tx, mCurrentBoundsF, progress); tx.apply(); } @@ -309,6 +294,108 @@ public class SwipePipToHomeAnimator extends RectFSpringAnim { return new RotatedPosition(degree, positionX, positionY); } + /** Builder class for {@link SwipePipToHomeAnimator} */ + public static class Builder { + private Context mContext; + private int mTaskId; + private ComponentName mComponentName; + private SurfaceControl mLeash; + private Rect mSourceRectHint; + private Rect mAppBounds; + private Matrix mHomeToWindowPositionMap; + private RectF mStartBounds; + private Rect mDestinationBounds; + private int mCornerRadius; + private View mAttachedView; + private @RecentsOrientedState.SurfaceRotation int mFromRotation = Surface.ROTATION_0; + private final Rect mDestinationBoundsTransformed = new Rect(); + + public Builder setContext(Context context) { + mContext = context; + return this; + } + + public Builder setTaskId(int taskId) { + mTaskId = taskId; + return this; + } + + public Builder setComponentName(ComponentName componentName) { + mComponentName = componentName; + return this; + } + + public Builder setLeash(SurfaceControl leash) { + mLeash = leash; + return this; + } + + public Builder setSourceRectHint(Rect sourceRectHint) { + mSourceRectHint = new Rect(sourceRectHint); + return this; + } + + public Builder setAppBounds(Rect appBounds) { + mAppBounds = new Rect(appBounds); + return this; + } + + public Builder setHomeToWindowPositionMap(Matrix homeToWindowPositionMap) { + mHomeToWindowPositionMap = new Matrix(homeToWindowPositionMap); + return this; + } + + public Builder setStartBounds(RectF startBounds) { + mStartBounds = new RectF(startBounds); + return this; + } + + public Builder setDestinationBounds(Rect destinationBounds) { + mDestinationBounds = new Rect(destinationBounds); + return this; + } + + public Builder setCornerRadius(int cornerRadius) { + mCornerRadius = cornerRadius; + return this; + } + + public Builder setAttachedView(View attachedView) { + mAttachedView = attachedView; + return this; + } + + public Builder setFromRotation(TaskViewSimulator taskViewSimulator, + @RecentsOrientedState.SurfaceRotation int fromRotation) { + if (fromRotation != Surface.ROTATION_90 && fromRotation != Surface.ROTATION_270) { + Log.wtf(TAG, "Not a supported rotation, rotation=" + fromRotation); + return this; + } + final Matrix matrix = new Matrix(); + taskViewSimulator.applyWindowToHomeRotation(matrix); + + // map the destination bounds into window space. mDestinationBounds is always calculated + // in the final home space and the animation runs in original window space. + final RectF transformed = new RectF(mDestinationBounds); + matrix.mapRect(transformed, new RectF(mDestinationBounds)); + transformed.round(mDestinationBoundsTransformed); + + mFromRotation = fromRotation; + return this; + } + + public SwipePipToHomeAnimator build() { + if (mDestinationBoundsTransformed.isEmpty()) { + mDestinationBoundsTransformed.set(mDestinationBounds); + } + return new SwipePipToHomeAnimator(mContext, mTaskId, mComponentName, mLeash, + mSourceRectHint, mAppBounds, + mHomeToWindowPositionMap, mStartBounds, mDestinationBounds, + mFromRotation, mDestinationBoundsTransformed, + mCornerRadius, mAttachedView); + } + } + private static class RotatedPosition { private final float degree; private final float positionX; diff --git a/quickstep/src/com/android/quickstep/views/FloatingWidgetView.java b/quickstep/src/com/android/quickstep/views/FloatingWidgetView.java index 22ce9421f7..88b11a0884 100644 --- a/quickstep/src/com/android/quickstep/views/FloatingWidgetView.java +++ b/quickstep/src/com/android/quickstep/views/FloatingWidgetView.java @@ -152,6 +152,7 @@ public class FloatingWidgetView extends FrameLayout implements AnimatorListener, RectF widgetBackgroundPosition, Size windowSize, float windowCornerRadius, boolean appTargetIsTranslucent, int fallbackBackgroundColor) { mAppWidgetView = originalView; + // Deferrals must begin before GhostView is created. See b/190818220 mAppWidgetView.beginDeferringUpdates(); mBackgroundPosition = widgetBackgroundPosition; mAppTargetIsTranslucent = appTargetIsTranslucent; @@ -240,6 +241,7 @@ public class FloatingWidgetView extends FrameLayout implements AnimatorListener, ((ViewGroup) dragLayer.getParent()).removeView(this); dragLayer.removeView(mListenerView); mBackgroundView.finish(); + // Removing GhostView must occur before ending deferrals. See b/190818220 mAppWidgetView.endDeferringUpdates(); recycle(); mLauncher.getViewCache().recycleView(R.layout.floating_widget_view, this); diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index 710a9ab9fe..1b1066a65d 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -1665,7 +1665,6 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T pa.addListener(AnimatorListeners.forSuccessCallback(() -> { setLayoutRotation(newRotation, mOrientationState.getDisplayRotation()); mActivity.getDragLayer().recreateControllers(); - updateChildTaskOrientations(); setRecentsChangedOrientation(false).start(); })); pa.start(); diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuView.java b/quickstep/src/com/android/quickstep/views/TaskMenuView.java index c97225ec17..d663635c79 100644 --- a/quickstep/src/com/android/quickstep/views/TaskMenuView.java +++ b/quickstep/src/com/android/quickstep/views/TaskMenuView.java @@ -59,6 +59,7 @@ public class TaskMenuView extends AbstractFloatingView implements OnScrollChange private static final int REVEAL_OPEN_DURATION = 150; private static final int REVEAL_CLOSE_DURATION = 100; + private final float mTaskInsetMargin; private BaseDraggingActivity mActivity; private TextView mTaskName; @@ -75,6 +76,7 @@ public class TaskMenuView extends AbstractFloatingView implements OnScrollChange mActivity = BaseDraggingActivity.fromContext(context); setClipToOutline(true); + mTaskInsetMargin = getResources().getDimension(R.dimen.task_card_margin); } @Override @@ -124,8 +126,13 @@ public class TaskMenuView extends AbstractFloatingView implements OnScrollChange private void setPosition(float x, float y, int overscrollShift) { PagedOrientationHandler pagedOrientationHandler = mTaskView.getPagedOrientationHandler(); + // Inset due to margin + PointF additionalInset = pagedOrientationHandler + .getAdditionalInsetForTaskMenu(mTaskInsetMargin); int taskTopMargin = mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx; - float adjustedY = y + taskTopMargin; + + float adjustedY = y + taskTopMargin - additionalInset.y; + float adjustedX = x - additionalInset.x; // Changing pivot to make computations easier // NOTE: Changing the pivots means the rotated view gets rotated about the new pivots set, // which would render the X and Y position set here incorrect @@ -137,7 +144,8 @@ public class TaskMenuView extends AbstractFloatingView implements OnScrollChange setPivotY(0); } setRotation(pagedOrientationHandler.getDegreesRotated()); - setX(pagedOrientationHandler.getTaskMenuX(x, mTaskView.getThumbnail(), overscrollShift)); + setX(pagedOrientationHandler.getTaskMenuX(adjustedX, + mTaskView.getThumbnail(), overscrollShift)); setY(pagedOrientationHandler.getTaskMenuY( adjustedY, mTaskView.getThumbnail(), overscrollShift)); } @@ -228,8 +236,7 @@ public class TaskMenuView extends AbstractFloatingView implements OnScrollChange private void orientAroundTaskView(TaskView taskView) { PagedOrientationHandler orientationHandler = taskView.getPagedOrientationHandler(); measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); - float taskInsetMargin = getResources().getDimension(R.dimen.task_card_margin); - orientationHandler.setTaskMenuAroundTaskView(this, taskInsetMargin); + orientationHandler.setTaskMenuAroundTaskView(this, mTaskInsetMargin); mActivity.getDragLayer().getDescendantRectRelativeToSelf(taskView, sTempRect); Rect insets = mActivity.getDragLayer().getInsets(); BaseDragLayer.LayoutParams params = (BaseDragLayer.LayoutParams) getLayoutParams(); @@ -243,9 +250,6 @@ public class TaskMenuView extends AbstractFloatingView implements OnScrollChange setScaleY(taskView.getScaleY()); orientationHandler.setTaskOptionsMenuLayoutOrientation( mActivity.getDeviceProfile(), mOptionLayout); - PointF additionalInset = orientationHandler.getAdditionalInsetForTaskMenu(taskInsetMargin); - insets.left += additionalInset.x; - insets.top += additionalInset.y; setPosition(sTempRect.left - insets.left, sTempRect.top - insets.top, 0); } |