Merge "Predictive back: widget to all apps" into tm-qpr-dev

This commit is contained in:
Fengjiang Li
2023-01-25 05:26:49 +00:00
committed by Android (Google) Code Review
12 changed files with 177 additions and 53 deletions

View File

@@ -194,7 +194,8 @@ public class TaskbarDragLayer extends BaseDragLayer<TaskbarActivityContext> {
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getAction() == ACTION_UP && event.getKeyCode() == KEYCODE_BACK) {
AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(mActivity);
if (topView != null && topView.onBackPressed()) {
if (topView != null && topView.canHandleBack()) {
topView.onBackInvoked();
// Handled by the floating view.
return true;
}

View File

@@ -71,7 +71,8 @@ public class TaskbarOverlayDragLayer extends
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getAction() == ACTION_UP && event.getKeyCode() == KEYCODE_BACK) {
AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(mActivity);
if (topView != null && topView.onBackPressed()) {
if (topView != null && topView.canHandleBack()) {
topView.onBackInvoked();
return true;
}
}

View File

@@ -84,6 +84,7 @@ import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.LauncherState;
import com.android.launcher3.OnBackPressedHandler;
import com.android.launcher3.QuickstepAccessibilityDelegate;
import com.android.launcher3.QuickstepTransitionManager;
import com.android.launcher3.R;
@@ -638,20 +639,49 @@ public class QuickstepLauncher extends Launcher {
getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
OnBackInvokedDispatcher.PRIORITY_DEFAULT,
new OnBackAnimationCallback() {
@Nullable OnBackPressedHandler mActiveOnBackPressedHandler;
@Override
public void onBackStarted(@NonNull BackEvent backEvent) {
if (mActiveOnBackPressedHandler != null) {
mActiveOnBackPressedHandler.onBackCancelled();
}
mActiveOnBackPressedHandler = getOnBackPressedHandler();
mActiveOnBackPressedHandler.onBackStarted();
}
@Override
public void onBackInvoked() {
onBackPressed();
// Recreate mActiveOnBackPressedHandler if necessary to avoid NPE because:
// 1. b/260636433: In 3-button-navigation mode, onBackStarted() is not
// called on ACTION_DOWN before onBackInvoked() is called in ACTION_UP.
// 2. Launcher#onBackPressed() will call onBackInvoked() without calling
// onBackInvoked() beforehand.
if (mActiveOnBackPressedHandler == null) {
mActiveOnBackPressedHandler = getOnBackPressedHandler();
}
mActiveOnBackPressedHandler.onBackInvoked();
mActiveOnBackPressedHandler = null;
TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "onBackInvoked");
}
@Override
public void onBackProgressed(@NonNull BackEvent backEvent) {
QuickstepLauncher.this.onBackProgressed(backEvent.getProgress());
if (!FeatureFlags.IS_STUDIO_BUILD && mActiveOnBackPressedHandler == null) {
return;
}
mActiveOnBackPressedHandler
.onBackProgressed(backEvent.getProgress());
}
@Override
public void onBackCancelled() {
QuickstepLauncher.this.onBackCancelled();
if (!FeatureFlags.IS_STUDIO_BUILD && mActiveOnBackPressedHandler == null) {
return;
}
mActiveOnBackPressedHandler.onBackCancelled();
mActiveOnBackPressedHandler = null;
}
});
}

View File

