Snap for 8340624 from 6c7b0f7db8 to tm-release

Change-Id: Ia76757e74f6f6df7e31a7b6ea9590ea5d0d1bc86
This commit is contained in:
Android Build Coastguard Worker
2022-03-23 01:08:38 +00:00
39 changed files with 504 additions and 187 deletions
@@ -51,6 +51,12 @@
<include layout="@layout/all_apps_personal_work_tabs" />
</com.android.launcher3.allapps.FloatingHeaderView>
<com.android.launcher3.taskbar.allapps.TaskbarAllAppsFallbackSearchContainer
android:id="@+id/search_container_all_apps"
android:layout_width="0dp"
android:layout_height="0dp"
android:visibility="gone" />
<include layout="@layout/all_apps_fast_scroller" />
</com.android.launcher3.taskbar.allapps.TaskbarAllAppsContainerView>
</com.android.launcher3.taskbar.allapps.TaskbarAllAppsSlideInView>
@@ -23,14 +23,14 @@ import com.android.launcher3.DeviceProfile;
import com.android.launcher3.DeviceProfile.DeviceProfileListenable;
import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.views.AppLauncher;
import java.util.ArrayList;
import java.util.List;
// TODO(b/218912746): Share more behavior to avoid all apps context depending directly on taskbar.
/** Base for common behavior between taskbar window contexts. */
public abstract class BaseTaskbarContext extends ContextThemeWrapper implements ActivityContext,
public abstract class BaseTaskbarContext extends ContextThemeWrapper implements AppLauncher,
DeviceProfileListenable {
protected final LayoutInflater mLayoutInflater;
@@ -442,7 +442,8 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
mControllers.stashedHandleViewController.setIsHomeButtonDisabled(
mControllers.navbarButtonsViewController.isHomeDisabled());
mControllers.taskbarKeyguardController.updateStateForSysuiFlags(systemUiStateFlags);
mControllers.taskbarStashController.updateStateForSysuiFlags(systemUiStateFlags, fromInit);
mControllers.taskbarStashController.updateStateForSysuiFlags(
systemUiStateFlags, fromInit || !isUserSetupComplete());
mControllers.taskbarScrimViewController.updateStateForSysuiFlags(systemUiStateFlags,
fromInit);
mControllers.navButtonController.updateSysuiFlags(systemUiStateFlags);
@@ -54,6 +54,10 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba
public static final int FLAG_STASHED_IN_APP_IME = 1 << 5; // IME is visible
public static final int FLAG_IN_STASHED_LAUNCHER_STATE = 1 << 6;
public static final int FLAG_STASHED_IN_APP_ALL_APPS = 1 << 7; // All apps is visible.
public static final int FLAG_IN_SETUP = 1 << 8; // In the Setup Wizard
// If any of these flags are enabled, isInApp should return true.
private static final int FLAGS_IN_APP = FLAG_IN_APP | FLAG_IN_SETUP;
// If we're in an app and any of these flags are enabled, taskbar should be stashed.
private static final int FLAGS_STASHED_IN_APP = FLAG_STASHED_IN_APP_MANUAL
@@ -141,7 +145,7 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba
// Evaluate whether the handle should be stashed
private final StatePropertyHolder mStatePropertyHolder = new StatePropertyHolder(
flags -> {
boolean inApp = hasAnyFlag(flags, FLAG_IN_APP);
boolean inApp = hasAnyFlag(flags, FLAGS_IN_APP);
boolean stashedInApp = hasAnyFlag(flags, FLAGS_STASHED_IN_APP);
boolean stashedLauncherState = hasAnyFlag(flags, FLAG_IN_STASHED_LAUNCHER_STATE);
return (inApp && stashedInApp) || (!inApp && stashedLauncherState);
@@ -179,10 +183,7 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba
boolean isInSetup = !mActivity.isUserSetupComplete() || sharedState.setupUIVisible;
updateStateForFlag(FLAG_STASHED_IN_APP_MANUAL, isManuallyStashedInApp);
updateStateForFlag(FLAG_STASHED_IN_APP_SETUP, isInSetup);
if (isInSetup) {
// Update the in-app state to ensure isStashed() reflects right state during SUW
updateStateForFlag(FLAG_IN_APP, true);
}
updateStateForFlag(FLAG_IN_SETUP, isInSetup);
applyState();
notifyStashChange(/* visible */ false, /* stashed */ isStashedInApp());
@@ -216,9 +217,10 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba
* Sets the flag indicating setup UI is visible
*/
protected void setSetupUIVisible(boolean isVisible) {
updateStateForFlag(FLAG_STASHED_IN_APP_SETUP,
isVisible || !mActivity.isUserSetupComplete());
applyState();
boolean hideTaskbar = isVisible || !mActivity.isUserSetupComplete();
updateStateForFlag(FLAG_IN_SETUP, hideTaskbar);
updateStateForFlag(FLAG_STASHED_IN_APP_SETUP, hideTaskbar);
applyState(hideTaskbar ? 0 : TASKBAR_STASH_DURATION);
}
/**
@@ -259,7 +261,7 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba
}
private boolean isInApp() {
return hasAnyFlag(FLAG_IN_APP);
return hasAnyFlag(FLAGS_IN_APP);
}
/**
@@ -478,7 +480,7 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba
}
public void applyState() {
applyState(TASKBAR_STASH_DURATION);
applyState(hasAnyFlag(FLAG_IN_SETUP) ? 0 : TASKBAR_STASH_DURATION);
}
public void applyState(long duration) {
@@ -568,8 +570,8 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba
if (hasAnyFlag(changedFlags, FLAGS_STASHED_IN_APP)) {
mControllers.uiController.onStashedInAppChanged();
}
if (hasAnyFlag(changedFlags, FLAGS_STASHED_IN_APP | FLAG_IN_APP)) {
notifyStashChange(/* visible */ hasAnyFlag(FLAG_IN_APP),
if (hasAnyFlag(changedFlags, FLAGS_STASHED_IN_APP | FLAGS_IN_APP)) {
notifyStashChange(/* visible */ hasAnyFlag(FLAGS_IN_APP),
/* stashed */ isStashedInApp());
}
if (hasAnyFlag(changedFlags, FLAG_STASHED_IN_APP_MANUAL)) {
@@ -613,6 +615,7 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba
str.add((flags & FLAG_IN_STASHED_LAUNCHER_STATE) != 0
? "FLAG_IN_STASHED_LAUNCHER_STATE" : "");
str.add((flags & FLAG_STASHED_IN_APP_ALL_APPS) != 0 ? "FLAG_STASHED_IN_APP_ALL_APPS" : "");
str.add((flags & FLAG_IN_SETUP) != 0 ? "FLAG_IN_SETUP" : "");
return str.toString();
}
@@ -17,22 +17,17 @@ package com.android.launcher3.taskbar.allapps;
import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowInsets;
import androidx.recyclerview.widget.RecyclerView;
import com.android.launcher3.allapps.ActivityAllAppsContainerView;
import com.android.launcher3.allapps.AllAppsGridAdapter;
import com.android.launcher3.allapps.AlphabeticalAppsList;
import com.android.launcher3.allapps.BaseAdapterProvider;
import com.android.launcher3.allapps.BaseAllAppsAdapter;
import com.android.launcher3.allapps.BaseAllAppsContainerView;
import com.android.launcher3.allapps.search.SearchAdapterProvider;
/** All apps container accessible from taskbar. */
public class TaskbarAllAppsContainerView extends BaseAllAppsContainerView<TaskbarAllAppsContext> {
public class TaskbarAllAppsContainerView extends
ActivityAllAppsContainerView<TaskbarAllAppsContext> {
public TaskbarAllAppsContainerView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
@@ -42,41 +37,6 @@ public class TaskbarAllAppsContainerView extends BaseAllAppsContainerView<Taskba
super(context, attrs, defStyleAttr);
}
@Override
protected SearchAdapterProvider<?> createMainAdapterProvider() {
// Taskbar all apps does not yet support search, so this implementation is minimal.
return new SearchAdapterProvider<TaskbarAllAppsContext>(mActivityContext) {
@Override
public boolean launchHighlightedItem() {
return false;
}
@Override
public View getHighlightedItem() {
return null;
}
@Override
public RecyclerView.ItemDecoration getDecorator() {
return null;
}
@Override
public boolean isViewSupported(int viewType) {
return false;
}
@Override
public void onBindView(AllAppsGridAdapter.ViewHolder holder, int position) { }
@Override
public AllAppsGridAdapter.ViewHolder onCreateViewHolder(LayoutInflater layoutInflater,
ViewGroup parent, int viewType) {
return null;
}
};
}
@Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
setInsets(insets.getInsets(WindowInsets.Type.systemBars()).toRect());
@@ -32,6 +32,9 @@ import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.allapps.ActivityAllAppsContainerView;
import com.android.launcher3.allapps.search.DefaultSearchAdapterProvider;
import com.android.launcher3.allapps.search.SearchAdapterProvider;
import com.android.launcher3.dot.DotInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.popup.PopupDataProvider;
@@ -154,6 +157,12 @@ class TaskbarAllAppsContext extends BaseTaskbarContext {
@Override
public void onPopupVisibilityChanged(boolean isVisible) {}
@Override
public SearchAdapterProvider<?> createSearchAdapterProvider(
ActivityAllAppsContainerView<?> appsView) {
return new DefaultSearchAdapterProvider(this);
}
/** Root drag layer for this context. */
private static class TaskbarAllAppsDragLayer extends
BaseDragLayer<TaskbarAllAppsContext> implements OnComputeInsetsListener {
@@ -0,0 +1,54 @@
/*
* Copyright (C) 2022 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.taskbar.allapps;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import androidx.annotation.Nullable;
import com.android.launcher3.ExtendedEditText;
import com.android.launcher3.allapps.ActivityAllAppsContainerView;
import com.android.launcher3.allapps.SearchUiManager;
/** Empty search container for Taskbar All Apps used as a fallback if search is not supported. */
public class TaskbarAllAppsFallbackSearchContainer extends View implements SearchUiManager {
public TaskbarAllAppsFallbackSearchContainer(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public TaskbarAllAppsFallbackSearchContainer(
Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public void initializeSearch(ActivityAllAppsContainerView<?> containerView) {
// Do nothing.
}
@Override
public void resetSearch() {
// Do nothing.
}
@Nullable
@Override
public ExtendedEditText getEditText() {
return null;
}
}
@@ -1273,8 +1273,7 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
HomeAnimationFactory homeAnimFactory =
createHomeAnimationFactory(cookies, duration, isTranslucent, appCanEnterPip,
runningTaskTarget);
mIsSwipingPipToHome = !mIsSwipeForStagedSplit
&& homeAnimFactory.supportSwipePipToHome() && appCanEnterPip;
mIsSwipingPipToHome = !mIsSwipeForStagedSplit && appCanEnterPip;
final RectFSpringAnim[] windowAnim;
if (mIsSwipingPipToHome) {
mSwipePipToHomeAnimator = createWindowAnimationToPip(
@@ -50,12 +50,14 @@ import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.anim.SpringAnimationBuilder;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.util.DisplayController;
import com.android.quickstep.fallback.FallbackRecentsView;
import com.android.quickstep.fallback.RecentsState;
@@ -93,6 +95,8 @@ public class FallbackSwipeHandler extends
private final Matrix mTmpMatrix = new Matrix();
private float mMaxLauncherScale = 1;
private boolean mAppCanEnterPip;
public FallbackSwipeHandler(Context context, RecentsAnimationDeviceState deviceState,
TaskAnimationManager taskAnimationManager, GestureState gestureState, long touchTimeMs,
boolean continuingLastGesture, InputConsumerController inputConsumer) {
@@ -135,16 +139,27 @@ public class FallbackSwipeHandler extends
protected HomeAnimationFactory createHomeAnimationFactory(ArrayList<IBinder> launchCookies,
long duration, boolean isTargetTranslucent, boolean appCanEnterPip,
RemoteAnimationTargetCompat runningTaskTarget) {
mAppCanEnterPip = appCanEnterPip;
if (appCanEnterPip) {
return new FallbackPipToHomeAnimationFactory();
}
mActiveAnimationFactory = new FallbackHomeAnimationFactory(duration);
startHomeIntent(mActiveAnimationFactory);
return mActiveAnimationFactory;
}
private void startHomeIntent(
@Nullable FallbackHomeAnimationFactory gestureContractAnimationFactory) {
ActivityOptions options = ActivityOptions.makeCustomAnimation(mContext, 0, 0);
Intent intent = new Intent(mGestureState.getHomeIntent());
mActiveAnimationFactory.addGestureContract(intent);
if (gestureContractAnimationFactory != null) {
gestureContractAnimationFactory.addGestureContract(intent);
}
try {
mContext.startActivity(intent, options.toBundle());
} catch (NullPointerException | ActivityNotFoundException | SecurityException e) {
mContext.startActivity(createHomeIntent());
}
return mActiveAnimationFactory;
}
@Override
@@ -160,8 +175,19 @@ public class FallbackSwipeHandler extends
@Override
protected void finishRecentsControllerToHome(Runnable callback) {
final Runnable recentsCallback;
if (mAppCanEnterPip) {
// Make sure Launcher is resumed after auto-enter-pip transition to actually trigger
// the PiP task appearing.
recentsCallback = () -> {
callback.run();
startHomeIntent(null /* gestureContractAnimationFactory */);
};
} else {
recentsCallback = callback;
}
mRecentsAnimationController.finish(
false /* toRecents */, callback, true /* sendUserLeaveHint */);
mAppCanEnterPip /* toRecents */, recentsCallback, true /* sendUserLeaveHint */);
}
@Override
@@ -186,6 +212,17 @@ public class FallbackSwipeHandler extends
}
}
private class FallbackPipToHomeAnimationFactory extends HomeAnimationFactory {
@NonNull
@Override
public AnimatorPlaybackController createActivityAnimationToHome() {
// copied from {@link LauncherSwipeHandlerV2.LauncherHomeAnimationFactory}
long accuracy = 2 * Math.max(mDp.widthPx, mDp.heightPx);
return mActivity.getStateManager().createAnimationToNewWorkspace(
RecentsState.HOME, accuracy, StateAnimationConfig.SKIP_ALL_ANIMATIONS);
}
}
private class FallbackHomeAnimationFactory extends HomeAnimationFactory {
private final Rect mTempRect = new Rect();
private final TransformParams mHomeAlphaParams = new TransformParams();
@@ -284,10 +284,5 @@ public class LauncherSwipeHandlerV2 extends
getViewIgnoredInWorkspaceRevealAnimation())
.start();
}
@Override
public boolean supportSwipePipToHome() {
return true;
}
}
}
@@ -183,14 +183,6 @@ public abstract class SwipeUpAnimationLogic implements
public void onCancel() { }
/**
* @return {@code true} if this factory supports animating an Activity to PiP window on
* swiping up to home.
*/
public boolean supportSwipePipToHome() {
return false;
}
/**
* @param progress The progress of the animation to the home screen.
* @return The current alpha to set on the animating app window.
@@ -306,7 +306,7 @@ public final class DigitalWellBeingToast {
private void setBanner(@Nullable View view) {
mBanner = view;
if (view != null) {
if (view != null && mTaskView.getRecentsView() != null) {
setupAndAddBanner();
setBannerOutline();
}
@@ -271,7 +271,8 @@ public class GroupedTaskView extends TaskView {
getPagedOrientationHandler().setSplitIconParams(mIconView, mIconView2,
taskIconHeight, mSnapshotView.getMeasuredWidth(), mSnapshotView.getMeasuredHeight(),
isRtl, deviceProfile, mSplitBoundsConfig);
getMeasuredHeight(), getMeasuredWidth(), isRtl, deviceProfile,
mSplitBoundsConfig);
}
private void updateSecondaryDwbPlacement() {
@@ -890,15 +890,7 @@ public class TaskView extends FrameLayout implements Reusable {
if (confirmSecondSplitSelectApp()) {
return;
}
if (ENABLE_QUICKSTEP_LIVE_TILE.get() && isRunningTask()) {
RecentsView recentsView = getRecentsView();
recentsView.switchToScreenshot(
() -> recentsView.finishRecentsAnimation(true /* toRecents */,
false /* shouldPip */,
() -> showTaskMenu(iconView)));
} else {
showTaskMenu(iconView);
}
showTaskMenu(iconView);
});
iconView.setOnLongClickListener(v -> {
requestDisallowInterceptTouchEvent(true);
@@ -1008,8 +1000,11 @@ public class TaskView extends FrameLayout implements Reusable {
// resetViewTransforms is called during Quickswitch scrolling.
mDismissTranslationX = mTaskOffsetTranslationX =
mTaskResistanceTranslationX = mSplitSelectTranslationX = mGridEndTranslationX = 0f;
mDismissTranslationY = mTaskOffsetTranslationY = mTaskResistanceTranslationY =
mSplitSelectTranslationY = 0f;
mDismissTranslationY = mTaskOffsetTranslationY = mTaskResistanceTranslationY = 0f;
if (getRecentsView() == null || !getRecentsView().isSplitSelectionActive()) {
mSplitSelectTranslationY = 0f;
}
setSnapshotScale(1f);
applyTranslationX();
applyTranslationY();
+6 -3
View File
@@ -16,14 +16,17 @@
-->
<resources>
<!-- Hotseat -->
<!-- Hotseat -->
<dimen name="spring_loaded_hotseat_top_margin">44dp</dimen>
<!-- Dynamic grid -->
<!-- Dynamic grid -->
<dimen name="dynamic_grid_edge_margin">11.33dp</dimen>
<dimen name="cell_layout_padding">11.33dp</dimen>
<!-- Dragging -->
<!-- Dragging -->
<dimen name="drop_target_top_margin">0dp</dimen>
<dimen name="drop_target_bottom_margin">16dp</dimen>
<!-- AllApps -->
<dimen name="all_apps_bottom_sheet_horizontal_padding">52dp</dimen>
</resources>
+1 -1
View File
@@ -23,7 +23,7 @@
<!-- AllApps -->
<dimen name="all_apps_search_bar_content_overlap">0dp</dimen>
<dimen name="all_apps_bottom_sheet_horizontal_padding">46dp</dimen>
<dimen name="all_apps_bottom_sheet_horizontal_padding">48dp</dimen>
<!-- Fast scroll -->
<dimen name="fastscroll_popup_width">75dp</dimen>
+7
View File
@@ -18,13 +18,20 @@
<!-- Dragging-->
<dimen name="drop_target_top_margin">0dp</dimen>
<dimen name="drop_target_bottom_margin">32dp</dimen>
<!-- Dynamic grid -->
<dimen name="dynamic_grid_edge_margin">21.93dp</dimen>
<dimen name="cell_layout_padding">29.33dp</dimen>
<!-- Hotseat -->
<dimen name="spring_loaded_hotseat_top_margin">64dp</dimen>
<!-- AllApps -->
<dimen name="all_apps_bottom_sheet_horizontal_padding">32dp</dimen>
<!-- Widget picker-->
<dimen name="widget_list_horizontal_margin">49dp</dimen>
<!-- Bottom sheet-->
<dimen name="bottom_sheet_extra_top_padding">0dp</dimen>
</resources>
+4 -1
View File
@@ -16,10 +16,12 @@
<resources>
<!-- AllApps -->
<dimen name="all_apps_bottom_sheet_horizontal_padding">65dp</dimen>
<dimen name="all_apps_bottom_sheet_horizontal_padding">28dp</dimen>
<!-- Dynamic grid -->
<dimen name="dynamic_grid_edge_margin">27.59dp</dimen>
<dimen name="cell_layout_padding">36dp</dimen>
<!-- Dragging -->
<dimen name="drop_target_text_size">20sp</dimen>
<dimen name="dynamic_grid_drop_target_size">72dp</dimen>
@@ -28,6 +30,7 @@
<dimen name="drop_target_button_gap">32dp</dimen>
<dimen name="drop_target_top_margin">32dp</dimen>
<dimen name="drop_target_bottom_margin">32dp</dimen>
<!-- Hotseat -->
<dimen name="spring_loaded_hotseat_top_margin">164dp</dimen>
+19
View File
@@ -241,9 +241,28 @@
if not specified -->
<attr name="borderSpaceTwoPanelLandscapeVertical" format="float" />
<!-- These min cell values are only used if GridDisplayOption#isScalable is true -->
<!-- defaults to minCellHeight, if not specified -->
<attr name="allAppsCellHeight" format="float" />
<!-- defaults to minCellWidth, if not specified -->
<attr name="allAppsCellWidth" format="float" />
<!-- defaults to allAppsCellHeight, if not specified -->
<attr name="allAppsCellHeightLandscape" format="float" />
<!-- defaults to allAppsCellWidth, if not specified -->
<attr name="allAppsCellWidthLandscape" format="float" />
<!-- defaults to allAppsCellHeight, if not specified -->
<attr name="allAppsCellHeightTwoPanelPortrait" format="float" />
<!-- defaults to allAppsCellWidth, if not specified -->
<attr name="allAppsCellWidthTwoPanelPortrait" format="float" />
<!-- defaults to allAppsCellHeight, if not specified -->
<attr name="allAppsCellHeightTwoPanelLandscape" format="float" />
<!-- defaults to allAppsCellWidth, if not specified -->
<attr name="allAppsCellWidthTwoPanelLandscape" format="float" />
<!-- defaults to borderSpace, if not specified -->
<attr name="allAppsBorderSpace" format="float" />
<!-- defaults to allAppsBorderSpace, if not specified -->
<attr name="allAppsBorderSpaceLandscape" format="float" />
<!-- defaults to allAppsBorderSpace, if not specified -->
<attr name="allAppsBorderSpaceTwoPanelPortrait" format="float" />
<!-- defaults to allAppsBorderSpace, if not specified -->
<attr name="allAppsBorderSpaceTwoPanelLandscape" format="float" />
@@ -216,6 +216,7 @@ public abstract class BaseDraggingActivity extends BaseActivity
* Creates and returns {@link SearchAdapterProvider} for build variant specific search result
* views
*/
@Override
public SearchAdapterProvider<?> createSearchAdapterProvider(
ActivityAllAppsContainerView<?> allApps) {
return new DefaultSearchAdapterProvider(this);
+35 -17
View File
@@ -93,7 +93,7 @@ public class CellLayout extends ViewGroup {
private int mFixedCellWidth;
private int mFixedCellHeight;
@ViewDebug.ExportedProperty(category = "launcher")
private final Point mBorderSpace;
private Point mBorderSpace;
@ViewDebug.ExportedProperty(category = "launcher")
private int mCountX;
@@ -239,22 +239,7 @@ public class CellLayout extends ViewGroup {
mActivity = ActivityContext.lookupContext(context);
DeviceProfile deviceProfile = mActivity.getDeviceProfile();
switch (mContainerType) {
case FOLDER:
mBorderSpace = new Point(deviceProfile.folderCellLayoutBorderSpacePx);
break;
case HOTSEAT:
mBorderSpace = new Point(deviceProfile.hotseatBorderSpace,
deviceProfile.hotseatBorderSpace);
break;
case WORKSPACE:
default:
mBorderSpace = new Point(deviceProfile.cellLayoutBorderSpacePx);
break;
}
mCellWidth = mCellHeight = -1;
mFixedCellWidth = mFixedCellHeight = -1;
resetCellSizeInternal(deviceProfile);
mCountX = deviceProfile.inv.numColumns;
mCountY = deviceProfile.inv.numRows;
@@ -379,6 +364,12 @@ public class CellLayout extends ViewGroup {
return mShortcutsAndWidgets.getLayerType() == LAYER_TYPE_HARDWARE;
}
/**
* Change sizes of cells
*
* @param width the new width of the cells
* @param height the new height of the cells
*/
public void setCellDimensions(int width, int height) {
mFixedCellWidth = mCellWidth = width;
mFixedCellHeight = mCellHeight = height;
@@ -386,6 +377,33 @@ public class CellLayout extends ViewGroup {
mBorderSpace);
}
private void resetCellSizeInternal(DeviceProfile deviceProfile) {
switch (mContainerType) {
case FOLDER:
mBorderSpace = new Point(deviceProfile.folderCellLayoutBorderSpacePx);
break;
case HOTSEAT:
mBorderSpace = new Point(deviceProfile.hotseatBorderSpace,
deviceProfile.hotseatBorderSpace);
break;
case WORKSPACE:
default:
mBorderSpace = new Point(deviceProfile.cellLayoutBorderSpacePx);
break;
}
mCellWidth = mCellHeight = -1;
mFixedCellWidth = mFixedCellHeight = -1;
}
/**
* Reset the cell sizes and border space
*/
public void resetCellSize(DeviceProfile deviceProfile) {
resetCellSizeInternal(deviceProfile);
requestLayout();
}
public void setGridSize(int x, int y) {
mCountX = x;
mCountY = y;
+14 -10
View File
@@ -624,14 +624,15 @@ public class DeviceProfile {
+ textHeight + (topBottomPadding * 2);
}
private void updateAllAppsWidth(Resources res) {
private void updateAllAppsContainerWidth(Resources res) {
int cellLayoutHorizontalPadding =
(cellLayoutPaddingPx.left + cellLayoutPaddingPx.right) / 2;
if (isTablet) {
allAppsLeftRightPadding = res.getDimensionPixelSize(
R.dimen.all_apps_bottom_sheet_horizontal_padding) + cellLayoutHorizontalPadding;
allAppsLeftRightPadding =
res.getDimensionPixelSize(R.dimen.all_apps_bottom_sheet_horizontal_padding);
int usedWidth = (allAppsCellWidthPx * numShownAllAppsColumns)
+ (allAppsBorderSpacePx.x * (numShownAllAppsColumns + 1))
+ (allAppsBorderSpacePx.x * (numShownAllAppsColumns - 1))
+ allAppsLeftRightPadding * 2;
allAppsLeftRightMargin = Math.max(1, (availableWidthPx - usedWidth) / 2);
} else {
@@ -755,24 +756,26 @@ public class DeviceProfile {
* Updates the iconSize for allApps* variants.
*/
public void updateAllAppsIconSize(float scale, Resources res) {
if (numShownAllAppsColumns != inv.numColumns) {
//TODO(b/218638090): remove the tablet condition once we have phone specs
if (isScalableGrid && isTablet) {
allAppsIconSizePx =
pxFromDp(inv.allAppsIconSize[mTypeIndex], mMetrics);
allAppsIconTextSizePx =
pxFromSp(inv.allAppsIconTextSize[mTypeIndex], mMetrics);
allAppsIconDrawablePaddingPx = iconDrawablePaddingOriginalPx;
autoResizeAllAppsCells();
allAppsCellWidthPx = pxFromDp(inv.allAppsCellSize[mTypeIndex].x, mMetrics, scale);
allAppsCellHeightPx = pxFromDp(inv.allAppsCellSize[mTypeIndex].y, mMetrics, scale);
} else {
float invIconSizeDp = inv.iconSize[mTypeIndex];
float invIconTextSizeSp = inv.iconTextSize[mTypeIndex];
allAppsIconSizePx = Math.max(1, pxFromDp(invIconSizeDp, mMetrics, scale));
allAppsIconTextSizePx = (int) (pxFromSp(invIconTextSizeSp, mMetrics) * scale);
allAppsIconDrawablePaddingPx = (int) (iconDrawablePaddingOriginalPx * scale);
allAppsCellWidthPx = allAppsIconSizePx + (2 * allAppsIconDrawablePaddingPx);
allAppsCellHeightPx = getCellSize().y;
}
allAppsCellWidthPx = allAppsIconSizePx + (2 * allAppsIconDrawablePaddingPx);
updateAllAppsWidth(res);
updateAllAppsContainerWidth(res);
if (isVerticalBarLayout()) {
hideWorkspaceLabelsIfNotEnoughSpace();
}
@@ -998,7 +1001,7 @@ public class DeviceProfile {
additionalLeftSpace = qsbWidth + hotseatBorderSpace;
}
int hotseatTopDiff = hotseatHeight - taskbarOffset;
int hotseatTopPadding = hotseatHeight - taskbarOffset - hotseatCellHeightPx;
int endOffset = ApiWrapper.getHotseatEndOffset(context);
int requiredWidth = iconSizePx * numShownHotseatIcons
@@ -1007,7 +1010,7 @@ public class DeviceProfile {
int hotseatSize = Math.min(requiredWidth, availableWidthPx - endOffset);
int sideSpacing = (availableWidthPx - hotseatSize) / 2;
mHotseatPadding.set(sideSpacing + additionalLeftSpace, hotseatTopDiff, sideSpacing,
mHotseatPadding.set(sideSpacing + additionalLeftSpace, hotseatTopPadding, sideSpacing,
taskbarOffset);
if (endOffset > sideSpacing) {
@@ -1223,6 +1226,7 @@ public class DeviceProfile {
allAppsIconDrawablePaddingPx));
writer.println(prefix + pxToDpStr("allAppsCellHeightPx", allAppsCellHeightPx));
writer.println(prefix + pxToDpStr("allAppsCellWidthPx", allAppsCellWidthPx));
writer.println(prefix + pxToDpStr("allAppsBorderSpacePx", allAppsBorderSpacePx.x));
writer.println(prefix + "\tnumShownAllAppsColumns: " + numShownAllAppsColumns);
writer.println(prefix + pxToDpStr("allAppsLeftRightPadding", allAppsLeftRightPadding));
writer.println(prefix + pxToDpStr("allAppsLeftRightMargin", allAppsLeftRightMargin));
+3 -3
View File
@@ -84,6 +84,7 @@ public class Hotseat extends CellLayout implements Insettable {
removeAllViewsInLayout();
mHasVerticalHotseat = hasVerticalHotseat;
DeviceProfile dp = mActivity.getDeviceProfile();
resetCellSize(dp);
if (hasVerticalHotseat) {
setGridSize(1, dp.numShownHotseatIcons);
} else {
@@ -110,10 +111,9 @@ public class Hotseat extends CellLayout implements Insettable {
mQsb.setVisibility(View.VISIBLE);
lp.gravity = Gravity.BOTTOM;
lp.width = ViewGroup.LayoutParams.MATCH_PARENT;
lp.height = (grid.isTaskbarPresent
lp.height = grid.isTaskbarPresent
? grid.workspacePadding.bottom
: grid.hotseatBarSizePx)
+ (grid.isTaskbarPresent ? grid.taskbarSize : insets.bottom);
: grid.hotseatBarSizePx + insets.bottom;
}
Rect padding = grid.getHotseatLayoutPadding(getContext());
@@ -128,6 +128,7 @@ public class InvariantDeviceProfile {
public float[] horizontalMargin;
public PointF[] allAppsCellSize;
public float[] allAppsIconSize;
public float[] allAppsIconTextSize;
public PointF[] allAppsBorderSpaces;
@@ -357,6 +358,7 @@ public class InvariantDeviceProfile {
numDatabaseAllAppsColumns = deviceType == TYPE_MULTI_DISPLAY
? closestProfile.numDatabaseAllAppsColumns : closestProfile.numAllAppsColumns;
allAppsCellSize = displayOption.allAppsCellSize;
allAppsBorderSpaces = displayOption.allAppsBorderSpaces;
allAppsIconSize = displayOption.allAppsIconSizes;
allAppsIconTextSize = displayOption.allAppsIconTextSizes;
@@ -798,6 +800,7 @@ public class InvariantDeviceProfile {
private final float[] iconSizes = new float[COUNT_SIZES];
private final float[] textSizes = new float[COUNT_SIZES];
private final PointF[] allAppsCellSize = new PointF[COUNT_SIZES];
private final float[] allAppsIconSizes = new float[COUNT_SIZES];
private final float[] allAppsIconTextSizes = new float[COUNT_SIZES];
private final PointF[] allAppsBorderSpaces = new PointF[COUNT_SIZES];
@@ -873,9 +876,35 @@ public class InvariantDeviceProfile {
folderBorderSpace = borderSpace;
x = a.getFloat(R.styleable.ProfileDisplayOption_allAppsCellWidth,
minCellSize[INDEX_DEFAULT].x);
y = a.getFloat(R.styleable.ProfileDisplayOption_allAppsCellHeight,
minCellSize[INDEX_DEFAULT].y);
allAppsCellSize[INDEX_DEFAULT] = new PointF(x, y);
x = a.getFloat(R.styleable.ProfileDisplayOption_allAppsCellWidthLandscape,
allAppsCellSize[INDEX_DEFAULT].x);
y = a.getFloat(R.styleable.ProfileDisplayOption_allAppsCellHeightLandscape,
allAppsCellSize[INDEX_DEFAULT].y);
allAppsCellSize[INDEX_LANDSCAPE] = new PointF(x, y);
x = a.getFloat(R.styleable.ProfileDisplayOption_allAppsCellWidthTwoPanelPortrait,
allAppsCellSize[INDEX_DEFAULT].x);
y = a.getFloat(R.styleable.ProfileDisplayOption_allAppsCellHeightTwoPanelPortrait,
allAppsCellSize[INDEX_DEFAULT].y);
allAppsCellSize[INDEX_TWO_PANEL_PORTRAIT] = new PointF(x, y);
x = a.getFloat(R.styleable.ProfileDisplayOption_allAppsCellWidthTwoPanelLandscape,
allAppsCellSize[INDEX_DEFAULT].x);
y = a.getFloat(R.styleable.ProfileDisplayOption_allAppsCellHeightTwoPanelLandscape,
allAppsCellSize[INDEX_DEFAULT].y);
allAppsCellSize[INDEX_TWO_PANEL_LANDSCAPE] = new PointF(x, y);
x = y = a.getFloat(R.styleable.ProfileDisplayOption_allAppsBorderSpace,
borderSpace);
allAppsBorderSpaces[INDEX_DEFAULT] = new PointF(x, y);
x = y = a.getFloat(R.styleable.ProfileDisplayOption_allAppsBorderSpaceLandscape,
allAppsBorderSpaces[INDEX_DEFAULT].x);
allAppsBorderSpaces[INDEX_LANDSCAPE] = new PointF(x, y);
x = y = a.getFloat(
R.styleable.ProfileDisplayOption_allAppsBorderSpaceTwoPanelPortrait,
@@ -971,6 +1000,7 @@ public class InvariantDeviceProfile {
textSizes[i] = 0;
borderSpaces[i] = new PointF();
minCellSize[i] = new PointF();
allAppsCellSize[i] = new PointF();
allAppsIconSizes[i] = 0;
allAppsIconTextSizes[i] = 0;
allAppsBorderSpaces[i] = new PointF();
@@ -987,6 +1017,8 @@ public class InvariantDeviceProfile {
minCellSize[i].y *= w;
horizontalMargin[i] *= w;
hotseatBorderSpaces[i] *= w;
allAppsCellSize[i].x *= w;
allAppsCellSize[i].y *= w;
allAppsIconSizes[i] *= w;
allAppsIconTextSizes[i] *= w;
allAppsBorderSpaces[i].x *= w;
@@ -1008,6 +1040,8 @@ public class InvariantDeviceProfile {
minCellSize[i].y += p.minCellSize[i].y;
horizontalMargin[i] += p.horizontalMargin[i];
hotseatBorderSpaces[i] += p.hotseatBorderSpaces[i];
allAppsCellSize[i].x += p.allAppsCellSize[i].x;
allAppsCellSize[i].y += p.allAppsCellSize[i].y;
allAppsIconSizes[i] += p.allAppsIconSizes[i];
allAppsIconTextSizes[i] += p.allAppsIconTextSizes[i];
allAppsBorderSpaces[i].x += p.allAppsBorderSpaces[i].x;
@@ -26,12 +26,13 @@ import android.widget.RelativeLayout;
import androidx.core.graphics.ColorUtils;
import androidx.recyclerview.widget.RecyclerView;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.DeviceProfile.DeviceProfileListenable;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.allapps.search.SearchAdapterProvider;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.views.AppLauncher;
import java.util.Objects;
@@ -40,8 +41,8 @@ import java.util.Objects;
*
* @param <T> Type of context inflating all apps.
*/
public class ActivityAllAppsContainerView<T extends BaseDraggingActivity> extends
BaseAllAppsContainerView<T> {
public class ActivityAllAppsContainerView<T extends Context & AppLauncher
& DeviceProfileListenable> extends BaseAllAppsContainerView<T> {
protected SearchUiManager mSearchUiManager;
/**
@@ -103,13 +104,8 @@ public class ActivityAllAppsContainerView<T extends BaseDraggingActivity> extend
}
}
/** Handles selection on focused view and returns {@code true} on success. */
public boolean launchHighlightedItem() {
return getMainAdapterProvider().launchHighlightedItem();
}
@Override
protected SearchAdapterProvider<?> createMainAdapterProvider() {
protected final SearchAdapterProvider<?> createMainAdapterProvider() {
return mActivityContext.createSearchAdapterProvider(this);
}
@@ -29,14 +29,13 @@ import android.view.inputmethod.EditorInfo;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.ExtendedEditText;
import com.android.launcher3.Launcher;
import com.android.launcher3.Utilities;
import com.android.launcher3.allapps.BaseAllAppsAdapter.AdapterItem;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.search.SearchAlgorithm;
import com.android.launcher3.search.SearchCallback;
import com.android.launcher3.views.ActivityContext;
/**
* An interface to a search box that AllApps can command.
@@ -45,7 +44,7 @@ public class AllAppsSearchBarController
implements TextWatcher, OnEditorActionListener, ExtendedEditText.OnBackKeyListener,
OnFocusChangeListener {
protected BaseDraggingActivity mLauncher;
protected ActivityContext mLauncher;
protected SearchCallback<AdapterItem> mCallback;
protected ExtendedEditText mInput;
protected String mQuery;
@@ -62,7 +61,7 @@ public class AllAppsSearchBarController
*/
public final void initialize(
SearchAlgorithm<AdapterItem> searchAlgorithm, ExtendedEditText input,
BaseDraggingActivity launcher, SearchCallback<AdapterItem> callback) {
ActivityContext launcher, SearchCallback<AdapterItem> callback) {
mCallback = callback;
mLauncher = launcher;
@@ -125,7 +124,7 @@ public class AllAppsSearchBarController
mLauncher.getStatsLogManager().logger()
.log(LAUNCHER_ALLAPPS_FOCUSED_ITEM_SELECTED_WITH_IME);
// selectFocusedView should return SearchTargetEvent that is passed onto onClick
return Launcher.getLauncher(mLauncher).getAppsView().launchHighlightedItem();
return mLauncher.getAppsView().getMainAdapterProvider().launchHighlightedItem();
}
return false;
}
@@ -32,7 +32,6 @@ import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup.MarginLayoutParams;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.ExtendedEditText;
import com.android.launcher3.Insettable;
@@ -43,6 +42,7 @@ import com.android.launcher3.allapps.AlphabeticalAppsList;
import com.android.launcher3.allapps.BaseAllAppsAdapter.AdapterItem;
import com.android.launcher3.allapps.SearchUiManager;
import com.android.launcher3.search.SearchCallback;
import com.android.launcher3.views.ActivityContext;
import java.util.ArrayList;
@@ -53,7 +53,7 @@ public class AppsSearchContainerLayout extends ExtendedEditText
implements SearchUiManager, SearchCallback<AdapterItem>,
AllAppsStore.OnUpdateListener, Insettable {
private final BaseDraggingActivity mLauncher;
private final ActivityContext mLauncher;
private final AllAppsSearchBarController mSearchBarController;
private final SpannableStringBuilder mSearchQueryBuilder;
@@ -74,7 +74,7 @@ public class AppsSearchContainerLayout extends ExtendedEditText
public AppsSearchContainerLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mLauncher = BaseDraggingActivity.fromContext(context);
mLauncher = ActivityContext.lookupContext(context);
mSearchBarController = new AllAppsSearchBarController();
mSearchQueryBuilder = new SpannableStringBuilder();
@@ -134,7 +134,7 @@ public class AppsSearchContainerLayout extends ExtendedEditText
mApps = appsView.getApps();
mAppsView = appsView;
mSearchBarController.initialize(
new DefaultAppSearchAlgorithm(mLauncher),
new DefaultAppSearchAlgorithm(getContext()),
this, mLauncher, this);
}
@@ -23,20 +23,20 @@ import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.allapps.AllAppsGridAdapter;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.views.AppLauncher;
/**
* Provides views for local search results
* Provides views for local search results.
*/
public class DefaultSearchAdapterProvider extends SearchAdapterProvider<BaseDraggingActivity> {
public class DefaultSearchAdapterProvider extends SearchAdapterProvider<AppLauncher> {
private final RecyclerView.ItemDecoration mDecoration;
private View mHighlightedView;
public DefaultSearchAdapterProvider(BaseDraggingActivity launcher) {
public DefaultSearchAdapterProvider(AppLauncher launcher) {
super(launcher);
mDecoration = new RecyclerView.ItemDecoration() {
@Override
@@ -258,6 +258,9 @@ public final class FeatureFlags {
"ENABLE_NEW_MIGRATION_LOGIC", true,
"Enable the new grid migration logic, keeping pages when src < dest");
public static final BooleanFlag ENABLE_ONE_SEARCH_MOTION = new DeviceFlag(
"ENABLE_ONE_SEARCH_MOTION", false, "Enables animations in OneSearch.");
public static void initialize(Context context) {
synchronized (sDebugFlags) {
for (DebugFlag flag : sDebugFlags) {
+20 -7
View File
@@ -16,6 +16,7 @@
package com.android.launcher3.icons;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
import static com.android.launcher3.widget.WidgetSections.NO_CATEGORY;
@@ -340,14 +341,15 @@ public class IconCache extends BaseIconCache {
Map<Pair<UserHandle, Boolean>, List<IconRequestInfo<T>>> iconLoadSubsectionsMap =
iconRequestInfos.stream()
.filter(iconRequest -> {
if (iconRequest.itemInfo.getTargetComponent() != null) {
return true;
if (iconRequest.itemInfo.getTargetComponent() == null) {
Log.i(TAG,
"Skipping Item info with null component name: "
+ iconRequest.itemInfo);
iconRequest.itemInfo.bitmap = getDefaultIcon(
iconRequest.itemInfo.user);
return false;
}
Log.i(TAG,
"Skipping Item info with null component name: "
+ iconRequest.itemInfo);
iconRequest.itemInfo.bitmap = getDefaultIcon(iconRequest.itemInfo.user);
return false;
return true;
})
.collect(groupingBy(iconRequest ->
Pair.create(iconRequest.itemInfo.user, iconRequest.useLowResIcon)));
@@ -356,6 +358,17 @@ public class IconCache extends BaseIconCache {
iconLoadSubsectionsMap.forEach((sectionKey, filteredList) -> {
Map<ComponentName, List<IconRequestInfo<T>>> duplicateIconRequestsMap =
filteredList.stream()
.filter(iconRequest -> {
// Filter out icons that should not share the same bitmap and title
if (iconRequest.itemInfo.itemType == ITEM_TYPE_DEEP_SHORTCUT) {
Log.e(TAG,
"Skipping Item info for deep shortcut: "
+ iconRequest.itemInfo,
new IllegalStateException());
return false;
}
return true;
})
.collect(groupingBy(iconRequest ->
iconRequest.itemInfo.getTargetComponent()));
@@ -615,7 +615,13 @@ public class LoaderTask implements Runnable {
}
if (info != null) {
iconRequestInfos.add(c.createIconRequestInfo(info, useLowResIcon));
if (info.itemType
!= LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
// Skip deep shortcuts; their title and icons have already been
// loaded above.
iconRequestInfos.add(
c.createIconRequestInfo(info, useLowResIcon));
}
c.applyCommonProperties(info);
@@ -16,6 +16,7 @@
package com.android.launcher3.touch;
import static android.view.Gravity.BOTTOM;
import static android.view.Gravity.CENTER_VERTICAL;
import static android.view.Gravity.END;
import static android.view.Gravity.START;
@@ -414,14 +415,17 @@ public class LandscapePagedViewHandler implements PagedOrientationHandler {
@Override
public void setSplitTaskSwipeRect(DeviceProfile dp, Rect outRect,
StagedSplitBounds splitInfo, int desiredStagePosition) {
float diff;
float horizontalDividerDiff = splitInfo.visualDividerBounds.width() / 2f;
float topLeftTaskPercent = splitInfo.appsStackedVertically
? splitInfo.topTaskPercent
: splitInfo.leftTaskPercent;
float dividerBarPercent = splitInfo.appsStackedVertically
? splitInfo.dividerHeightPercent
: splitInfo.dividerWidthPercent;
if (desiredStagePosition == SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT) {
diff = outRect.height() * (1f - splitInfo.leftTaskPercent) + horizontalDividerDiff;
outRect.bottom -= diff;
outRect.bottom = outRect.top + (int) (outRect.height() * topLeftTaskPercent);
} else {
diff = outRect.height() * splitInfo.leftTaskPercent + horizontalDividerDiff;
outRect.top += diff;
outRect.top += (int) (outRect.height() * (topLeftTaskPercent + dividerBarPercent));
}
}
@@ -468,18 +472,42 @@ public class LandscapePagedViewHandler implements PagedOrientationHandler {
@Override
public void setSplitIconParams(View primaryIconView, View secondaryIconView,
int taskIconHeight, int primarySnapshotWidth, int primarySnapshotHeight,
boolean isRtl, DeviceProfile deviceProfile, StagedSplitBounds splitConfig) {
int groupedTaskViewHeight, int groupedTaskViewWidth, boolean isRtl,
DeviceProfile deviceProfile, StagedSplitBounds splitConfig) {
FrameLayout.LayoutParams primaryIconParams =
(FrameLayout.LayoutParams) primaryIconView.getLayoutParams();
FrameLayout.LayoutParams secondaryIconParams =
new FrameLayout.LayoutParams(primaryIconParams);
primaryIconParams.gravity = CENTER_VERTICAL | (isRtl ? START : END);
// We calculate the "midpoint" of the thumbnail area, and place the icons there.
// This is the place where the thumbnail area splits by default, in a near-50/50 split.
// It is usually not exactly 50/50, due to insets/screen cutouts.
int fullscreenInsetThickness = deviceProfile.getInsets().top;
int fullscreenMidpointFromBottom = ((deviceProfile.heightPx - fullscreenInsetThickness)
/ 2);
float midpointFromBottomPct = (float) fullscreenMidpointFromBottom / deviceProfile.heightPx;
float insetPct = (float) fullscreenInsetThickness / deviceProfile.heightPx;
int spaceAboveSnapshots = deviceProfile.overviewTaskThumbnailTopMarginPx;
int overviewThumbnailAreaThickness = groupedTaskViewHeight - spaceAboveSnapshots;
int bottomToMidpointOffset = (int) (overviewThumbnailAreaThickness * midpointFromBottomPct);
int insetOffset = (int) (overviewThumbnailAreaThickness * insetPct);
primaryIconParams.gravity = BOTTOM | (isRtl ? START : END);
secondaryIconParams.gravity = BOTTOM | (isRtl ? START : END);
primaryIconView.setTranslationX(0);
primaryIconView.setTranslationY(-(taskIconHeight / 2f));
secondaryIconParams.gravity = CENTER_VERTICAL | (isRtl ? START : END);
secondaryIconView.setTranslationX(0);
secondaryIconView.setTranslationY(taskIconHeight / 2f);
if (splitConfig.initiatedFromSeascape) {
// if the split was initiated from seascape,
// the task on the right (secondary) is slightly larger
primaryIconView.setTranslationY(-bottomToMidpointOffset - insetOffset);
secondaryIconView.setTranslationY(-bottomToMidpointOffset - insetOffset
+ taskIconHeight);
} else {
// if not,
// the task on the left (primary) is slightly larger
primaryIconView.setTranslationY(-bottomToMidpointOffset);
secondaryIconView.setTranslationY(-bottomToMidpointOffset + taskIconHeight);
}
primaryIconView.setLayoutParams(primaryIconParams);
secondaryIconView.setLayoutParams(secondaryIconParams);
@@ -146,7 +146,8 @@ public interface PagedOrientationHandler {
int taskIconMargin, int taskIconHeight, int thumbnailTopMargin, boolean isRtl);
void setSplitIconParams(View primaryIconView, View secondaryIconView,
int taskIconHeight, int primarySnapshotWidth, int primarySnapshotHeight,
boolean isRtl, DeviceProfile deviceProfile, StagedSplitBounds splitConfig);
int groupedTaskViewHeight, int groupedTaskViewWidth, boolean isRtl,
DeviceProfile deviceProfile, StagedSplitBounds splitConfig);
/*
* The following two methods try to center the TaskMenuView in landscape by finding the center
@@ -18,6 +18,7 @@ package com.android.launcher3.touch;
import static android.view.Gravity.BOTTOM;
import static android.view.Gravity.CENTER_HORIZONTAL;
import static android.view.Gravity.END;
import static android.view.Gravity.START;
import static android.view.Gravity.TOP;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
@@ -334,8 +335,14 @@ public class PortraitPagedViewHandler implements PagedOrientationHandler {
// Set translations
if (deviceProfile.isLandscape) {
if (desiredTaskId == splitBounds.rightBottomTaskId) {
translationX = ((taskViewWidth * splitBounds.leftTaskPercent)
+ (taskViewWidth * splitBounds.dividerWidthPercent));
float leftTopTaskPercent = splitBounds.appsStackedVertically
? splitBounds.topTaskPercent
: splitBounds.leftTaskPercent;
float dividerThicknessPercent = splitBounds.appsStackedVertically
? splitBounds.dividerHeightPercent
: splitBounds.dividerWidthPercent;
translationX = ((taskViewWidth * leftTopTaskPercent)
+ (taskViewWidth * dividerThicknessPercent));
}
} else {
if (desiredTaskId == splitBounds.leftTopTaskId) {
@@ -488,19 +495,24 @@ public class PortraitPagedViewHandler implements PagedOrientationHandler {
public void setSplitTaskSwipeRect(DeviceProfile dp, Rect outRect,
StagedSplitBounds splitInfo, int desiredStagePosition) {
boolean isLandscape = dp.isLandscape;
float topLeftTaskPercent = splitInfo.appsStackedVertically
? splitInfo.topTaskPercent
: splitInfo.leftTaskPercent;
float dividerBarPercent = splitInfo.appsStackedVertically
? splitInfo.dividerHeightPercent
: splitInfo.dividerWidthPercent;
if (desiredStagePosition == SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT) {
if (isLandscape) {
outRect.right = outRect.left + (int) (outRect.width() * splitInfo.leftTaskPercent);
outRect.right = outRect.left + (int) (outRect.width() * topLeftTaskPercent);
} else {
outRect.bottom = outRect.top + (int) (outRect.height() * splitInfo.topTaskPercent);
outRect.bottom = outRect.top + (int) (outRect.height() * topLeftTaskPercent);
}
} else {
if (isLandscape) {
outRect.left += (int) (outRect.width() *
(splitInfo.leftTaskPercent + splitInfo.dividerWidthPercent));
outRect.left += (int) (outRect.width() * (topLeftTaskPercent + dividerBarPercent));
} else {
outRect.top += (int) (outRect.height() *
(splitInfo.topTaskPercent + splitInfo.dividerHeightPercent));
outRect.top += (int) (outRect.height() * (topLeftTaskPercent + dividerBarPercent));
}
}
}
@@ -559,18 +571,70 @@ public class PortraitPagedViewHandler implements PagedOrientationHandler {
@Override
public void setSplitIconParams(View primaryIconView, View secondaryIconView,
int taskIconHeight, int primarySnapshotWidth, int primarySnapshotHeight,
boolean isRtl, DeviceProfile deviceProfile, StagedSplitBounds splitConfig) {
int groupedTaskViewHeight, int groupedTaskViewWidth, boolean isRtl,
DeviceProfile deviceProfile, StagedSplitBounds splitConfig) {
FrameLayout.LayoutParams primaryIconParams =
(FrameLayout.LayoutParams) primaryIconView.getLayoutParams();
FrameLayout.LayoutParams secondaryIconParams =
new FrameLayout.LayoutParams(primaryIconParams);
primaryIconParams.gravity = TOP | CENTER_HORIZONTAL;
// shifts icon half a width left (height is used conveniently here since icons are square)
primaryIconView.setTranslationX(-(taskIconHeight / 2f));
if (deviceProfile.isLandscape) {
// We calculate the "midpoint" of the thumbnail area, and place the icons there.
// This is the place where the thumbnail area splits by default, in a near-50/50 split.
// It is usually not exactly 50/50, due to insets/screen cutouts.
int fullscreenInsetThickness = deviceProfile.isSeascape()
? deviceProfile.getInsets().right
: deviceProfile.getInsets().left;
int fullscreenMidpointFromBottom = ((deviceProfile.widthPx
- fullscreenInsetThickness) / 2);
float midpointFromBottomPct = (float) fullscreenMidpointFromBottom
/ deviceProfile.widthPx;
float insetPct = (float) fullscreenInsetThickness / deviceProfile.widthPx;
int spaceAboveSnapshots = 0;
int overviewThumbnailAreaThickness = groupedTaskViewWidth - spaceAboveSnapshots;
int bottomToMidpointOffset = (int) (overviewThumbnailAreaThickness
* midpointFromBottomPct);
int insetOffset = (int) (overviewThumbnailAreaThickness * insetPct);
if (deviceProfile.isSeascape()) {
primaryIconParams.gravity = TOP | (isRtl ? END : START);
secondaryIconParams.gravity = TOP | (isRtl ? END : START);
if (splitConfig.initiatedFromSeascape) {
// if the split was initiated from seascape,
// the task on the right (secondary) is slightly larger
primaryIconView.setTranslationX(bottomToMidpointOffset - taskIconHeight);
secondaryIconView.setTranslationX(bottomToMidpointOffset);
} else {
// if not,
// the task on the left (primary) is slightly larger
primaryIconView.setTranslationX(bottomToMidpointOffset + insetOffset
- taskIconHeight);
secondaryIconView.setTranslationX(bottomToMidpointOffset + insetOffset);
}
} else {
primaryIconParams.gravity = TOP | (isRtl ? START : END);
secondaryIconParams.gravity = TOP | (isRtl ? START : END);
if (!splitConfig.initiatedFromSeascape) {
// if the split was initiated from landscape,
// the task on the left (primary) is slightly larger
primaryIconView.setTranslationX(-bottomToMidpointOffset);
secondaryIconView.setTranslationX(-bottomToMidpointOffset + taskIconHeight);
} else {
// if not,
// the task on the right (secondary) is slightly larger
primaryIconView.setTranslationX(-bottomToMidpointOffset - insetOffset);
secondaryIconView.setTranslationX(-bottomToMidpointOffset - insetOffset
+ taskIconHeight);
}
}
} else {
primaryIconParams.gravity = TOP | CENTER_HORIZONTAL;
// shifts icon half a width left (height is used here since icons are square)
primaryIconView.setTranslationX(-(taskIconHeight / 2f));
secondaryIconParams.gravity = TOP | CENTER_HORIZONTAL;
secondaryIconView.setTranslationX(taskIconHeight / 2f);
}
primaryIconView.setTranslationY(0);
secondaryIconParams.gravity = TOP | CENTER_HORIZONTAL;
secondaryIconView.setTranslationX(taskIconHeight / 2f);
secondaryIconView.setTranslationY(0);
primaryIconView.setLayoutParams(primaryIconParams);
@@ -178,16 +178,46 @@ public class SeascapePagedViewHandler extends LandscapePagedViewHandler {
@Override
public void setSplitIconParams(View primaryIconView, View secondaryIconView,
int taskIconHeight, int primarySnapshotWidth, int primarySnapshotHeight,
boolean isRtl, DeviceProfile deviceProfile, StagedSplitBounds splitConfig) {
int groupedTaskViewHeight, int groupedTaskViewWidth, boolean isRtl,
DeviceProfile deviceProfile, StagedSplitBounds splitConfig) {
super.setSplitIconParams(primaryIconView, secondaryIconView, taskIconHeight,
primarySnapshotWidth, primarySnapshotHeight, isRtl, deviceProfile, splitConfig);
primarySnapshotWidth, primarySnapshotHeight, groupedTaskViewHeight,
groupedTaskViewWidth, isRtl, deviceProfile, splitConfig);
FrameLayout.LayoutParams primaryIconParams =
(FrameLayout.LayoutParams) primaryIconView.getLayoutParams();
FrameLayout.LayoutParams secondaryIconParams =
(FrameLayout.LayoutParams) secondaryIconView.getLayoutParams();
primaryIconParams.gravity = CENTER_VERTICAL | (isRtl ? END : START);
secondaryIconParams.gravity = CENTER_VERTICAL | (isRtl ? END : START);
// We calculate the "midpoint" of the thumbnail area, and place the icons there.
// This is the place where the thumbnail area splits by default, in a near-50/50 split.
// It is usually not exactly 50/50, due to insets/screen cutouts.
int fullscreenInsetThickness = deviceProfile.getInsets().top;
int fullscreenMidpointFromBottom = ((deviceProfile.heightPx
- fullscreenInsetThickness) / 2);
float midpointFromBottomPct = (float) fullscreenMidpointFromBottom / deviceProfile.heightPx;
float insetPct = (float) fullscreenInsetThickness / deviceProfile.heightPx;
int spaceAboveSnapshots = deviceProfile.overviewTaskThumbnailTopMarginPx;
int overviewThumbnailAreaThickness = groupedTaskViewHeight - spaceAboveSnapshots;
int bottomToMidpointOffset = (int) (overviewThumbnailAreaThickness * midpointFromBottomPct);
int insetOffset = (int) (overviewThumbnailAreaThickness * insetPct);
primaryIconParams.gravity = BOTTOM | (isRtl ? END : START);
secondaryIconParams.gravity = BOTTOM | (isRtl ? END : START);
primaryIconView.setTranslationX(0);
secondaryIconView.setTranslationX(0);
if (splitConfig.initiatedFromSeascape) {
// if the split was initiated from seascape,
// the task on the right (secondary) is slightly larger
primaryIconView.setTranslationY(-bottomToMidpointOffset - insetOffset);
secondaryIconView.setTranslationY(-bottomToMidpointOffset - insetOffset
+ taskIconHeight);
} else {
// if not,
// the task on the left (primary) is slightly larger
primaryIconView.setTranslationY(-bottomToMidpointOffset);
secondaryIconView.setTranslationY(-bottomToMidpointOffset + taskIconHeight);
}
primaryIconView.setLayoutParams(primaryIconParams);
secondaryIconView.setLayoutParams(secondaryIconParams);
}
@@ -113,6 +113,14 @@ public final class SplitConfigurationOptions {
* the bounds were originally in
*/
public final boolean appsStackedVertically;
/**
* If {@code true}, that means at the time of creation of this object, the phone was in
* seascape orientation. This is important on devices with insets, because they do not split
* evenly -- one of the insets must be slightly larger to account for the inset.
* From landscape, it is the leftTop task that expands slightly.
* From seascape, it is the rightBottom task that expands slightly.
*/
public final boolean initiatedFromSeascape;
public final int leftTopTaskId;
public final int rightBottomTaskId;
@@ -128,11 +136,22 @@ public final class SplitConfigurationOptions {
this.visualDividerBounds = new Rect(leftTopBounds.left, leftTopBounds.bottom,
leftTopBounds.right, rightBottomBounds.top);
appsStackedVertically = true;
initiatedFromSeascape = false;
} else {
// horizontal apps, vertical divider
this.visualDividerBounds = new Rect(leftTopBounds.right, leftTopBounds.top,
rightBottomBounds.left, leftTopBounds.bottom);
appsStackedVertically = false;
// The following check is unreliable on devices without insets
// (initiatedFromSeascape will always be set to false.) This happens to be OK for
// all our current uses, but should be refactored.
// TODO: Create a more reliable check, or refactor how splitting works on devices
// with insets.
if (rightBottomBounds.width() > leftTopBounds.width()) {
initiatedFromSeascape = true;
} else {
initiatedFromSeascape = false;
}
}
leftTaskPercent = this.leftTopBounds.width() / (float) rightBottomBounds.right;
@@ -25,7 +25,8 @@ import android.view.View.AccessibilityDelegate;
import androidx.annotation.Nullable;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.allapps.BaseAllAppsContainerView;
import com.android.launcher3.allapps.ActivityAllAppsContainerView;
import com.android.launcher3.allapps.search.SearchAdapterProvider;
import com.android.launcher3.dot.DotInfo;
import com.android.launcher3.dragndrop.DragController;
import com.android.launcher3.folder.FolderIcon;
@@ -99,7 +100,7 @@ public interface ActivityContext {
/**
* The all apps container, if it exists in this context.
*/
default BaseAllAppsContainerView<?> getAppsView() {
default ActivityAllAppsContainerView<?> getAppsView() {
return null;
}
@@ -190,4 +191,14 @@ public interface ActivityContext {
default StringCache getStringCache() {
return null;
}
/**
* Creates and returns {@link SearchAdapterProvider} for build variant specific search result
* views.
*/
@Nullable
default SearchAdapterProvider<?> createSearchAdapterProvider(
ActivityAllAppsContainerView<?> appsView) {
return null;
}
}
@@ -229,7 +229,7 @@ public class OptionsPopupView extends ArrowPopup<Launcher>
Launcher launcher = Launcher.getLauncher(view.getContext());
launcher.startActivity(new Intent(Intent.ACTION_APPLICATION_PREFERENCES)
.setPackage(launcher.getPackageName())
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK));
return true;
}
@@ -208,6 +208,12 @@ class DeviceProfileTest {
PointF(64f, 83f),
PointF(64f, 83f)
).toTypedArray()
allAppsCellSize = listOf(
PointF(64f, 83f),
PointF(64f, 83f),
PointF(64f, 83f),
PointF(64f, 83f)
).toTypedArray()
}
}
}