Snap for 9528303 from ab83443fe8 to udc-release
Change-Id: I0d0d5df8cdd6587dc6d519007f634a903bcbde38
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A
|
||||
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_ASSIST_GESTURE_CONSTRAINED;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BUBBLES_EXPANDED;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DREAMING;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DIALOG_SHOWING;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_HOME_DISABLED;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SHOWING;
|
||||
@@ -339,7 +340,8 @@ public class RecentsAnimationDeviceState implements DisplayInfoChangeListener {
|
||||
&& (mSystemUiStateFlags & SYSUI_STATE_QUICK_SETTINGS_EXPANDED) == 0
|
||||
&& (mSystemUiStateFlags & SYSUI_STATE_MAGNIFICATION_OVERLAP) == 0
|
||||
&& ((mSystemUiStateFlags & SYSUI_STATE_HOME_DISABLED) == 0
|
||||
|| (mSystemUiStateFlags & SYSUI_STATE_OVERVIEW_DISABLED) == 0);
|
||||
|| (mSystemUiStateFlags & SYSUI_STATE_OVERVIEW_DISABLED) == 0)
|
||||
&& (mSystemUiStateFlags & SYSUI_STATE_DEVICE_DREAMING) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -233,15 +233,10 @@ public class RotationTouchHelper implements DisplayInfoChangeListener {
|
||||
* @return whether the coordinates of the {@param event} is in the swipe up gesture region.
|
||||
*/
|
||||
public boolean isInSwipeUpTouchRegion(MotionEvent event, BaseActivityInterface activity) {
|
||||
boolean inBarArea = mOrientationTouchTransformer.touchInValidSwipeRegions(event.getX(),
|
||||
event.getY());
|
||||
if (inBarArea) {
|
||||
return true;
|
||||
}
|
||||
if (isTrackpadMotionEvent(event)) {
|
||||
return !activity.isResumed();
|
||||
}
|
||||
return false;
|
||||
return mOrientationTouchTransformer.touchInValidSwipeRegions(event.getX(), event.getY());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -250,15 +245,11 @@ public class RotationTouchHelper implements DisplayInfoChangeListener {
|
||||
*/
|
||||
public boolean isInSwipeUpTouchRegion(MotionEvent event, int pointerIndex,
|
||||
BaseActivityInterface activity) {
|
||||
boolean inBarArea = mOrientationTouchTransformer.touchInValidSwipeRegions(
|
||||
event.getX(pointerIndex), event.getY(pointerIndex));
|
||||
if (inBarArea) {
|
||||
return true;
|
||||
}
|
||||
if (isTrackpadMotionEvent(event)) {
|
||||
return !activity.isResumed();
|
||||
}
|
||||
return false;
|
||||
return mOrientationTouchTransformer.touchInValidSwipeRegions(event.getX(pointerIndex),
|
||||
event.getY(pointerIndex));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -50,7 +50,7 @@ import java.util.HashMap;
|
||||
|
||||
public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAnimationListener {
|
||||
public static final boolean ENABLE_SHELL_TRANSITIONS =
|
||||
SystemProperties.getBoolean("persist.wm.debug.shell_transit", false);
|
||||
SystemProperties.getBoolean("persist.wm.debug.shell_transit", true);
|
||||
public static final boolean SHELL_TRANSITIONS_ROTATION = ENABLE_SHELL_TRANSITIONS
|
||||
&& SystemProperties.getBoolean("persist.wm.debug.shell_transit_rotate", false);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -34,7 +34,7 @@ import org.junit.rules.TestRule;
|
||||
*/
|
||||
public abstract class AbstractQuickStepTest extends AbstractLauncherUiTest {
|
||||
public static final boolean ENABLE_SHELL_TRANSITIONS =
|
||||
SystemProperties.getBoolean("persist.wm.debug.shell_transit", false);
|
||||
SystemProperties.getBoolean("persist.wm.debug.shell_transit", true);
|
||||
@Override
|
||||
protected TestRule getRulesInsideActivityMonitor() {
|
||||
return RuleChain.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -132,7 +132,6 @@ import com.android.launcher3.allapps.ActivityAllAppsContainerView;
|
||||
import com.android.launcher3.allapps.AllAppsRecyclerView;
|
||||
import com.android.launcher3.allapps.AllAppsStore;
|
||||
import com.android.launcher3.allapps.AllAppsTransitionController;
|
||||
import com.android.launcher3.allapps.BaseAllAppsContainerView;
|
||||
import com.android.launcher3.allapps.BaseSearchConfig;
|
||||
import com.android.launcher3.allapps.DiscoveryBounce;
|
||||
import com.android.launcher3.anim.PropertyListBuilder;
|
||||
@@ -560,6 +559,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() { };
|
||||
}
|
||||
@@ -1642,7 +1696,7 @@ public class Launcher extends StatefulActivity<LauncherState>
|
||||
|
||||
private void showAllAppsWorkTabFromIntent(boolean alreadyOnHome) {
|
||||
showAllAppsFromIntent(alreadyOnHome);
|
||||
mAppsView.switchToTab(BaseAllAppsContainerView.AdapterHolder.WORK);
|
||||
mAppsView.switchToTab(ActivityAllAppsContainerView.AdapterHolder.WORK);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2047,36 +2101,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
|
||||
|
||||
@@ -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() {}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -299,7 +299,7 @@ public class AllAppsRecyclerView extends FastScrollRecyclerView {
|
||||
return;
|
||||
} else if (appsView.mViewPager != null) {
|
||||
int currentPage = appsView.mViewPager.getCurrentPage();
|
||||
if (currentPage == BaseAllAppsContainerView.AdapterHolder.WORK) {
|
||||
if (currentPage == ActivityAllAppsContainerView.AdapterHolder.WORK) {
|
||||
// In work A-Z list
|
||||
mgr.logger().withContainerInfo(containerInfo).log((mCumulativeVerticalScroll > 0)
|
||||
? LAUNCHER_WORK_FAB_BUTTON_COLLAPSE
|
||||
|
||||
@@ -1,996 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 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.allapps;
|
||||
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_COUNT;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_TAP_ON_PERSONAL_TAB;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_TAP_ON_WORK_TAB;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.Path.Direction;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcelable;
|
||||
import android.os.Process;
|
||||
import android.os.UserManager;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
import android.util.TypedValue;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.WindowInsets;
|
||||
import android.widget.Button;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.core.graphics.ColorUtils;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
|
||||
import com.android.launcher3.DragSource;
|
||||
import com.android.launcher3.DropTarget.DragObject;
|
||||
import com.android.launcher3.Insettable;
|
||||
import com.android.launcher3.InsettableFrameLayout;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.allapps.search.DefaultSearchAdapterProvider;
|
||||
import com.android.launcher3.allapps.search.SearchAdapterProvider;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.keyboard.FocusedItemDecorator;
|
||||
import com.android.launcher3.model.StringCache;
|
||||
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;
|
||||
import com.android.launcher3.views.BaseDragLayer;
|
||||
import com.android.launcher3.views.RecyclerViewFastScroller;
|
||||
import com.android.launcher3.views.ScrimView;
|
||||
import com.android.launcher3.views.SpringRelativeLayout;
|
||||
import com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip.OnActivePageChangedListener;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* Base all apps view container.
|
||||
*
|
||||
* @param <T> Type of context inflating all apps.
|
||||
*/
|
||||
public abstract class BaseAllAppsContainerView<T extends Context & ActivityContext>
|
||||
extends SpringRelativeLayout implements DragSource, Insettable,
|
||||
OnDeviceProfileChangeListener, OnActivePageChangedListener,
|
||||
ScrimView.ScrimDrawingController {
|
||||
|
||||
protected static final String BUNDLE_KEY_CURRENT_PAGE = "launcher.allapps.current_page";
|
||||
|
||||
public static final float PULL_MULTIPLIER = .02f;
|
||||
public static final float FLING_VELOCITY_MULTIPLIER = 1200f;
|
||||
|
||||
// Render the header protection at all times to debug clipping issues.
|
||||
private static final boolean DEBUG_HEADER_PROTECTION = false;
|
||||
|
||||
private final Paint mHeaderPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
private final Rect mInsets = new Rect();
|
||||
|
||||
/** Context of an activity or window that is inflating this container. */
|
||||
protected final T mActivityContext;
|
||||
protected final List<AdapterHolder> mAH;
|
||||
protected final Predicate<ItemInfo> mPersonalMatcher = ItemInfoMatcher.ofUser(
|
||||
Process.myUserHandle());
|
||||
private final AllAppsStore mAllAppsStore = new AllAppsStore();
|
||||
|
||||
private final RecyclerView.OnScrollListener mScrollListener =
|
||||
new RecyclerView.OnScrollListener() {
|
||||
@Override
|
||||
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
|
||||
updateHeaderScroll(recyclerView.computeVerticalScrollOffset());
|
||||
}
|
||||
};
|
||||
|
||||
protected final WorkProfileManager mWorkManager;
|
||||
|
||||
private final Paint mNavBarScrimPaint;
|
||||
private int mNavBarScrimHeight = 0;
|
||||
|
||||
protected AllAppsPagedView mViewPager;
|
||||
private SearchRecyclerView mSearchRecyclerView;
|
||||
private SearchAdapterProvider<?> mMainAdapterProvider;
|
||||
|
||||
protected FloatingHeaderView mHeader;
|
||||
protected View mBottomSheetBackground;
|
||||
private View mBottomSheetHandleArea;
|
||||
|
||||
/**
|
||||
* View that defines the search box. Result is rendered inside {@link #mSearchRecyclerView}.
|
||||
*/
|
||||
protected View mSearchContainer;
|
||||
protected SearchUiManager mSearchUiManager;
|
||||
|
||||
protected boolean mUsingTabs;
|
||||
private boolean mHasWorkApps;
|
||||
|
||||
protected RecyclerViewFastScroller mTouchHandler;
|
||||
protected final Point mFastScrollerOffset = new Point();
|
||||
|
||||
protected final int mScrimColor;
|
||||
private final int mHeaderProtectionColor;
|
||||
protected final float mHeaderThreshold;
|
||||
private final Path mTmpPath = new Path();
|
||||
private final RectF mTmpRectF = new RectF();
|
||||
private float[] mBottomSheetCornerRadii;
|
||||
private ScrimView mScrimView;
|
||||
private int mHeaderColor;
|
||||
private int mBottomSheetBackgroundColor;
|
||||
private int mTabsProtectionAlpha;
|
||||
|
||||
protected BaseAllAppsContainerView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
mActivityContext = ActivityContext.lookupContext(context);
|
||||
|
||||
mScrimColor = Themes.getAttrColor(context, R.attr.allAppsScrimColor);
|
||||
mHeaderThreshold = getResources().getDimensionPixelSize(
|
||||
R.dimen.dynamic_grid_cell_border_spacing);
|
||||
mHeaderProtectionColor = Themes.getAttrColor(context, R.attr.allappsHeaderProtectionColor);
|
||||
|
||||
mWorkManager = new WorkProfileManager(mActivityContext.getSystemService(UserManager.class),
|
||||
this, mActivityContext.getStatsLogManager());
|
||||
mAH = Arrays.asList(null, null, null);
|
||||
mNavBarScrimPaint = new Paint();
|
||||
mNavBarScrimPaint.setColor(Themes.getAttrColor(context, R.attr.allAppsNavBarScrimColor));
|
||||
|
||||
mAllAppsStore.addUpdateListener(this::onAppsUpdated);
|
||||
mActivityContext.addOnDeviceProfileChangeListener(this);
|
||||
|
||||
// This is a focus listener that proxies focus from a view into the list view. This is to
|
||||
// work around the search box from getting first focus and showing the cursor.
|
||||
setOnFocusChangeListener((v, hasFocus) -> {
|
||||
if (hasFocus && getActiveRecyclerView() != null) {
|
||||
getActiveRecyclerView().requestFocus();
|
||||
}
|
||||
});
|
||||
initContent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the view hierarchy and internal variables. Any initialization which actually uses
|
||||
* these members should be done in {@link #onFinishInflate()}.
|
||||
* In terms of subclass initialization, the following would be parallel order for activity:
|
||||
* initContent -> onPreCreate
|
||||
* constructor/init -> onCreate
|
||||
* onFinishInflate -> onPostCreate
|
||||
*/
|
||||
protected void initContent() {
|
||||
mMainAdapterProvider = createMainAdapterProvider();
|
||||
|
||||
mAH.set(AdapterHolder.MAIN, new AdapterHolder(AdapterHolder.MAIN));
|
||||
mAH.set(AdapterHolder.WORK, new AdapterHolder(AdapterHolder.WORK));
|
||||
mAH.set(AdapterHolder.SEARCH, new AdapterHolder(AdapterHolder.SEARCH));
|
||||
|
||||
getLayoutInflater().inflate(R.layout.all_apps_content, this);
|
||||
mHeader = findViewById(R.id.all_apps_header);
|
||||
mBottomSheetBackground = findViewById(R.id.bottom_sheet_background);
|
||||
mBottomSheetHandleArea = findViewById(R.id.bottom_sheet_handle_area);
|
||||
mSearchRecyclerView = findViewById(R.id.search_results_list_view);
|
||||
|
||||
// Add the search box next to the header
|
||||
mSearchContainer = inflateSearchBox();
|
||||
addView(mSearchContainer, indexOfChild(mHeader) + 1);
|
||||
mSearchUiManager = (SearchUiManager) mSearchContainer;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
|
||||
mAH.get(AdapterHolder.SEARCH).setup(mSearchRecyclerView,
|
||||
/* Filter out A-Z apps */ itemInfo -> false);
|
||||
rebindAdapters(true /* force */);
|
||||
float cornerRadius = Themes.getDialogCornerRadius(getContext());
|
||||
mBottomSheetCornerRadii = new float[]{
|
||||
cornerRadius,
|
||||
cornerRadius, // Top left radius in px
|
||||
cornerRadius,
|
||||
cornerRadius, // Top right radius in px
|
||||
0,
|
||||
0, // Bottom right
|
||||
0,
|
||||
0 // Bottom left
|
||||
};
|
||||
final TypedValue value = new TypedValue();
|
||||
getContext().getTheme().resolveAttribute(android.R.attr.colorBackground, value, true);
|
||||
mBottomSheetBackgroundColor = value.data;
|
||||
updateBackground(mActivityContext.getDeviceProfile());
|
||||
}
|
||||
|
||||
/**
|
||||
* Inflates the search box
|
||||
*/
|
||||
protected View inflateSearchBox() {
|
||||
return getLayoutInflater().inflate(R.layout.search_container_all_apps, this, false);
|
||||
}
|
||||
|
||||
/** Creates the adapter provider for the main section. */
|
||||
protected SearchAdapterProvider<?> createMainAdapterProvider() {
|
||||
return new DefaultSearchAdapterProvider(mActivityContext);
|
||||
}
|
||||
|
||||
/** The adapter provider for the main section. */
|
||||
public final SearchAdapterProvider<?> getMainAdapterProvider() {
|
||||
return mMainAdapterProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dispatchRestoreInstanceState(SparseArray<Parcelable> sparseArray) {
|
||||
try {
|
||||
// Many slice view id is not properly assigned, and hence throws null
|
||||
// pointer exception in the underneath method. Catching the exception
|
||||
// simply doesn't restore these slice views. This doesn't have any
|
||||
// user visible effect because because we query them again.
|
||||
super.dispatchRestoreInstanceState(sparseArray);
|
||||
} catch (Exception e) {
|
||||
Log.e("AllAppsContainerView", "restoreInstanceState viewId = 0", e);
|
||||
}
|
||||
|
||||
Bundle state = (Bundle) sparseArray.get(R.id.work_tab_state_id, null);
|
||||
if (state != null) {
|
||||
int currentPage = state.getInt(BUNDLE_KEY_CURRENT_PAGE, 0);
|
||||
if (currentPage == AdapterHolder.WORK && mViewPager != null) {
|
||||
mViewPager.setCurrentPage(currentPage);
|
||||
rebindAdapters();
|
||||
} else {
|
||||
reset(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
|
||||
super.dispatchSaveInstanceState(container);
|
||||
Bundle state = new Bundle();
|
||||
state.putInt(BUNDLE_KEY_CURRENT_PAGE, getCurrentPage());
|
||||
container.put(R.id.work_tab_state_id, state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the long click listener for icons
|
||||
*/
|
||||
public void setOnIconLongClickListener(OnLongClickListener listener) {
|
||||
for (AdapterHolder holder : mAH) {
|
||||
holder.mAdapter.setOnIconLongClickListener(listener);
|
||||
}
|
||||
}
|
||||
|
||||
public AllAppsStore getAppsStore() {
|
||||
return mAllAppsStore;
|
||||
}
|
||||
|
||||
public WorkProfileManager getWorkManager() {
|
||||
return mWorkManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeviceProfileChanged(DeviceProfile dp) {
|
||||
for (AdapterHolder holder : mAH) {
|
||||
holder.mAdapter.setAppsPerRow(dp.numShownAllAppsColumns);
|
||||
if (holder.mRecyclerView != null) {
|
||||
// Remove all views and clear the pool, while keeping the data same. After this
|
||||
// call, all the viewHolders will be recreated.
|
||||
holder.mRecyclerView.swapAdapter(holder.mRecyclerView.getAdapter(), true);
|
||||
holder.mRecyclerView.getRecycledViewPool().clear();
|
||||
}
|
||||
}
|
||||
updateBackground(dp);
|
||||
}
|
||||
|
||||
protected void updateBackground(DeviceProfile deviceProfile) {
|
||||
mBottomSheetBackground.setVisibility(deviceProfile.isTablet ? View.VISIBLE : View.GONE);
|
||||
// Note: For tablets, the opaque background and header protection are added in drawOnScrim.
|
||||
// For the taskbar entrypoint, the scrim is drawn differently, so a static background is
|
||||
// added in TaskbarAllAppsContainerView and header protection is not yet supported.
|
||||
}
|
||||
|
||||
private void onAppsUpdated() {
|
||||
mHasWorkApps = Stream.of(mAllAppsStore.getApps()).anyMatch(mWorkManager.getMatcher());
|
||||
if (!isSearching()) {
|
||||
rebindAdapters();
|
||||
if (mHasWorkApps) {
|
||||
mWorkManager.reset();
|
||||
}
|
||||
}
|
||||
|
||||
mActivityContext.getStatsLogManager().logger()
|
||||
.withCardinality(mAllAppsStore.getApps().length)
|
||||
.log(LAUNCHER_ALLAPPS_COUNT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the view itself will handle the touch event or not.
|
||||
*/
|
||||
public boolean shouldContainerScroll(MotionEvent ev) {
|
||||
BaseDragLayer dragLayer = mActivityContext.getDragLayer();
|
||||
// Scroll if not within the container view (e.g. over large-screen scrim).
|
||||
if (!dragLayer.isEventOverView(getVisibleContainerView(), ev)) {
|
||||
return true;
|
||||
}
|
||||
if (dragLayer.isEventOverView(mBottomSheetHandleArea, ev)) {
|
||||
return true;
|
||||
}
|
||||
AllAppsRecyclerView rv = getActiveRecyclerView();
|
||||
if (rv == null) {
|
||||
return true;
|
||||
}
|
||||
if (rv.getScrollbar() != null
|
||||
&& rv.getScrollbar().getThumbOffsetY() >= 0
|
||||
&& dragLayer.isEventOverView(rv.getScrollbar(), ev)) {
|
||||
return false;
|
||||
}
|
||||
return rv.shouldContainerScroll(ev, dragLayer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
||||
// The AllAppsContainerView houses the QSB and is hence visible from the Workspace
|
||||
// Overview states. We shouldn't intercept for the scrubber in these cases.
|
||||
if (!isInAllApps()) {
|
||||
mTouchHandler = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
|
||||
AllAppsRecyclerView rv = getActiveRecyclerView();
|
||||
if (rv != null && rv.getScrollbar() != null
|
||||
&& rv.getScrollbar().isHitInParent(ev.getX(), ev.getY(), mFastScrollerOffset)) {
|
||||
mTouchHandler = rv.getScrollbar();
|
||||
} else {
|
||||
mTouchHandler = null;
|
||||
}
|
||||
}
|
||||
if (mTouchHandler != null) {
|
||||
return mTouchHandler.handleTouchEvent(ev, mFastScrollerOffset);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent ev) {
|
||||
if (!isInAllApps()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
|
||||
AllAppsRecyclerView rv = getActiveRecyclerView();
|
||||
if (rv != null && rv.getScrollbar() != null
|
||||
&& rv.getScrollbar().isHitInParent(ev.getX(), ev.getY(), mFastScrollerOffset)) {
|
||||
mTouchHandler = rv.getScrollbar();
|
||||
} else {
|
||||
mTouchHandler = null;
|
||||
|
||||
}
|
||||
}
|
||||
if (mTouchHandler != null) {
|
||||
mTouchHandler.handleTouchEvent(ev, mFastScrollerOffset);
|
||||
return true;
|
||||
}
|
||||
if (isSearching()
|
||||
&& mActivityContext.getDragLayer().isEventOverView(getVisibleContainerView(), ev)) {
|
||||
// if in search state, consume touch event.
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Description of the container view based on its current state. */
|
||||
public String getDescription() {
|
||||
StringCache cache = mActivityContext.getStringCache();
|
||||
if (mUsingTabs) {
|
||||
if (cache != null) {
|
||||
return isPersonalTab()
|
||||
? cache.allAppsPersonalTabAccessibility
|
||||
: cache.allAppsWorkTabAccessibility;
|
||||
} else {
|
||||
return isPersonalTab()
|
||||
? getContext().getString(R.string.all_apps_button_personal_label)
|
||||
: getContext().getString(R.string.all_apps_button_work_label);
|
||||
}
|
||||
}
|
||||
return getContext().getString(R.string.all_apps_button_label);
|
||||
}
|
||||
|
||||
/** The current active recycler view (A-Z list from one of the profiles, or search results). */
|
||||
public AllAppsRecyclerView getActiveRecyclerView() {
|
||||
if (isSearching()) {
|
||||
return getSearchRecyclerView();
|
||||
}
|
||||
return getActiveAppsRecyclerView();
|
||||
}
|
||||
|
||||
/** The current apps recycler view in the container. */
|
||||
private AllAppsRecyclerView getActiveAppsRecyclerView() {
|
||||
if (!mUsingTabs || isPersonalTab()) {
|
||||
return mAH.get(AdapterHolder.MAIN).mRecyclerView;
|
||||
} else {
|
||||
return mAH.get(AdapterHolder.WORK).mRecyclerView;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The container for A-Z apps (the ViewPager for main+work tabs, or main RV). This is currently
|
||||
* hidden while searching.
|
||||
**/
|
||||
protected View getAppsRecyclerViewContainer() {
|
||||
return mViewPager != null ? mViewPager : findViewById(R.id.apps_list_view);
|
||||
}
|
||||
|
||||
/** The RV for search results, which is hidden while A-Z apps are visible. */
|
||||
public SearchRecyclerView getSearchRecyclerView() {
|
||||
return mSearchRecyclerView;
|
||||
}
|
||||
|
||||
protected boolean isPersonalTab() {
|
||||
return mViewPager == null || mViewPager.getNextPage() == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Switches the current page to the provided {@code tab} if tabs are supported, otherwise does
|
||||
* nothing.
|
||||
*/
|
||||
public void switchToTab(int tab) {
|
||||
if (mUsingTabs) {
|
||||
mViewPager.setCurrentPage(tab);
|
||||
}
|
||||
}
|
||||
|
||||
public LayoutInflater getLayoutInflater() {
|
||||
return LayoutInflater.from(getContext());
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the state of AllApps.
|
||||
*/
|
||||
public void reset(boolean animate) {
|
||||
for (int i = 0; i < mAH.size(); i++) {
|
||||
if (mAH.get(i).mRecyclerView != null) {
|
||||
mAH.get(i).mRecyclerView.scrollToTop();
|
||||
}
|
||||
}
|
||||
if (isHeaderVisible()) {
|
||||
mHeader.reset(animate);
|
||||
}
|
||||
// Reset the base recycler view after transitioning home.
|
||||
updateHeaderScroll(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDropCompleted(View target, DragObject d, boolean success) {}
|
||||
|
||||
@Override
|
||||
public void setInsets(Rect insets) {
|
||||
mInsets.set(insets);
|
||||
DeviceProfile grid = mActivityContext.getDeviceProfile();
|
||||
|
||||
applyAdapterSideAndBottomPaddings(grid);
|
||||
|
||||
MarginLayoutParams mlp = (MarginLayoutParams) getLayoutParams();
|
||||
mlp.leftMargin = insets.left;
|
||||
mlp.rightMargin = insets.right;
|
||||
setLayoutParams(mlp);
|
||||
|
||||
if (grid.isVerticalBarLayout()) {
|
||||
setPadding(grid.workspacePadding.left, 0, grid.workspacePadding.right, 0);
|
||||
} else {
|
||||
int topPadding = grid.allAppsTopPadding;
|
||||
if (FeatureFlags.ENABLE_FLOATING_SEARCH_BAR.get() && !grid.isTablet) {
|
||||
topPadding += getResources().getDimensionPixelSize(
|
||||
R.dimen.all_apps_additional_top_padding_floating_search);
|
||||
}
|
||||
setPadding(grid.allAppsLeftRightMargin, topPadding, grid.allAppsLeftRightMargin, 0);
|
||||
}
|
||||
|
||||
InsettableFrameLayout.dispatchInsets(this, insets);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a padding in case a scrim is shown on the bottom of the view and a padding is needed.
|
||||
*/
|
||||
protected int computeNavBarScrimHeight(WindowInsets insets) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current height of nav bar scrim
|
||||
*/
|
||||
public int getNavBarScrimHeight() {
|
||||
return mNavBarScrimHeight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) {
|
||||
mNavBarScrimHeight = computeNavBarScrimHeight(insets);
|
||||
applyAdapterSideAndBottomPaddings(mActivityContext.getDeviceProfile());
|
||||
return super.dispatchApplyWindowInsets(insets);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dispatchDraw(Canvas canvas) {
|
||||
super.dispatchDraw(canvas);
|
||||
|
||||
if (mNavBarScrimHeight > 0) {
|
||||
canvas.drawRect(0, getHeight() - mNavBarScrimHeight, getWidth(), getHeight(),
|
||||
mNavBarScrimPaint);
|
||||
}
|
||||
}
|
||||
|
||||
protected void rebindAdapters() {
|
||||
rebindAdapters(false /* force */);
|
||||
}
|
||||
|
||||
protected void rebindAdapters(boolean force) {
|
||||
updateSearchResultsVisibility();
|
||||
|
||||
boolean showTabs = shouldShowTabs();
|
||||
if (showTabs == mUsingTabs && !force) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isSearching()) {
|
||||
mUsingTabs = showTabs;
|
||||
mWorkManager.detachWorkModeSwitch();
|
||||
return;
|
||||
}
|
||||
|
||||
// replaceAppsRVcontainer() needs to use both mUsingTabs value to remove the old view AND
|
||||
// showTabs value to create new view. Hence the mUsingTabs new value assignment MUST happen
|
||||
// after this call.
|
||||
replaceAppsRVContainer(showTabs);
|
||||
mUsingTabs = showTabs;
|
||||
|
||||
mAllAppsStore.unregisterIconContainer(mAH.get(AdapterHolder.MAIN).mRecyclerView);
|
||||
mAllAppsStore.unregisterIconContainer(mAH.get(AdapterHolder.WORK).mRecyclerView);
|
||||
mAllAppsStore.unregisterIconContainer(mAH.get(AdapterHolder.SEARCH).mRecyclerView);
|
||||
|
||||
if (mUsingTabs) {
|
||||
mAH.get(AdapterHolder.MAIN).setup(mViewPager.getChildAt(0), mPersonalMatcher);
|
||||
mAH.get(AdapterHolder.WORK).setup(mViewPager.getChildAt(1), mWorkManager.getMatcher());
|
||||
mAH.get(AdapterHolder.WORK).mRecyclerView.setId(R.id.apps_list_view_work);
|
||||
if (FeatureFlags.ENABLE_EXPANDING_PAUSE_WORK_BUTTON.get()) {
|
||||
mAH.get(AdapterHolder.WORK).mRecyclerView.addOnScrollListener(
|
||||
mWorkManager.newScrollListener());
|
||||
}
|
||||
mViewPager.getPageIndicator().setActiveMarker(AdapterHolder.MAIN);
|
||||
findViewById(R.id.tab_personal)
|
||||
.setOnClickListener((View view) -> {
|
||||
if (mViewPager.snapToPage(AdapterHolder.MAIN)) {
|
||||
mActivityContext.getStatsLogManager().logger()
|
||||
.log(LAUNCHER_ALLAPPS_TAP_ON_PERSONAL_TAB);
|
||||
}
|
||||
mActivityContext.hideKeyboard();
|
||||
});
|
||||
findViewById(R.id.tab_work)
|
||||
.setOnClickListener((View view) -> {
|
||||
if (mViewPager.snapToPage(AdapterHolder.WORK)) {
|
||||
mActivityContext.getStatsLogManager().logger()
|
||||
.log(LAUNCHER_ALLAPPS_TAP_ON_WORK_TAB);
|
||||
}
|
||||
mActivityContext.hideKeyboard();
|
||||
});
|
||||
setDeviceManagementResources();
|
||||
onActivePageChanged(mViewPager.getNextPage());
|
||||
} else {
|
||||
mAH.get(AdapterHolder.MAIN).setup(findViewById(R.id.apps_list_view), null);
|
||||
mAH.get(AdapterHolder.WORK).mRecyclerView = null;
|
||||
}
|
||||
setupHeader();
|
||||
|
||||
mAllAppsStore.registerIconContainer(mAH.get(AdapterHolder.MAIN).mRecyclerView);
|
||||
mAllAppsStore.registerIconContainer(mAH.get(AdapterHolder.WORK).mRecyclerView);
|
||||
mAllAppsStore.registerIconContainer(mAH.get(AdapterHolder.SEARCH).mRecyclerView);
|
||||
}
|
||||
|
||||
protected void updateSearchResultsVisibility() {
|
||||
if (isSearching()) {
|
||||
getSearchRecyclerView().setVisibility(VISIBLE);
|
||||
getAppsRecyclerViewContainer().setVisibility(GONE);
|
||||
mHeader.setVisibility(GONE);
|
||||
} else {
|
||||
getSearchRecyclerView().setVisibility(GONE);
|
||||
getAppsRecyclerViewContainer().setVisibility(VISIBLE);
|
||||
mHeader.setVisibility(VISIBLE);
|
||||
}
|
||||
if (mHeader.isSetUp()) {
|
||||
mHeader.setActiveRV(getCurrentPage());
|
||||
}
|
||||
}
|
||||
|
||||
private void applyAdapterSideAndBottomPaddings(DeviceProfile grid) {
|
||||
int bottomPadding = Math.max(mInsets.bottom, mNavBarScrimHeight);
|
||||
mAH.forEach(adapterHolder -> {
|
||||
adapterHolder.mPadding.bottom = bottomPadding;
|
||||
adapterHolder.mPadding.left =
|
||||
adapterHolder.mPadding.right = grid.allAppsLeftRightPadding;
|
||||
adapterHolder.applyPadding();
|
||||
});
|
||||
}
|
||||
|
||||
private void setDeviceManagementResources() {
|
||||
if (mActivityContext.getStringCache() != null) {
|
||||
Button personalTab = findViewById(R.id.tab_personal);
|
||||
personalTab.setText(mActivityContext.getStringCache().allAppsPersonalTab);
|
||||
|
||||
Button workTab = findViewById(R.id.tab_work);
|
||||
workTab.setText(mActivityContext.getStringCache().allAppsWorkTab);
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean shouldShowTabs() {
|
||||
return mHasWorkApps;
|
||||
}
|
||||
|
||||
protected boolean isSearching() {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected View replaceAppsRVContainer(boolean showTabs) {
|
||||
for (int i = AdapterHolder.MAIN; i <= AdapterHolder.WORK; i++) {
|
||||
AdapterHolder adapterHolder = mAH.get(i);
|
||||
if (adapterHolder.mRecyclerView != null) {
|
||||
adapterHolder.mRecyclerView.setLayoutManager(null);
|
||||
adapterHolder.mRecyclerView.setAdapter(null);
|
||||
}
|
||||
}
|
||||
View oldView = getAppsRecyclerViewContainer();
|
||||
int index = indexOfChild(oldView);
|
||||
removeView(oldView);
|
||||
int layout = showTabs ? R.layout.all_apps_tabs : R.layout.all_apps_rv_layout;
|
||||
View newView = getLayoutInflater().inflate(layout, this, false);
|
||||
addView(newView, index);
|
||||
if (showTabs) {
|
||||
mViewPager = (AllAppsPagedView) newView;
|
||||
mViewPager.initParentViews(this);
|
||||
mViewPager.getPageIndicator().setOnActivePageChangedListener(this);
|
||||
|
||||
mWorkManager.reset();
|
||||
post(() -> mAH.get(AdapterHolder.WORK).applyPadding());
|
||||
|
||||
} else {
|
||||
mWorkManager.detachWorkModeSwitch();
|
||||
mViewPager = null;
|
||||
}
|
||||
return newView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivePageChanged(int currentActivePage) {
|
||||
if (mAH.get(currentActivePage).mRecyclerView != null) {
|
||||
mAH.get(currentActivePage).mRecyclerView.bindFastScrollbar();
|
||||
}
|
||||
// Header keeps track of active recycler view to properly render header protection.
|
||||
mHeader.setActiveRV(currentActivePage);
|
||||
reset(true /* animate */);
|
||||
|
||||
mWorkManager.onActivePageChanged(currentActivePage);
|
||||
}
|
||||
|
||||
// Used by tests only
|
||||
private boolean isDescendantViewVisible(int viewId) {
|
||||
final View view = findViewById(viewId);
|
||||
if (view == null) return false;
|
||||
|
||||
if (!view.isShown()) return false;
|
||||
|
||||
return view.getGlobalVisibleRect(new Rect());
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public boolean isPersonalTabVisible() {
|
||||
return isDescendantViewVisible(R.id.tab_personal);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public boolean isWorkTabVisible() {
|
||||
return isDescendantViewVisible(R.id.tab_work);
|
||||
}
|
||||
|
||||
public AlphabeticalAppsList<T> getSearchResultList() {
|
||||
return mAH.get(AdapterHolder.SEARCH).mAppsList;
|
||||
}
|
||||
|
||||
public FloatingHeaderView getFloatingHeaderView() {
|
||||
return mHeader;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public View getContentView() {
|
||||
return isSearching() ? getSearchRecyclerView() : getAppsRecyclerViewContainer();
|
||||
}
|
||||
|
||||
/** The current page visible in all apps. */
|
||||
public int getCurrentPage() {
|
||||
return isSearching()
|
||||
? AdapterHolder.SEARCH
|
||||
: mViewPager == null ? AdapterHolder.MAIN : mViewPager.getNextPage();
|
||||
}
|
||||
|
||||
/** The scroll bar for the active apps recycler view. */
|
||||
public RecyclerViewFastScroller getScrollBar() {
|
||||
AllAppsRecyclerView rv = getActiveAppsRecyclerView();
|
||||
return rv == null ? null : rv.getScrollbar();
|
||||
}
|
||||
|
||||
void setupHeader() {
|
||||
mHeader.setVisibility(View.VISIBLE);
|
||||
boolean tabsHidden = !mUsingTabs;
|
||||
mHeader.setup(
|
||||
mAH.get(AdapterHolder.MAIN).mRecyclerView,
|
||||
mAH.get(AdapterHolder.WORK).mRecyclerView,
|
||||
(SearchRecyclerView) mAH.get(AdapterHolder.SEARCH).mRecyclerView,
|
||||
getCurrentPage(),
|
||||
tabsHidden);
|
||||
|
||||
int padding = mHeader.getMaxTranslation();
|
||||
mAH.forEach(adapterHolder -> {
|
||||
adapterHolder.mPadding.top = padding;
|
||||
adapterHolder.applyPadding();
|
||||
if (adapterHolder.mRecyclerView != null) {
|
||||
adapterHolder.mRecyclerView.scrollToTop();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public boolean isHeaderVisible() {
|
||||
return mHeader != null && mHeader.getVisibility() == View.VISIBLE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an update listener to animator that adds springs to the animation.
|
||||
*/
|
||||
public void addSpringFromFlingUpdateListener(ValueAnimator animator,
|
||||
float velocity /* release velocity */,
|
||||
float progress /* portion of the distance to travel*/) {
|
||||
animator.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationStart(Animator animator) {
|
||||
float distance = (1 - progress) * getHeight(); // px
|
||||
float settleVelocity = Math.min(0, distance
|
||||
/ (AllAppsTransitionController.INTERP_COEFF * animator.getDuration())
|
||||
+ velocity);
|
||||
absorbSwipeUpVelocity(Math.max(1000, Math.abs(
|
||||
Math.round(settleVelocity * FLING_VELOCITY_MULTIPLIER))));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** Invoked when the container is pulled. */
|
||||
public void onPull(float deltaDistance, float displacement) {
|
||||
absorbPullDeltaDistance(PULL_MULTIPLIER * deltaDistance, PULL_MULTIPLIER * displacement);
|
||||
// Current motion spec is to actually push and not pull
|
||||
// on this surface. However, until EdgeEffect.onPush (b/190612804) is
|
||||
// implemented at view level, we will simply pull
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getDrawingRect(Rect outRect) {
|
||||
super.getDrawingRect(outRect);
|
||||
outRect.offset(0, (int) getTranslationY());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTranslationY(float translationY) {
|
||||
super.setTranslationY(translationY);
|
||||
invalidateHeader();
|
||||
}
|
||||
|
||||
public void setScrimView(ScrimView scrimView) {
|
||||
mScrimView = scrimView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawOnScrimWithScale(Canvas canvas, float scale) {
|
||||
boolean isTablet = mActivityContext.getDeviceProfile().isTablet;
|
||||
|
||||
// Draw full background panel for tablets.
|
||||
if (isTablet) {
|
||||
mHeaderPaint.setColor(mBottomSheetBackgroundColor);
|
||||
View panel = (View) mBottomSheetBackground;
|
||||
float translationY = ((View) panel.getParent()).getTranslationY();
|
||||
mTmpRectF.set(panel.getLeft(), panel.getTop() + translationY,
|
||||
panel.getRight(), panel.getBottom());
|
||||
mTmpPath.reset();
|
||||
mTmpPath.addRoundRect(mTmpRectF, mBottomSheetCornerRadii, Direction.CW);
|
||||
canvas.drawPath(mTmpPath, mHeaderPaint);
|
||||
}
|
||||
|
||||
if (DEBUG_HEADER_PROTECTION) {
|
||||
mHeaderPaint.setColor(Color.MAGENTA);
|
||||
mHeaderPaint.setAlpha(255);
|
||||
} else {
|
||||
mHeaderPaint.setColor(mHeaderColor);
|
||||
mHeaderPaint.setAlpha((int) (getAlpha() * Color.alpha(mHeaderColor)));
|
||||
}
|
||||
if (mHeaderPaint.getColor() == mScrimColor || mHeaderPaint.getColor() == 0) {
|
||||
return;
|
||||
}
|
||||
final float offset = (getVisibleContainerView().getHeight() * (1 - scale) / 2);
|
||||
final float bottom =
|
||||
scale * (getHeaderBottom() + getVisibleContainerView().getPaddingTop()) + offset;
|
||||
FloatingHeaderView headerView = getFloatingHeaderView();
|
||||
if (isTablet) {
|
||||
// Start adding header protection if search bar or tabs will attach to the top.
|
||||
if (!FeatureFlags.ENABLE_FLOATING_SEARCH_BAR.get() || mUsingTabs) {
|
||||
View panel = (View) mBottomSheetBackground;
|
||||
float translationY = ((View) panel.getParent()).getTranslationY();
|
||||
mTmpRectF.set(panel.getLeft(), panel.getTop() + translationY, panel.getRight(),
|
||||
bottom);
|
||||
mTmpPath.reset();
|
||||
mTmpPath.addRoundRect(mTmpRectF, mBottomSheetCornerRadii, Direction.CW);
|
||||
canvas.drawPath(mTmpPath, mHeaderPaint);
|
||||
}
|
||||
} else {
|
||||
canvas.drawRect(0, 0, canvas.getWidth(), bottom, mHeaderPaint);
|
||||
}
|
||||
int tabsHeight = headerView.getPeripheralProtectionHeight();
|
||||
if (mTabsProtectionAlpha > 0 && tabsHeight != 0) {
|
||||
if (DEBUG_HEADER_PROTECTION) {
|
||||
mHeaderPaint.setColor(Color.BLUE);
|
||||
mHeaderPaint.setAlpha(255);
|
||||
} else {
|
||||
mHeaderPaint.setAlpha((int) (getAlpha() * mTabsProtectionAlpha));
|
||||
}
|
||||
int left = 0;
|
||||
int right = canvas.getWidth();
|
||||
if (isTablet) {
|
||||
left = mBottomSheetBackground.getLeft();
|
||||
right = mBottomSheetBackground.getRight();
|
||||
}
|
||||
canvas.drawRect(left, bottom, right, bottom + tabsHeight, mHeaderPaint);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* redraws header protection
|
||||
*/
|
||||
public void invalidateHeader() {
|
||||
if (mScrimView != null) {
|
||||
mScrimView.invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
protected void updateHeaderScroll(int scrolledOffset) {
|
||||
float prog = Utilities.boundToRange((float) scrolledOffset / mHeaderThreshold, 0f, 1f);
|
||||
int headerColor = getHeaderColor(prog);
|
||||
int tabsAlpha = mHeader.getPeripheralProtectionHeight() == 0 ? 0
|
||||
: (int) (Utilities.boundToRange(
|
||||
(scrolledOffset + mHeader.mSnappedScrolledY) / mHeaderThreshold, 0f, 1f)
|
||||
* 255);
|
||||
if (headerColor != mHeaderColor || mTabsProtectionAlpha != tabsAlpha) {
|
||||
mHeaderColor = headerColor;
|
||||
mTabsProtectionAlpha = tabsAlpha;
|
||||
invalidateHeader();
|
||||
}
|
||||
}
|
||||
|
||||
protected int getHeaderColor(float blendRatio) {
|
||||
return ColorUtils.blendARGB(mScrimColor, mHeaderProtectionColor, blendRatio);
|
||||
}
|
||||
|
||||
protected abstract BaseAllAppsAdapter<T> createAdapter(AlphabeticalAppsList<T> mAppsList,
|
||||
BaseAdapterProvider[] adapterProviders);
|
||||
|
||||
public int getHeaderBottom() {
|
||||
int bottom = (int) getTranslationY() + mHeader.getClipTop();
|
||||
if (FeatureFlags.ENABLE_FLOATING_SEARCH_BAR.get()) {
|
||||
if (mActivityContext.getDeviceProfile().isTablet) {
|
||||
return bottom + mBottomSheetBackground.getTop();
|
||||
}
|
||||
return bottom;
|
||||
}
|
||||
return bottom + mHeader.getTop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a view that denotes the visible part of all apps container view.
|
||||
*/
|
||||
public View getVisibleContainerView() {
|
||||
return mActivityContext.getDeviceProfile().isTablet ? mBottomSheetBackground : this;
|
||||
}
|
||||
|
||||
protected void onInitializeRecyclerView(RecyclerView rv) {
|
||||
rv.addOnScrollListener(mScrollListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} the All Apps UI is currently being displayed on the target surface and
|
||||
* is interactive.
|
||||
*/
|
||||
public abstract boolean isInAllApps();
|
||||
|
||||
/** Holds a {@link BaseAllAppsAdapter} and related fields. */
|
||||
public class AdapterHolder {
|
||||
public static final int MAIN = 0;
|
||||
public static final int WORK = 1;
|
||||
public static final int SEARCH = 2;
|
||||
|
||||
private final int mType;
|
||||
public final BaseAllAppsAdapter<T> mAdapter;
|
||||
final RecyclerView.LayoutManager mLayoutManager;
|
||||
final AlphabeticalAppsList<T> mAppsList;
|
||||
final Rect mPadding = new Rect();
|
||||
AllAppsRecyclerView mRecyclerView;
|
||||
|
||||
AdapterHolder(int type) {
|
||||
mType = type;
|
||||
mAppsList = new AlphabeticalAppsList<>(mActivityContext,
|
||||
isSearch() ? null : mAllAppsStore,
|
||||
isWork() ? mWorkManager : null);
|
||||
BaseAdapterProvider[] adapterProviders =
|
||||
new BaseAdapterProvider[]{mMainAdapterProvider};
|
||||
|
||||
mAdapter = createAdapter(mAppsList, adapterProviders);
|
||||
mAppsList.setAdapter(mAdapter);
|
||||
mLayoutManager = mAdapter.getLayoutManager();
|
||||
}
|
||||
|
||||
void setup(@NonNull View rv, @Nullable Predicate<ItemInfo> matcher) {
|
||||
mAppsList.updateItemFilter(matcher);
|
||||
mRecyclerView = (AllAppsRecyclerView) rv;
|
||||
mRecyclerView.setEdgeEffectFactory(createEdgeEffectFactory());
|
||||
mRecyclerView.setApps(mAppsList);
|
||||
mRecyclerView.setLayoutManager(mLayoutManager);
|
||||
mRecyclerView.setAdapter(mAdapter);
|
||||
mRecyclerView.setHasFixedSize(true);
|
||||
// No animations will occur when changes occur to the items in this RecyclerView.
|
||||
mRecyclerView.setItemAnimator(null);
|
||||
onInitializeRecyclerView(mRecyclerView);
|
||||
FocusedItemDecorator focusedItemDecorator = new FocusedItemDecorator(mRecyclerView);
|
||||
mRecyclerView.addItemDecoration(focusedItemDecorator);
|
||||
mAdapter.setIconFocusListener(focusedItemDecorator.getFocusListener());
|
||||
applyPadding();
|
||||
}
|
||||
|
||||
void applyPadding() {
|
||||
if (mRecyclerView != null) {
|
||||
int bottomOffset = 0;
|
||||
if (isWork() && mWorkManager.getWorkModeSwitch() != null) {
|
||||
bottomOffset = mInsets.bottom + mWorkManager.getWorkModeSwitch().getHeight();
|
||||
}
|
||||
mRecyclerView.setPadding(mPadding.left, mPadding.top, mPadding.right,
|
||||
mPadding.bottom + bottomOffset);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isWork() {
|
||||
return mType == WORK;
|
||||
}
|
||||
|
||||
private boolean isSearch() {
|
||||
return mType == SEARCH;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.android.launcher3.Insettable;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.allapps.BaseAllAppsContainerView.AdapterHolder;
|
||||
import com.android.launcher3.allapps.ActivityAllAppsContainerView.AdapterHolder;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
|
||||
import com.android.launcher3.views.ActivityContext;
|
||||
@@ -72,8 +72,8 @@ public class FloatingHeaderView extends LinearLayout implements
|
||||
moved(current);
|
||||
applyVerticalMove();
|
||||
if (headerCollapsed != mHeaderCollapsed) {
|
||||
BaseAllAppsContainerView<?> parent =
|
||||
(BaseAllAppsContainerView<?>) getParent();
|
||||
ActivityAllAppsContainerView<?> parent =
|
||||
(ActivityAllAppsContainerView<?>) getParent();
|
||||
parent.invalidateHeader();
|
||||
}
|
||||
}
|
||||
@@ -191,7 +191,7 @@ public class FloatingHeaderView extends LinearLayout implements
|
||||
updateExpectedHeight();
|
||||
|
||||
if (mMaxTranslation != oldMaxHeight || mFloatingRowsCollapsed) {
|
||||
BaseAllAppsContainerView<?> parent = (BaseAllAppsContainerView<?>) getParent();
|
||||
ActivityAllAppsContainerView parent = (ActivityAllAppsContainerView) getParent();
|
||||
if (parent != null) {
|
||||
parent.setupHeader();
|
||||
}
|
||||
|
||||
@@ -16,11 +16,11 @@
|
||||
package com.android.launcher3.allapps;
|
||||
|
||||
import static com.android.launcher3.LauncherPrefs.WORK_EDU_STEP;
|
||||
import static com.android.launcher3.allapps.ActivityAllAppsContainerView.AdapterHolder.MAIN;
|
||||
import static com.android.launcher3.allapps.ActivityAllAppsContainerView.AdapterHolder.SEARCH;
|
||||
import static com.android.launcher3.allapps.ActivityAllAppsContainerView.AdapterHolder.WORK;
|
||||
import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_WORK_DISABLED_CARD;
|
||||
import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_WORK_EDU_CARD;
|
||||
import static com.android.launcher3.allapps.BaseAllAppsContainerView.AdapterHolder.MAIN;
|
||||
import static com.android.launcher3.allapps.BaseAllAppsContainerView.AdapterHolder.SEARCH;
|
||||
import static com.android.launcher3.allapps.BaseAllAppsContainerView.AdapterHolder.WORK;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TURN_OFF_WORK_APPS_TAP;
|
||||
import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_HAS_SHORTCUT_PERMISSION;
|
||||
import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_QUIET_MODE_CHANGE_PERMISSION;
|
||||
@@ -54,7 +54,7 @@ import java.util.ArrayList;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* Companion class for {@link BaseAllAppsContainerView} to manage work tab and personal tab
|
||||
* Companion class for {@link ActivityAllAppsContainerView} to manage work tab and personal tab
|
||||
* related
|
||||
* logic based on {@link WorkProfileState}?
|
||||
*/
|
||||
@@ -79,7 +79,7 @@ public class WorkProfileManager implements PersonalWorkSlidingTabStrip.OnActiveP
|
||||
public @interface WorkProfileState { }
|
||||
|
||||
private final UserManager mUserManager;
|
||||
private final BaseAllAppsContainerView<?> mAllApps;
|
||||
private final ActivityAllAppsContainerView<?> mAllApps;
|
||||
private final Predicate<ItemInfo> mMatcher;
|
||||
private final StatsLogManager mStatsLogManager;
|
||||
|
||||
@@ -89,7 +89,7 @@ public class WorkProfileManager implements PersonalWorkSlidingTabStrip.OnActiveP
|
||||
private int mCurrentState;
|
||||
|
||||
public WorkProfileManager(
|
||||
UserManager userManager, BaseAllAppsContainerView<?> allApps,
|
||||
UserManager userManager, ActivityAllAppsContainerView allApps,
|
||||
StatsLogManager statsLogManager) {
|
||||
mUserManager = userManager;
|
||||
mAllApps = allApps;
|
||||
@@ -152,7 +152,7 @@ public class WorkProfileManager implements PersonalWorkSlidingTabStrip.OnActiveP
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and attaches for profile toggle button to {@link BaseAllAppsContainerView}
|
||||
* Creates and attaches for profile toggle button to {@link ActivityAllAppsContainerView}
|
||||
*/
|
||||
public boolean attachWorkModeSwitch() {
|
||||
if (!mAllApps.getAppsStore().hasModelFlag(
|
||||
@@ -177,7 +177,7 @@ public class WorkProfileManager implements PersonalWorkSlidingTabStrip.OnActiveP
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Removes work profile toggle button from {@link BaseAllAppsContainerView}
|
||||
* Removes work profile toggle button from {@link ActivityAllAppsContainerView}
|
||||
*/
|
||||
public void detachWorkModeSwitch() {
|
||||
if (mWorkModeSwitch != null && mWorkModeSwitch.getParent() == mAllApps) {
|
||||
@@ -195,7 +195,7 @@ public class WorkProfileManager implements PersonalWorkSlidingTabStrip.OnActiveP
|
||||
return mWorkModeSwitch;
|
||||
}
|
||||
|
||||
private BaseAllAppsContainerView<?>.AdapterHolder getAH() {
|
||||
private ActivityAllAppsContainerView.AdapterHolder getAH() {
|
||||
return mAllApps.mAH.get(WORK);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package com.android.launcher3.allapps.search;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
@@ -37,12 +36,6 @@ public abstract class SearchAdapterProvider<T extends ActivityContext> extends B
|
||||
mLauncher = launcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from LiveSearchManager to notify slice status updates.
|
||||
*/
|
||||
public void onSliceStatusUpdate(Uri sliceUri) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles selection event on search adapter item. Returns false if provider can not handle
|
||||
* event
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user