Snap for 9528303 from ab83443fe8 to udc-release

Change-Id: I0d0d5df8cdd6587dc6d519007f634a903bcbde38
This commit is contained in:
Android Build Coastguard Worker
2023-01-26 04:26:55 +00:00
22 changed files with 1090 additions and 1117 deletions
@@ -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;
}
+57 -26
View File
@@ -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
+3 -6
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
@@ -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