@@ -111,11 +111,6 @@ public class AllAppsEduView extends AbstractFloatingView {
return (type & TYPE_ALL_APPS_EDU) != 0;
}
@Override
public boolean onBackPressed() {
return true;
}
@Override
public boolean canInterceptEventsInSystemGestureRegion() {
return true;

View File

@@ -46,7 +46,8 @@ import java.lang.annotation.RetentionPolicy;
/**
* Base class for a View which shows a floating UI on top of the launcher UI.
*/
public abstract class AbstractFloatingView extends LinearLayout implements TouchController {
public abstract class AbstractFloatingView extends LinearLayout implements TouchController,
OnBackPressedHandler {
@IntDef(flag = true, value = {
TYPE_FOLDER,
@@ -165,12 +166,16 @@ public abstract class AbstractFloatingView extends LinearLayout implements Touch
protected abstract boolean isOfType(@FloatingViewType int type);
/** @return Whether the back is consumed. If false, Launcher will handle the back as well. */
public boolean onBackPressed() {
close(true);
/** Return true if this view can consume back press. */
public boolean canHandleBack() {
return true;
}
@Override
public void onBackInvoked() {
close(true);
}
@Override
public boolean onControllerTouchEvent(MotionEvent ev) {
return false;

View File

@@ -125,9 +125,13 @@ public abstract class BaseDraggingActivity extends BaseActivity
mCurrentActionMode = null;
}
protected boolean isInAutoCancelActionMode() {
return mCurrentActionMode != null && AUTO_CANCEL_ACTION_MODE == mCurrentActionMode.getTag();
}
@Override
public boolean finishAutoCancelActionMode() {
if (mCurrentActionMode != null && AUTO_CANCEL_ACTION_MODE == mCurrentActionMode.getTag()) {
if (isInAutoCancelActionMode()) {
mCurrentActionMode.finish();
return true;
}

View File

@@ -560,6 +560,61 @@ public class Launcher extends StatefulActivity<LauncherState>
setTitle(R.string.home_screen);
}
/**
* Provide {@link OnBackPressedHandler} in below order:
* <ol>
* <li> auto cancel action mode handler
* <li> drag handler
* <li> view handler
* <li> state handler
* </ol>
*
* A back gesture (a single click on back button, or a swipe back gesture that contains a series
* of swipe events) should be handled by the same handler from above list. For a new back
* gesture, a new handler should be regenerated.
*
* Note that state handler will always be handling the back press event if the previous 3 don't.
*/
@NonNull
protected OnBackPressedHandler getOnBackPressedHandler() {
// #1 auto cancel action mode handler
if (isInAutoCancelActionMode()) {
return this::finishAutoCancelActionMode;
}
// #2 drag handler
if (mDragController.isDragging()) {
return mDragController::cancelDrag;
}
// #3 view handler
AbstractFloatingView topView =
AbstractFloatingView.getTopOpenView(Launcher.this);
if (topView != null && topView.canHandleBack()) {
return topView;
}
// #4 state handler
return new OnBackPressedHandler() {
@Override
public void onBackInvoked() {
onStateBack();
}
@Override
public void onBackProgressed(
@FloatRange(from = 0.0, to = 1.0) float backProgress) {
mStateManager.getState().onBackProgressed(
Launcher.this, backProgress);
}
@Override
public void onBackCancelled() {
mStateManager.getState().onBackCancelled(Launcher.this);
}
};
}
protected LauncherOverlayManager getDefaultOverlay() {
return new LauncherOverlayManager() { };
}
@@ -2047,36 +2102,13 @@ public class Launcher extends StatefulActivity<LauncherState>
@Override
public void onBackPressed() {
if (finishAutoCancelActionMode()) {
return;
}
if (mDragController.isDragging()) {
mDragController.cancelDrag();
return;
}
// Note: There should be at most one log per method call. This is enforced implicitly
// by using if-else statements.
AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(this);
if (topView == null || !topView.onBackPressed()) {
// Not handled by the floating view.
onStateBack();
}
getOnBackPressedHandler().onBackInvoked();
}
protected void onStateBack() {
mStateManager.getState().onBackPressed(this);
}
protected void onBackProgressed(@FloatRange(from = 0.0, to = 1.0) float backProgress) {
mStateManager.getState().onBackProgressed(this, backProgress);
}
protected void onBackCancelled() {
mStateManager.getState().onBackCancelled(this);
}
protected void onScreenOnChanged(boolean isOn) {
// Reset AllApps to its initial state only if we are not in the middle of
// processing a multi-step drop

View File

@@ -0,0 +1,45 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.launcher3;
import androidx.annotation.FloatRange;
/**
* Interface that mimics {@link android.window.OnBackInvokedCallback} without dependencies on U's
* API such as {@link android.window.BackEvent}.
*
* <p> Impl can assume below order during a back gesture:
* <ol>
* <li> [optional] one {@link #onBackStarted()} will be called to start the gesture
* <li> zero or multiple {@link #onBackProgressed(float)} will be called during swipe gesture
* <li> either one of {@link #onBackInvoked()} or {@link #onBackCancelled()} will be called to end
* the gesture
*/
public interface OnBackPressedHandler {
/** Called when back has started. */
default void onBackStarted() {}
/** Called when back is committed. */
void onBackInvoked();
/** Called with back gesture's progress. */
default void onBackProgressed(@FloatRange(from = 0.0, to = 1.0) float backProgress) {}
/** Called when user drops the back gesture. */
default void onBackCancelled() {}
}

View File

@@ -81,10 +81,10 @@ public class DiscoveryBounce extends AbstractFloatingView {
}
@Override
public boolean onBackPressed() {
super.onBackPressed();
// Go back to the previous state (from a user's perspective this floating view isn't
// something to go back from).
public boolean canHandleBack() {
// Since DiscoveryBounce doesn't handle back, onBackInvoked() won't be called and we should
// close it without animation.
close(false);
return false;
}

View File

@@ -1579,17 +1579,14 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
return getOpenView(activityContext, TYPE_FOLDER);
}
/**
* Navigation bar back key or hardware input back key has been issued.
*/
/** Navigation bar back key or hardware input back key has been issued. */
@Override
public boolean onBackPressed() {
public void onBackInvoked() {
if (isEditingName()) {
mFolderName.dispatchBackKey();
} else {
super.onBackPressed();
super.onBackInvoked();
}
return true;
}
@Override

View File

@@ -175,8 +175,9 @@ public class SecondaryDisplayLauncher extends BaseDraggingActivity
// Note: There should be at most one log per method call. This is enforced implicitly
// by using if-else statements.
AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(this);
if (topView != null && topView.onBackPressed()) {
if (topView != null && topView.canHandleBack()) {
// Handled by the floating view.
topView.onBackInvoked();
} else {
showAppDrawer(false);
}

View File

@@ -17,7 +17,9 @@ package com.android.launcher3.widget.picker;
import static android.view.View.MeasureSpec.makeMeasureSpec;
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
import static com.android.launcher3.allapps.AllAppsTransitionController.SWIPE_ALL_APPS_TO_HOME_MIN_SCALE;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WIDGETSTRAY_SEARCHED;
import static com.android.launcher3.testing.shared.TestProtocol.NORMAL_STATE_ORDINAL;
@@ -45,6 +47,7 @@ import android.view.animation.Interpolator;
import android.widget.Button;
import android.widget.TextView;
import androidx.annotation.FloatRange;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.recyclerview.widget.DefaultItemAnimator;
@@ -54,6 +57,7 @@ import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.model.UserManagerState;
@@ -264,6 +268,15 @@ public class WidgetsFullSheet extends BaseWidgetSheet
attachScrollbarToRecyclerView(currentRecyclerView);
}
@Override
public void onBackProgressed(@FloatRange(from = 0.0, to = 1.0) float progress) {
float deceleratedProgress =
Interpolators.PREDICTIVE_BACK_DECELERATED_EASE.getInterpolation(progress);
float scaleProgress = SWIPE_ALL_APPS_TO_HOME_MIN_SCALE
+ (1 - SWIPE_ALL_APPS_TO_HOME_MIN_SCALE) * (1 - deceleratedProgress);
SCALE_PROPERTY.set(this, scaleProgress);
}
private void attachScrollbarToRecyclerView(WidgetsRecyclerView recyclerView) {
recyclerView.bindFastScrollbar();
if (mCurrentWidgetsRecyclerView != recyclerView) {
@@ -736,12 +749,12 @@ public class WidgetsFullSheet extends BaseWidgetSheet
}
@Override
public boolean onBackPressed() {
public void onBackInvoked() {
if (mIsInSearchMode) {
mSearchBar.reset();
return true;
} else {
super.onBackInvoked();
}
return super.onBackPressed();
}
@Override