Snap for 7752803 from b0ca4b3070 to tm-release

Change-Id: I25058f456bc561a2b1c87b1de07577fa27821a7f
This commit is contained in:
Android Build Coastguard Worker
2021-09-22 03:08:47 +00:00
11 changed files with 250 additions and 65 deletions
@@ -15,12 +15,15 @@
*/
package com.android.launcher3.hybridhotseat;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent
.LAUNCHER_HOTSEAT_EDU_ONLY_TIP;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_HOTSEAT_EDU_ONLY_TIP;
import android.content.Intent;
import android.graphics.Rect;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.CellLayout;
import com.android.launcher3.Hotseat;
import com.android.launcher3.InvariantDeviceProfile;
@@ -47,6 +50,8 @@ import java.util.stream.IntStream;
*/
public class HotseatEduController {
private static final String TAG = "HotseatEduController";
public static final String SETTINGS_ACTION =
"android.settings.ACTION_CONTENT_SUGGESTIONS_SETTINGS";
@@ -188,8 +193,12 @@ public class HotseatEduController {
.getInt(LauncherSettings.Settings.EXTRA_VALUE);
mNewScreens = IntArray.wrap(pageId);
}
for (int i = 0; i < mLauncher.getDeviceProfile().numShownHotseatIcons; i++) {
View child = mHotseat.getChildAt(i, 0);
boolean isPortrait = !mLauncher.getDeviceProfile().isVerticalBarLayout();
int hotseatItemsNum = mLauncher.getDeviceProfile().numShownHotseatIcons;
for (int i = 0; i < hotseatItemsNum; i++) {
int x = isPortrait ? i : 0;
int y = isPortrait ? 0 : hotseatItemsNum - i - 1;
View child = mHotseat.getChildAt(x, y);
if (child == null || child.getTag() == null) continue;
ItemInfo tag = (ItemInfo) child.getTag();
if (tag.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION) continue;
@@ -229,8 +238,7 @@ public class HotseatEduController {
R.string.hotseat_prediction_settings, null,
() -> mLauncher.startActivity(getSettingsIntent()));
} else {
new ArrowTipView(mLauncher).show(
mLauncher.getString(R.string.hotseat_tip_no_empty_slots), mHotseat.getTop());
showHotseatArrowTip(true, mLauncher.getString(R.string.hotseat_tip_no_empty_slots));
}
}
@@ -251,15 +259,50 @@ public class HotseatEduController {
if (requiresMigration && canMigrateToFirstPage) {
showDialog();
} else {
new ArrowTipView(mLauncher).show(mLauncher.getString(
if (showHotseatArrowTip(requiresMigration, mLauncher.getString(
requiresMigration ? R.string.hotseat_tip_no_empty_slots
: R.string.hotseat_auto_enrolled),
mHotseat.getTop());
mLauncher.getStatsLogManager().logger().log(LAUNCHER_HOTSEAT_EDU_ONLY_TIP);
: R.string.hotseat_auto_enrolled))) {
mLauncher.getStatsLogManager().logger().log(LAUNCHER_HOTSEAT_EDU_ONLY_TIP);
}
finishOnboarding();
}
}
/**
* Finds a child suitable child in hotseat and shows arrow tip pointing at it.
*
* @param usePinned used to determine target view. If true, will use the first matching pinned
* item. Otherwise, will use the first predicted child
* @param message String to be shown inside the arrowView
* @return whether suitable child was found and tip was shown
*/
private boolean showHotseatArrowTip(boolean usePinned, String message) {
int childCount = mHotseat.getShortcutsAndWidgets().getChildCount();
boolean isPortrait = !mLauncher.getDeviceProfile().isVerticalBarLayout();
BubbleTextView tipTargetView = null;
for (int i = childCount - 1; i > -1; i--) {
int x = isPortrait ? i : 0;
int y = isPortrait ? 0 : i;
View v = mHotseat.getShortcutsAndWidgets().getChildAt(x, y);
if (v instanceof BubbleTextView && v.getTag() instanceof WorkspaceItemInfo) {
ItemInfo info = (ItemInfo) v.getTag();
boolean isPinned = info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT;
if (isPinned == usePinned) {
tipTargetView = (BubbleTextView) v;
break;
}
}
}
if (tipTargetView == null) {
Log.e(TAG, "Unable to find suitable view for ArrowTip");
return false;
}
Rect bounds = mLauncher.getViewBounds(tipTargetView);
new ArrowTipView(mLauncher).show(message, Gravity.END, bounds.centerX(), bounds.top);
return true;
}
void showDialog() {
if (mPredictedApps == null || mPredictedApps.isEmpty()) {
return;
@@ -77,6 +77,11 @@ public class HotseatEduDialog extends AbstractSlideInView<Launcher> implements I
mContent = this;
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
setTranslationShift(TRANSLATION_SHIFT_CLOSED);
}
@Override
protected void onFinishInflate() {
@@ -200,9 +205,9 @@ public class HotseatEduDialog extends AbstractSlideInView<Launcher> implements I
}
AbstractFloatingView.closeAllOpenViews(mActivityContext);
attachToContainer();
mActivityContext.getStatsLogManager().logger().log(LAUNCHER_HOTSEAT_EDU_SEEN);
animateOpen();
populatePreview(predictions);
mActivityContext.getStatsLogManager().logger().log(LAUNCHER_HOTSEAT_EDU_SEEN);
}
/**
@@ -57,7 +57,6 @@ import com.android.launcher3.uioverrides.PredictedAppIcon;
import com.android.launcher3.uioverrides.QuickstepLauncher;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.OnboardingPrefs;
import com.android.launcher3.views.ArrowTipView;
import com.android.launcher3.views.Snackbar;
import java.util.ArrayList;
@@ -153,37 +152,14 @@ public class HotseatPredictionController implements DragController.DragListener,
*/
public void showEdu() {
mLauncher.getStateManager().goToState(NORMAL, true, forSuccessCallback(() -> {
if (mPredictedItems.isEmpty()) {
// launcher has empty predictions set
Snackbar.show(mLauncher, R.string.hotsaet_tip_prediction_disabled,
R.string.hotseat_prediction_settings, null,
() -> mLauncher.startActivity(getSettingsIntent()));
} else if (getPredictedIcons().size() >= (mHotSeatItemsCount + 1) / 2) {
showDiscoveryTip();
} else {
HotseatEduController eduController = new HotseatEduController(mLauncher);
eduController.setPredictedApps(mPredictedItems.stream()
.map(i -> (WorkspaceItemInfo) i)
.collect(Collectors.toList()));
eduController.showEdu();
}
HotseatEduController eduController = new HotseatEduController(mLauncher);
eduController.setPredictedApps(mPredictedItems.stream()
.map(i -> (WorkspaceItemInfo) i)
.collect(Collectors.toList()));
eduController.showEdu();
}));
}
/**
* Shows educational tip for hotseat if user does not go through Tips app.
*/
private void showDiscoveryTip() {
if (getPredictedIcons().isEmpty()) {
new ArrowTipView(mLauncher).show(
mLauncher.getString(R.string.hotseat_tip_no_empty_slots), mHotseat.getTop());
} else {
Snackbar.show(mLauncher, R.string.hotseat_tip_gaps_filled,
R.string.hotseat_prediction_settings, null,
() -> mLauncher.startActivity(getSettingsIntent()));
}
}
/**
* Returns if hotseat client has predictions
*/
@@ -510,6 +486,16 @@ public class HotseatPredictionController implements DragController.DragListener,
}
}
/**
* Called when user completes adding item requiring a config activity to the hotseat
*/
public void onDeferredDrop(int cellX, int cellY) {
View child = mHotseat.getChildAt(cellX, cellY);
if (child instanceof PredictedAppIcon) {
removeIconWithoutNotify((PredictedAppIcon) child);
}
}
private class PinPrediction extends SystemShortcut<QuickstepLauncher> {
private PinPrediction(QuickstepLauncher target, ItemInfo itemInfo) {
@@ -17,6 +17,7 @@ package com.android.launcher3.uioverrides;
import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_FOCUSED;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
@@ -69,6 +70,7 @@ import com.android.launcher3.uioverrides.touchcontrollers.TransposedQuickSwitchT
import com.android.launcher3.uioverrides.touchcontrollers.TwoButtonNavbarTouchController;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.OnboardingPrefs;
import com.android.launcher3.util.PendingRequestArgs;
import com.android.launcher3.util.TouchController;
import com.android.launcher3.util.UiThreadHelper;
import com.android.launcher3.util.UiThreadHelper.AsyncCommand;
@@ -138,6 +140,15 @@ public class QuickstepLauncher extends BaseQuickstepLauncher {
mHotseatPredictionController.logLaunchedAppRankingInfo(info, instanceId);
}
@Override
protected void completeAddShortcut(Intent data, int container, int screenId, int cellX,
int cellY, PendingRequestArgs args) {
if (container == CONTAINER_HOTSEAT) {
mHotseatPredictionController.onDeferredDrop(cellX, cellY);
}
super.completeAddShortcut(data, container, screenId, cellX, cellY, args);
}
@Override
protected LauncherAccessibilityDelegate createAccessibilityDelegate() {
return new QuickstepAccessibilityDelegate(this);
@@ -2725,7 +2725,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
if (showAsGrid) {
dismissedTaskWidth = dismissedTaskView.getLayoutParams().width + mPageSpacing;
isFocusedTaskDismissed = dismissedTaskViewId == mFocusedTaskViewId;
if (isFocusedTaskDismissed) {
if (isFocusedTaskDismissed && !isSplitSelectionActive()) {
nextFocusedTaskFromTop =
mTopRowIdSet.size() > 0 && mTopRowIdSet.size() >= (taskCount - 1) / 2f;
// Pick the next focused task from the preferred row.
@@ -2908,7 +2908,8 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
} else if (child instanceof TaskView) {
TaskView taskView = (TaskView) child;
if (isFocusedTaskDismissed) {
if (!isSameGridRow(taskView, nextFocusedTaskView)) {
if (nextFocusedTaskView != null &&
!isSameGridRow(taskView, nextFocusedTaskView)) {
continue;
}
} else {
@@ -2945,7 +2946,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
clampToProgress(LINEAR, 0f, ANIMATION_DISMISS_PROGRESS_MIDPOINT));
} else {
float primaryTranslation =
isFocusedTaskDismissed ? nextFocusedTaskWidth : dismissedTaskWidth;
nextFocusedTaskView != null ? nextFocusedTaskWidth : dismissedTaskWidth;
anim.setFloat(taskView, taskView.getPrimaryDismissTranslationProperty(),
mIsRtl ? primaryTranslation : -primaryTranslation,
clampToProgress(LINEAR, animationStartProgress,
@@ -3255,7 +3256,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
// Never enough space on phones
return true;
} else if (!mActivity.getDeviceProfile().isLandscape) {
return false;
return true;
}
Rect splitBounds = new Rect();
+1
View File
@@ -57,6 +57,7 @@
<dimen name="widget_handle_margin">13dp</dimen>
<dimen name="resize_frame_background_padding">24dp</dimen>
<dimen name="resize_frame_margin">22dp</dimen>
<dimen name="resize_frame_invalid_drag_across_two_panel_opacity_margin">24dp</dimen>
<!-- App widget reconfigure button -->
<dimen name="widget_reconfigure_button_corner_radius">14dp</dimen>
@@ -2,6 +2,7 @@ package com.android.launcher3;
import static android.appwidget.AppWidgetHostView.getDefaultPaddingForWidget;
import static com.android.launcher3.CellLayout.SPRING_LOADED_PROGRESS;
import static com.android.launcher3.LauncherAnimUtils.LAYOUT_HEIGHT;
import static com.android.launcher3.LauncherAnimUtils.LAYOUT_WIDTH;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WIDGET_RESIZE_COMPLETED;
@@ -9,6 +10,8 @@ import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCH
import static com.android.launcher3.views.BaseDragLayer.LAYOUT_X;
import static com.android.launcher3.views.BaseDragLayer.LAYOUT_Y;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
@@ -29,6 +32,7 @@ import androidx.annotation.Px;
import com.android.launcher3.accessibility.DragViewStateAnnouncer;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.keyboard.ViewGroupFocusHelper;
import com.android.launcher3.logging.InstanceId;
import com.android.launcher3.logging.InstanceIdSequence;
import com.android.launcher3.model.data.ItemInfo;
@@ -49,12 +53,14 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O
private static final String KEY_RECONFIGURABLE_WIDGET_EDUCATION_TIP_SEEN =
"launcher.reconfigurable_widget_education_tip_seen";
private static final Rect sTmpRect = new Rect();
private static final Rect sTmpRect2 = new Rect();
private static final int HANDLE_COUNT = 4;
private static final int INDEX_LEFT = 0;
private static final int INDEX_TOP = 1;
private static final int INDEX_RIGHT = 2;
private static final int INDEX_BOTTOM = 3;
private static final float MIN_OPACITY_FOR_CELL_LAYOUT_DURING_INVALID_RESIZE = 0.5f;
private final Launcher mLauncher;
private final DragViewStateAnnouncer mStateAnnouncer;
@@ -103,6 +109,16 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O
private final InstanceId logInstanceId = new InstanceIdSequence().newInstanceId();
private final ViewGroupFocusHelper mDragLayerRelativeCoordinateHelper;
/**
* In the two panel UI, it is not possible to resize a widget to cross its host
* {@link CellLayout}'s sibling. When this happens, we gradually reduce the opacity of the
* sibling {@link CellLayout} from 1f to
* {@link #MIN_OPACITY_FOR_CELL_LAYOUT_DURING_INVALID_RESIZE}.
*/
private final float mDragAcrossTwoPanelOpacityMargin;
private boolean mLeftBorderActive;
private boolean mRightBorderActive;
private boolean mTopBorderActive;
@@ -149,6 +165,10 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O
for (int i = 0; i < HANDLE_COUNT; i++) {
mSystemGestureExclusionRects.add(new Rect());
}
mDragAcrossTwoPanelOpacityMargin = mLauncher.getResources().getDimensionPixelSize(
R.dimen.resize_frame_invalid_drag_across_two_panel_opacity_margin);
mDragLayerRelativeCoordinateHelper = new ViewGroupFocusHelper(mLauncher.getDragLayer());
}
@Override
@@ -359,6 +379,37 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O
lp.y = sTmpRect.top;
}
// Handle invalid resize across CellLayouts in the two panel UI.
if (mCellLayout.getParent() instanceof Workspace) {
Workspace workspace = (Workspace) mCellLayout.getParent();
CellLayout pairedCellLayout = workspace.getScreenPair(mCellLayout);
if (pairedCellLayout != null) {
Rect focusedCellLayoutBound = sTmpRect;
mDragLayerRelativeCoordinateHelper.viewToRect(mCellLayout, focusedCellLayoutBound);
Rect resizeFrameBound = sTmpRect2;
findViewById(R.id.widget_resize_frame).getGlobalVisibleRect(resizeFrameBound);
float progress = 1f;
if (workspace.indexOfChild(pairedCellLayout) < workspace.indexOfChild(mCellLayout)
&& mDeltaX < 0
&& resizeFrameBound.left < focusedCellLayoutBound.left) {
// Resize from right to left.
progress = (mDragAcrossTwoPanelOpacityMargin + mDeltaX)
/ mDragAcrossTwoPanelOpacityMargin;
} else if (workspace.indexOfChild(pairedCellLayout)
> workspace.indexOfChild(mCellLayout)
&& mDeltaX > 0
&& resizeFrameBound.right > focusedCellLayoutBound.right) {
// Resize from left to right.
progress = (mDragAcrossTwoPanelOpacityMargin - mDeltaX)
/ mDragAcrossTwoPanelOpacityMargin;
}
float alpha = Math.max(MIN_OPACITY_FOR_CELL_LAYOUT_DURING_INVALID_RESIZE, progress);
float springLoadedProgress = Math.min(1f, 1f - progress);
updateInvalidResizeEffect(mCellLayout, pairedCellLayout, alpha,
springLoadedProgress);
}
}
requestLayout();
}
@@ -515,13 +566,24 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O
}
final DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
final CellLayout pairedCellLayout;
if (mCellLayout.getParent() instanceof Workspace) {
Workspace workspace = (Workspace) mCellLayout.getParent();
pairedCellLayout = workspace.getScreenPair(mCellLayout);
} else {
pairedCellLayout = null;
}
if (!animate) {
lp.width = newWidth;
lp.height = newHeight;
lp.x = newX;
lp.y = newY;
for (int i = 0; i < HANDLE_COUNT; i++) {
mDragHandles[i].setAlpha(1.0f);
mDragHandles[i].setAlpha(1f);
}
if (pairedCellLayout != null) {
updateInvalidResizeEffect(mCellLayout, pairedCellLayout, /* alpha= */ 1f,
/* springLoadedProgress= */ 0f);
}
requestLayout();
} else {
@@ -538,6 +600,10 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O
set.play(mFirstFrameAnimatorHelper.addTo(
ObjectAnimator.ofFloat(mDragHandles[i], ALPHA, 1f)));
}
if (pairedCellLayout != null) {
updateInvalidResizeEffect(mCellLayout, pairedCellLayout, /* alpha= */ 1f,
/* springLoadedProgress= */ 0f, /* animatorSet= */ set);
}
set.setDuration(SNAP_DURATION);
set.start();
}
@@ -624,6 +690,52 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O
}
}
private void updateInvalidResizeEffect(CellLayout cellLayout, CellLayout pairedCellLayout,
float alpha, float springLoadedProgress) {
updateInvalidResizeEffect(cellLayout, pairedCellLayout, alpha,
springLoadedProgress, /* animatorSet= */ null);
}
private void updateInvalidResizeEffect(CellLayout cellLayout, CellLayout pairedCellLayout,
float alpha, float springLoadedProgress, @Nullable AnimatorSet animatorSet) {
int childCount = pairedCellLayout.getChildCount();
for (int i = 0; i < childCount; i++) {
View child = pairedCellLayout.getChildAt(i);
if (animatorSet != null) {
animatorSet.play(
mFirstFrameAnimatorHelper.addTo(
ObjectAnimator.ofFloat(child, ALPHA, alpha)));
} else {
child.setAlpha(alpha);
}
}
if (animatorSet != null) {
animatorSet.play(mFirstFrameAnimatorHelper.addTo(
ObjectAnimator.ofFloat(cellLayout, SPRING_LOADED_PROGRESS,
springLoadedProgress)));
animatorSet.play(mFirstFrameAnimatorHelper.addTo(
ObjectAnimator.ofFloat(pairedCellLayout, SPRING_LOADED_PROGRESS,
springLoadedProgress)));
} else {
cellLayout.setSpringLoadedProgress(springLoadedProgress);
pairedCellLayout.setSpringLoadedProgress(springLoadedProgress);
}
boolean shouldShowCellLayoutBorder = springLoadedProgress > 0f;
if (animatorSet != null) {
animatorSet.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animator) {
cellLayout.setIsDragOverlapping(shouldShowCellLayoutBorder);
pairedCellLayout.setIsDragOverlapping(shouldShowCellLayoutBorder);
}
});
} else {
cellLayout.setIsDragOverlapping(shouldShowCellLayoutBorder);
pairedCellLayout.setIsDragOverlapping(shouldShowCellLayoutBorder);
}
}
@Override
protected boolean isOfType(int type) {
return (type & TYPE_WIDGET_RESIZE_FRAME) != 0;
+3 -3
View File
@@ -1264,7 +1264,7 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
*
* @param data The intent describing the shortcut.
*/
private void completeAddShortcut(Intent data, int container, int screenId, int cellX,
protected void completeAddShortcut(Intent data, int container, int screenId, int cellX,
int cellY, PendingRequestArgs args) {
if (args.getRequestCode() != REQUEST_CREATE_SHORTCUT
|| args.getPendingIntent().getComponent() == null) {
@@ -2128,7 +2128,7 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
actualIds.add(id);
}
int firstId = visibleIds.getArray().get(0);
int pairId = mWorkspace.getPagePair(firstId);
int pairId = mWorkspace.getScreenPair(firstId);
// Double check that actual screenIds contains the visibleId, as empty screens are hidden
// in single panel.
if (actualIds.contains(firstId)) {
@@ -2212,7 +2212,7 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
// Some empty pages might have been removed while the phone was in a single panel
// mode, so we want to add those empty pages back.
IntSet screenIds = IntSet.wrap(orderedScreenIds);
orderedScreenIds.forEach(screenId -> screenIds.add(mWorkspace.getPagePair(screenId)));
orderedScreenIds.forEach(screenId -> screenIds.add(mWorkspace.getScreenPair(screenId)));
orderedScreenIds = screenIds.getArray();
}
+2 -2
View File
@@ -208,7 +208,7 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
public void initParentViews(View parent) {
if (mPageIndicatorViewId > -1) {
mPageIndicator = parent.findViewById(mPageIndicatorViewId);
mPageIndicator.setMarkersCount(getChildCount());
mPageIndicator.setMarkersCount(getChildCount() / getPanelCount());
}
}
@@ -830,7 +830,7 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
private void dispatchPageCountChanged() {
if (mPageIndicator != null) {
mPageIndicator.setMarkersCount(getChildCount());
mPageIndicator.setMarkersCount(getChildCount() / getPanelCount());
}
// This ensures that when children are added, they get the correct transforms / alphas
// in accordance with any scroll effects.
+24 -7
View File
@@ -651,7 +651,7 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
// If the icon was dragged from Hotseat, there is no page pair
if (isTwoPanelEnabled() && !(mDragSourceInternal.getParent() instanceof Hotseat)) {
int pagePairScreenId = getPagePair(dragObject.dragInfo.screenId);
int pagePairScreenId = getScreenPair(dragObject.dragInfo.screenId);
CellLayout pagePair = mWorkspaceScreens.get(pagePairScreenId);
if (pagePair == null) {
// TODO: after http://b/198820019 is fixed, remove this
@@ -917,16 +917,33 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
}
/**
* Returns the page that is shown together with the given page when two panel is enabled.
* Returns the screen ID of a page that is shown together with the given page screen ID when the
* two panel UI is enabled.
*/
public int getPagePair(int page) {
if (page % 2 == 0) {
return page + 1;
public int getScreenPair(int screenId) {
if (screenId % 2 == 0) {
return screenId + 1;
} else {
return page - 1;
return screenId - 1;
}
}
/**
* Returns {@link CellLayout} that is shown together with the given {@link CellLayout} when the
* two panel UI is enabled.
*/
@Nullable
public CellLayout getScreenPair(CellLayout cellLayout) {
if (!isTwoPanelEnabled()) {
return null;
}
int screenId = getIdForScreen(cellLayout);
if (screenId == -1) {
return null;
}
return getScreenWithId(getScreenPair(screenId));
}
public void stripEmptyScreens() {
if (mLauncher.isWorkspaceLoading()) {
// Don't strip empty screens if the workspace is still loading.
@@ -959,7 +976,7 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
Iterator<Integer> removeScreensIterator = removeScreens.iterator();
while (removeScreensIterator.hasNext()) {
int pageToRemove = removeScreensIterator.next();
int pagePair = getPagePair(pageToRemove);
int pagePair = getScreenPair(pageToRemove);
if (!removeScreens.contains(pagePair)) {
// The page pair isn't empty so we want to remove the current page from the
// removable pages' collection
@@ -37,6 +37,7 @@ import androidx.core.content.ContextCompat;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.dragndrop.DragLayer;
@@ -56,6 +57,7 @@ public class ArrowTipView extends AbstractFloatingView {
protected final BaseDraggingActivity mActivity;
private final Handler mHandler = new Handler();
private final int mArrowWidth;
private final int mArrowMinOffset;
private boolean mIsPointingUp;
private Runnable mOnClosed;
private View mArrowView;
@@ -69,6 +71,8 @@ public class ArrowTipView extends AbstractFloatingView {
mActivity = BaseDraggingActivity.fromContext(context);
mIsPointingUp = isPointingUp;
mArrowWidth = context.getResources().getDimensionPixelSize(R.dimen.arrow_toast_arrow_width);
mArrowMinOffset = context.getResources().getDimensionPixelSize(
R.dimen.dynamic_grid_cell_border_spacing);
init(context);
}
@@ -126,10 +130,10 @@ public class ArrowTipView extends AbstractFloatingView {
/**
* Show the ArrowTipView (tooltip) center, start, or end aligned.
*
* @param text The text to be shown in the tooltip.
* @param gravity The gravity aligns the tooltip center, start, or end.
* @param text The text to be shown in the tooltip.
* @param gravity The gravity aligns the tooltip center, start, or end.
* @param arrowMarginStart The margin from start to place arrow (ignored if center)
* @param top The Y coordinate of the bottom of tooltip.
* @param top The Y coordinate of the bottom of tooltip.
* @return The tooltip.
*/
public ArrowTipView show(String text, int gravity, int arrowMarginStart, int top) {
@@ -152,23 +156,28 @@ public class ArrowTipView extends AbstractFloatingView {
ViewGroup parent = mActivity.getDragLayer();
parent.addView(this);
DeviceProfile grid = mActivity.getDeviceProfile();
DragLayer.LayoutParams params = (DragLayer.LayoutParams) getLayoutParams();
params.gravity = gravity;
params.leftMargin = mArrowMinOffset + grid.getInsets().left;
params.rightMargin = mArrowMinOffset + grid.getInsets().right;
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) mArrowView.getLayoutParams();
lp.gravity = gravity;
if (parent.getLayoutDirection() == LAYOUT_DIRECTION_RTL) {
arrowMarginStart = parent.getMeasuredWidth() - arrowMarginStart;
}
if (gravity == Gravity.END) {
lp.setMarginEnd(parent.getMeasuredWidth() - arrowMarginStart - mArrowWidth);
lp.setMarginEnd(Math.max(mArrowMinOffset,
parent.getMeasuredWidth() - params.rightMargin - arrowMarginStart
- mArrowWidth / 2));
} else if (gravity == Gravity.START) {
lp.setMarginStart(arrowMarginStart - mArrowWidth / 2);
lp.setMarginStart(Math.max(mArrowMinOffset,
arrowMarginStart - params.leftMargin - mArrowWidth / 2));
}
requestLayout();
params.leftMargin = mActivity.getDeviceProfile().workspacePadding.left;
params.rightMargin = mActivity.getDeviceProfile().workspacePadding.right;
post(() -> setY(top - (mIsPointingUp ? 0 : getHeight())));
mIsOpen = true;