Snap for 7406169 from 0bb96c9168 to sc-release
Change-Id: I0f17e42076c370e8fd2155f7293203c626b411c5
This commit is contained in:
@@ -171,7 +171,7 @@ public abstract class BaseQuickstepLauncher extends Launcher
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onUiChangedWhileSleeping() {
|
||||
public void onUiChangedWhileSleeping() {
|
||||
// Remove the snapshot because the content view may have obvious changes.
|
||||
UI_HELPER_EXECUTOR.execute(
|
||||
() -> ActivityManagerWrapper.getInstance().invalidateHomeTaskSnapshot(this));
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2019 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.appprediction;
|
||||
|
||||
import static com.android.launcher3.AbstractFloatingView.TYPE_DISCOVERY_BOUNCE;
|
||||
import static com.android.launcher3.AbstractFloatingView.TYPE_ON_BOARD_POPUP;
|
||||
import static com.android.launcher3.LauncherState.ALL_APPS;
|
||||
|
||||
import android.os.UserManager;
|
||||
|
||||
import com.android.launcher3.AbstractFloatingView;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.allapps.FloatingHeaderView;
|
||||
import com.android.launcher3.statemanager.StateManager.StateListener;
|
||||
import com.android.launcher3.views.ArrowTipView;
|
||||
|
||||
/**
|
||||
* ArrowTip helper aligned just above prediction apps, shown to users that enter all apps for the
|
||||
* first time.
|
||||
*/
|
||||
public class AllAppsTipView {
|
||||
|
||||
private static final String ALL_APPS_TIP_SEEN = "launcher.all_apps_tip_seen";
|
||||
|
||||
private static boolean showAllAppsTipIfNecessary(Launcher launcher) {
|
||||
FloatingHeaderView floatingHeaderView = launcher.getAppsView().getFloatingHeaderView();
|
||||
if (!floatingHeaderView.hasVisibleContent()
|
||||
|| AbstractFloatingView.getOpenView(launcher,
|
||||
TYPE_ON_BOARD_POPUP | TYPE_DISCOVERY_BOUNCE) != null
|
||||
|| !launcher.isInState(ALL_APPS)
|
||||
|| hasSeenAllAppsTip(launcher)
|
||||
|| launcher.getSystemService(UserManager.class).isDemoUser()
|
||||
|| Utilities.IS_RUNNING_IN_TEST_HARNESS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int[] coords = new int[2];
|
||||
floatingHeaderView.findFixedRowByType(PredictionRowView.class).getLocationOnScreen(coords);
|
||||
ArrowTipView arrowTipView = new ArrowTipView(launcher).setOnClosedCallback(() -> {
|
||||
launcher.getSharedPrefs().edit().putBoolean(ALL_APPS_TIP_SEEN, true).apply();
|
||||
// TODO: add log to WW
|
||||
});
|
||||
arrowTipView.show(launcher.getString(R.string.all_apps_prediction_tip), coords[1]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean hasSeenAllAppsTip(Launcher launcher) {
|
||||
return launcher.getSharedPrefs().getBoolean(ALL_APPS_TIP_SEEN, false);
|
||||
}
|
||||
|
||||
public static void scheduleShowIfNeeded(Launcher launcher) {
|
||||
if (!hasSeenAllAppsTip(launcher)) {
|
||||
launcher.getStateManager().addStateListener(new StateListener<LauncherState>() {
|
||||
@Override
|
||||
public void onStateTransitionComplete(LauncherState finalState) {
|
||||
if (finalState == ALL_APPS) {
|
||||
if (showAllAppsTipIfNecessary(launcher)) {
|
||||
launcher.getStateManager().removeStateListener(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -88,7 +88,6 @@ public class PredictionRowView extends LinearLayout implements
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
AllAppsTipView.scheduleShowIfNeeded(mLauncher);
|
||||
}
|
||||
|
||||
public void setup(FloatingHeaderView parent, FloatingHeaderRow[] rows, boolean tabsHidden) {
|
||||
|
||||
@@ -82,6 +82,7 @@ import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.anim.AnimationSuccessListener;
|
||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||
import com.android.launcher3.logging.StatsLogManager;
|
||||
import com.android.launcher3.logging.StatsLogManager.StatsLogger;
|
||||
import com.android.launcher3.statemanager.BaseState;
|
||||
@@ -1214,20 +1215,22 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
|
||||
&& (windowRotation == ROTATION_90 || windowRotation == ROTATION_270)) {
|
||||
swipePipToHomeAnimator.setFromRotation(mTaskViewSimulator, windowRotation);
|
||||
}
|
||||
AnimatorPlaybackController activityAnimationToHome =
|
||||
homeAnimFactory.createActivityAnimationToHome();
|
||||
swipePipToHomeAnimator.addListener(new AnimatorListenerAdapter() {
|
||||
private boolean mHasAnimationEnded;
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
if (mHasAnimationEnded) return;
|
||||
// Ensure Launcher ends in NORMAL state, we intentionally skip other callbacks
|
||||
// since they are not relevant in this swipe-pip-to-home case.
|
||||
homeAnimFactory.createActivityAnimationToHome().dispatchOnStart();
|
||||
// Ensure Launcher ends in NORMAL state
|
||||
activityAnimationToHome.dispatchOnStart();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
if (mHasAnimationEnded) return;
|
||||
mHasAnimationEnded = true;
|
||||
activityAnimationToHome.getAnimationPlayer().end();
|
||||
if (mRecentsAnimationController == null) {
|
||||
// If the recents animation is interrupted, we still end the running
|
||||
// animation (not canceled) so this is still called. In that case, we can
|
||||
|
||||
@@ -561,7 +561,7 @@ public class RecentsAnimationDeviceState implements
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mIsOneHandedModeEnabled || mIsSwipeToNotificationEnabled) {
|
||||
if (mIsOneHandedModeEnabled) {
|
||||
final Info displayInfo = mDisplayController.getInfo();
|
||||
return (mRotationTouchHelper.touchInOneHandedModeRegion(ev)
|
||||
&& displayInfo.rotation != Surface.ROTATION_90
|
||||
|
||||
@@ -40,6 +40,8 @@ import com.android.launcher3.util.SplitConfigurationOptions;
|
||||
import com.android.systemui.shared.recents.ISystemUiProxy;
|
||||
import com.android.systemui.shared.recents.model.Task;
|
||||
import com.android.systemui.shared.system.RemoteTransitionCompat;
|
||||
import com.android.systemui.shared.system.smartspace.ISmartspaceCallback;
|
||||
import com.android.systemui.shared.system.smartspace.ISmartspaceTransitionController;
|
||||
import com.android.wm.shell.onehanded.IOneHanded;
|
||||
import com.android.wm.shell.pip.IPip;
|
||||
import com.android.wm.shell.pip.IPipAnimationListener;
|
||||
@@ -61,6 +63,7 @@ public class SystemUiProxy implements ISystemUiProxy,
|
||||
|
||||
private ISystemUiProxy mSystemUiProxy;
|
||||
private IPip mPip;
|
||||
private ISmartspaceTransitionController mSmartspaceTransitionController;
|
||||
private ISplitScreen mSplitScreen;
|
||||
private IOneHanded mOneHanded;
|
||||
private IShellTransitions mShellTransitions;
|
||||
@@ -74,6 +77,7 @@ public class SystemUiProxy implements ISystemUiProxy,
|
||||
private IPipAnimationListener mPendingPipAnimationListener;
|
||||
private ISplitScreenListener mPendingSplitScreenListener;
|
||||
private IStartingWindowListener mPendingStartingWindowListener;
|
||||
private ISmartspaceCallback mPendingSmartspaceCallback;
|
||||
|
||||
// Used to dedupe calls to SystemUI
|
||||
private int mLastShelfHeight;
|
||||
@@ -125,7 +129,8 @@ public class SystemUiProxy implements ISystemUiProxy,
|
||||
|
||||
public void setProxy(ISystemUiProxy proxy, IPip pip, ISplitScreen splitScreen,
|
||||
IOneHanded oneHanded, IShellTransitions shellTransitions,
|
||||
IStartingWindow startingWindow) {
|
||||
IStartingWindow startingWindow,
|
||||
ISmartspaceTransitionController smartSpaceTransitionController) {
|
||||
unlinkToDeath();
|
||||
mSystemUiProxy = proxy;
|
||||
mPip = pip;
|
||||
@@ -133,6 +138,7 @@ public class SystemUiProxy implements ISystemUiProxy,
|
||||
mOneHanded = oneHanded;
|
||||
mShellTransitions = shellTransitions;
|
||||
mStartingWindow = startingWindow;
|
||||
mSmartspaceTransitionController = smartSpaceTransitionController;
|
||||
linkToDeath();
|
||||
// re-attach the listeners once missing due to setProxy has not been initialized yet.
|
||||
if (mPendingPipAnimationListener != null && mPip != null) {
|
||||
@@ -147,10 +153,14 @@ public class SystemUiProxy implements ISystemUiProxy,
|
||||
setStartingWindowListener(mPendingStartingWindowListener);
|
||||
mPendingStartingWindowListener = null;
|
||||
}
|
||||
if (mPendingSmartspaceCallback != null && mSmartspaceTransitionController != null) {
|
||||
setSmartspaceCallback(mPendingSmartspaceCallback);
|
||||
mPendingSmartspaceCallback = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void clearProxy() {
|
||||
setProxy(null, null, null, null, null, null);
|
||||
setProxy(null, null, null, null, null, null, null);
|
||||
}
|
||||
|
||||
// TODO(141886704): Find a way to remove this
|
||||
@@ -642,4 +652,21 @@ public class SystemUiProxy implements ISystemUiProxy,
|
||||
mPendingStartingWindowListener = listener;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// SmartSpace transitions
|
||||
//
|
||||
|
||||
public void setSmartspaceCallback(ISmartspaceCallback callback) {
|
||||
if (mSmartspaceTransitionController != null) {
|
||||
try {
|
||||
mSmartspaceTransitionController.setSmartspace(callback);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Failed call setStartingWindowListener", e);
|
||||
}
|
||||
} else {
|
||||
mPendingSmartspaceCallback = callback;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHE
|
||||
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_SHELL_TRANSITIONS;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_SPLIT_SCREEN;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_STARTING_WINDOW;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SMARTSPACE_TRANSITION_CONTROLLER;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_TRACING_ENABLED;
|
||||
|
||||
@@ -107,6 +108,7 @@ import com.android.systemui.shared.system.InputChannelCompat;
|
||||
import com.android.systemui.shared.system.InputChannelCompat.InputEventReceiver;
|
||||
import com.android.systemui.shared.system.InputConsumerController;
|
||||
import com.android.systemui.shared.system.InputMonitorCompat;
|
||||
import com.android.systemui.shared.system.smartspace.ISmartspaceTransitionController;
|
||||
import com.android.systemui.shared.tracing.ProtoTraceable;
|
||||
import com.android.wm.shell.onehanded.IOneHanded;
|
||||
import com.android.wm.shell.pip.IPip;
|
||||
@@ -164,9 +166,13 @@ public class TouchInteractionService extends Service implements PluginListener<O
|
||||
bundle.getBinder(KEY_EXTRA_SHELL_SHELL_TRANSITIONS));
|
||||
IStartingWindow startingWindow = IStartingWindow.Stub.asInterface(
|
||||
bundle.getBinder(KEY_EXTRA_SHELL_STARTING_WINDOW));
|
||||
ISmartspaceTransitionController smartspaceTransitionController =
|
||||
ISmartspaceTransitionController.Stub.asInterface(
|
||||
bundle.getBinder(KEY_EXTRA_SMARTSPACE_TRANSITION_CONTROLLER));
|
||||
MAIN_EXECUTOR.execute(() -> {
|
||||
SystemUiProxy.INSTANCE.get(TouchInteractionService.this).setProxy(proxy, pip,
|
||||
splitscreen, onehanded, shellTransitions, startingWindow);
|
||||
splitscreen, onehanded, shellTransitions, startingWindow,
|
||||
smartspaceTransitionController);
|
||||
TouchInteractionService.this.initInputMonitor();
|
||||
preloadOverview(true /* fromInit */);
|
||||
mDeviceState.runOnUserUnlocked(() -> {
|
||||
|
||||
@@ -147,12 +147,10 @@ public class OneHandedModeInputConsumer extends DelegateInputConsumer {
|
||||
}
|
||||
|
||||
private void onStartGestureDetected() {
|
||||
if (mDeviceState.isOneHandedModeEnabled()) {
|
||||
if (!mDeviceState.isOneHandedModeActive()) {
|
||||
SystemUiProxy.INSTANCE.get(mContext).startOneHandedMode();
|
||||
}
|
||||
} else if (mDeviceState.isSwipeToNotificationEnabled()) {
|
||||
if (mDeviceState.isSwipeToNotificationEnabled()) {
|
||||
SystemUiProxy.INSTANCE.get(mContext).expandNotificationPanel();
|
||||
} else if (!mDeviceState.isOneHandedModeActive()) {
|
||||
SystemUiProxy.INSTANCE.get(mContext).startOneHandedMode();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,8 +16,9 @@
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
|
||||
<item
|
||||
android:top="6dp"
|
||||
android:bottom="6dp">
|
||||
android:top="@dimen/all_apps_tabs_vertical_padding"
|
||||
android:bottom="@dimen/all_apps_tabs_vertical_padding
|
||||
">
|
||||
<shape android:shape="rectangle">
|
||||
<solid android:color="?androidprv:attr/colorSurface" />
|
||||
<corners android:radius="@dimen/all_apps_header_pill_corner_radius" />
|
||||
|
||||
@@ -14,9 +14,7 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<merge
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content">
|
||||
|
||||
@@ -40,7 +38,8 @@
|
||||
android:gravity="center"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:textColor="@color/arrow_tip_view_content"
|
||||
android:textSize="16sp"/>
|
||||
android:textSize="16sp" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/dismiss"
|
||||
android:layout_width="40dp"
|
||||
@@ -53,13 +52,13 @@
|
||||
android:src="@drawable/ic_remove_no_shadow"
|
||||
android:tint="@color/arrow_tip_view_content"
|
||||
android:background="?android:attr/selectableItemBackgroundBorderless"
|
||||
android:contentDescription="@string/accessibility_close"/>
|
||||
android:contentDescription="@string/accessibility_close" />
|
||||
</LinearLayout>
|
||||
|
||||
<View
|
||||
android:id="@+id/arrow"
|
||||
android:elevation="2dp"
|
||||
android:layout_width="10dp"
|
||||
android:layout_width="@dimen/arrow_toast_arrow_width"
|
||||
android:layout_height="8dp"
|
||||
android:layout_marginTop="-2dp"/>
|
||||
</merge>
|
||||
|
||||
@@ -105,6 +105,7 @@
|
||||
<dimen name="all_apps_tip_bottom_margin">8dp</dimen>
|
||||
<!-- The size of corner radius of the arrow in the arrow toast. -->
|
||||
<dimen name="arrow_toast_corner_radius">2dp</dimen>
|
||||
<dimen name="arrow_toast_arrow_width">10dp</dimen>
|
||||
|
||||
<!-- Search bar in All Apps -->
|
||||
<dimen name="all_apps_header_max_elevation">3dp</dimen>
|
||||
|
||||
+43
@@ -20,8 +20,10 @@ import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
|
||||
import android.appwidget.AppWidgetHostView;
|
||||
import android.content.Context;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.InvariantDeviceProfile;
|
||||
@@ -110,6 +112,47 @@ public final class LauncherAppWidgetProviderInfoTest {
|
||||
assertThat(info.minSpanY).isEqualTo(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void initSpans_minResizeWidthWithCellSpacingAndWidgetInset_shouldInitializeMinSpans() {
|
||||
InvariantDeviceProfile idp = createIDP();
|
||||
DeviceProfile dp = idp.supportedProfiles.get(0);
|
||||
Rect padding = new Rect();
|
||||
AppWidgetHostView.getDefaultPaddingForWidget(mContext, null, padding);
|
||||
int maxPadding = Math.max(Math.max(padding.left, padding.right),
|
||||
Math.max(padding.top, padding.bottom));
|
||||
dp.cellLayoutBorderSpacingPx = maxPadding + 1;
|
||||
Mockito.when(dp.shouldInsetWidgets()).thenReturn(true);
|
||||
|
||||
LauncherAppWidgetProviderInfo info = new LauncherAppWidgetProviderInfo();
|
||||
info.minResizeWidth = CELL_SIZE * 2 + maxPadding;
|
||||
info.minResizeHeight = CELL_SIZE * 2 + maxPadding;
|
||||
|
||||
info.initSpans(mContext, idp);
|
||||
|
||||
assertThat(info.minSpanX).isEqualTo(2);
|
||||
assertThat(info.minSpanY).isEqualTo(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void initSpans_minResizeWidthWithCellSpacingAndNoWidgetInset_shouldInitializeMinSpans() {
|
||||
InvariantDeviceProfile idp = createIDP();
|
||||
DeviceProfile dp = idp.supportedProfiles.get(0);
|
||||
Rect padding = new Rect();
|
||||
AppWidgetHostView.getDefaultPaddingForWidget(mContext, null, padding);
|
||||
int maxPadding = Math.max(Math.max(padding.left, padding.right),
|
||||
Math.max(padding.top, padding.bottom));
|
||||
dp.cellLayoutBorderSpacingPx = maxPadding - 1;
|
||||
Mockito.when(dp.shouldInsetWidgets()).thenReturn(false);
|
||||
LauncherAppWidgetProviderInfo info = new LauncherAppWidgetProviderInfo();
|
||||
info.minResizeWidth = CELL_SIZE * 2 + maxPadding;
|
||||
info.minResizeHeight = CELL_SIZE * 2 + maxPadding;
|
||||
|
||||
info.initSpans(mContext, idp);
|
||||
|
||||
assertThat(info.minSpanX).isEqualTo(3);
|
||||
assertThat(info.minSpanY).isEqualTo(3);
|
||||
}
|
||||
|
||||
private InvariantDeviceProfile createIDP() {
|
||||
DeviceProfile profile = Mockito.mock(DeviceProfile.class);
|
||||
doAnswer(i -> {
|
||||
|
||||
@@ -53,11 +53,19 @@ public class ArrowTipView extends AbstractFloatingView {
|
||||
|
||||
protected final BaseDraggingActivity mActivity;
|
||||
private final Handler mHandler = new Handler();
|
||||
private final boolean mIsPointingUp;
|
||||
private final int mArrowWidth;
|
||||
private Runnable mOnClosed;
|
||||
|
||||
public ArrowTipView(Context context) {
|
||||
this(context, false);
|
||||
}
|
||||
|
||||
public ArrowTipView(Context context, boolean isPointingUp) {
|
||||
super(context, null, 0);
|
||||
mActivity = BaseDraggingActivity.fromContext(context);
|
||||
mIsPointingUp = isPointingUp;
|
||||
mArrowWidth = context.getResources().getDimensionPixelSize(R.dimen.arrow_toast_arrow_width);
|
||||
init(context);
|
||||
}
|
||||
|
||||
@@ -105,13 +113,17 @@ public class ArrowTipView extends AbstractFloatingView {
|
||||
View arrowView = findViewById(R.id.arrow);
|
||||
ViewGroup.LayoutParams arrowLp = arrowView.getLayoutParams();
|
||||
ShapeDrawable arrowDrawable = new ShapeDrawable(TriangleShape.create(
|
||||
arrowLp.width, arrowLp.height, false));
|
||||
arrowLp.width, arrowLp.height, mIsPointingUp));
|
||||
Paint arrowPaint = arrowDrawable.getPaint();
|
||||
arrowPaint.setColor(ContextCompat.getColor(getContext(), R.color.arrow_tip_view_bg));
|
||||
arrowPaint.setColor(ContextCompat.getColor(getContext(), R.color.arrow_tip_view_bg));
|
||||
// The corner path effect won't be reflected in the shadow, but shouldn't be noticeable.
|
||||
arrowPaint.setPathEffect(new CornerPathEffect(
|
||||
context.getResources().getDimension(R.dimen.arrow_toast_corner_radius)));
|
||||
arrowView.setBackground(arrowDrawable);
|
||||
if (mIsPointingUp) {
|
||||
removeView(arrowView);
|
||||
addView(arrowView, 0);
|
||||
}
|
||||
|
||||
mIsOpen = true;
|
||||
|
||||
@@ -128,10 +140,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) {
|
||||
@@ -149,15 +161,15 @@ public class ArrowTipView extends AbstractFloatingView {
|
||||
arrowMarginStart = parent.getMeasuredWidth() - arrowMarginStart;
|
||||
}
|
||||
if (gravity == Gravity.END) {
|
||||
lp.setMarginEnd(parent.getMeasuredWidth() - arrowMarginStart);
|
||||
lp.setMarginEnd(parent.getMeasuredWidth() - arrowMarginStart - mArrowWidth);
|
||||
} else if (gravity == Gravity.START) {
|
||||
lp.setMarginStart(arrowMarginStart);
|
||||
lp.setMarginStart(arrowMarginStart - mArrowWidth / 2);
|
||||
}
|
||||
requestLayout();
|
||||
|
||||
params.leftMargin = mActivity.getDeviceProfile().workspacePadding.left;
|
||||
params.rightMargin = mActivity.getDeviceProfile().workspacePadding.right;
|
||||
post(() -> setY(top - getHeight()));
|
||||
post(() -> setY(top - (mIsPointingUp ? 0 : getHeight())));
|
||||
setAlpha(0);
|
||||
animate()
|
||||
.alpha(1f)
|
||||
@@ -172,13 +184,14 @@ public class ArrowTipView extends AbstractFloatingView {
|
||||
/**
|
||||
* Show the ArrowTipView (tooltip) custom aligned.
|
||||
*
|
||||
* @param text The text to be shown in the tooltip.
|
||||
* @param text The text to be shown in the tooltip.
|
||||
* @param arrowXCoord The X coordinate for the arrow on the tip. The arrow is usually in the
|
||||
* center of ArrowTipView unless the ArrowTipView goes beyond screen margin.
|
||||
* @param yCoord The Y coordinate of the bottom of the tooltip.
|
||||
* @param yCoord The Y coordinate of the bottom of the tooltip.
|
||||
* @return The tool tip view.
|
||||
*/
|
||||
@Nullable public ArrowTipView showAtLocation(String text, int arrowXCoord, int yCoord) {
|
||||
@Nullable
|
||||
public ArrowTipView showAtLocation(String text, int arrowXCoord, int yCoord) {
|
||||
ViewGroup parent = mActivity.getDragLayer();
|
||||
@Px int parentViewWidth = parent.getWidth();
|
||||
@Px int textViewWidth = getContext().getResources()
|
||||
|
||||
@@ -67,61 +67,86 @@ public class LauncherAppWidgetProviderInfo extends AppWidgetProviderInfo
|
||||
}
|
||||
|
||||
public void initSpans(Context context, InvariantDeviceProfile idp) {
|
||||
// Always assume we're working with the smallest span to make sure we
|
||||
// reserve enough space in both orientations.
|
||||
float smallestCellWidth = Float.MAX_VALUE;
|
||||
float smallestCellHeight = Float.MAX_VALUE;
|
||||
int minSpanX = 0;
|
||||
int minSpanY = 0;
|
||||
int maxSpanX = idp.numColumns;
|
||||
int maxSpanY = idp.numRows;
|
||||
int spanX = 0;
|
||||
int spanY = 0;
|
||||
|
||||
Rect widgetPadding = new Rect();
|
||||
Rect localPadding = new Rect();
|
||||
AppWidgetHostView.getDefaultPaddingForWidget(context, provider, widgetPadding);
|
||||
|
||||
Point cellSize = new Point();
|
||||
boolean isWidgetPadded = false;
|
||||
for (DeviceProfile dp : idp.supportedProfiles) {
|
||||
dp.getCellSize(cellSize);
|
||||
smallestCellWidth = Math.min(smallestCellWidth, cellSize.x);
|
||||
smallestCellHeight = Math.min(smallestCellHeight, cellSize.y);
|
||||
isWidgetPadded = isWidgetPadded || !dp.shouldInsetWidgets();
|
||||
// We want to account for the extra amount of padding that we are adding to the widget
|
||||
// to ensure that it gets the full amount of space that it has requested.
|
||||
// If grids supports insetting widgets, we do not account for widget padding.
|
||||
if (dp.shouldInsetWidgets()) {
|
||||
localPadding.setEmpty();
|
||||
} else {
|
||||
localPadding.set(widgetPadding);
|
||||
}
|
||||
minSpanX = Math.max(minSpanX,
|
||||
getSpanX(localPadding, minResizeWidth, dp.cellLayoutBorderSpacingPx,
|
||||
cellSize.x));
|
||||
minSpanY = Math.max(minSpanY,
|
||||
getSpanY(localPadding, minResizeHeight, dp.cellLayoutBorderSpacingPx,
|
||||
cellSize.y));
|
||||
|
||||
if (ATLEAST_S) {
|
||||
if (maxResizeWidth > 0) {
|
||||
maxSpanX = Math.min(maxSpanX,
|
||||
getSpanX(localPadding, maxResizeWidth, dp.cellLayoutBorderSpacingPx,
|
||||
cellSize.x));
|
||||
}
|
||||
if (maxResizeHeight > 0) {
|
||||
maxSpanY = Math.min(maxSpanY,
|
||||
getSpanY(localPadding, maxResizeHeight, dp.cellLayoutBorderSpacingPx,
|
||||
cellSize.y));
|
||||
}
|
||||
}
|
||||
|
||||
spanX = Math.max(spanX,
|
||||
getSpanX(localPadding, minWidth, dp.cellLayoutBorderSpacingPx, cellSize.x));
|
||||
spanY = Math.max(spanY,
|
||||
getSpanY(localPadding, minHeight, dp.cellLayoutBorderSpacingPx, cellSize.y));
|
||||
}
|
||||
|
||||
// We want to account for the extra amount of padding that we are adding to the widget
|
||||
// to ensure that it gets the full amount of space that it has requested.
|
||||
// If grids supports insetting widgets, we do not account for widget padding.
|
||||
Rect widgetPadding = new Rect();
|
||||
if (isWidgetPadded) {
|
||||
AppWidgetHostView.getDefaultPaddingForWidget(context, provider, widgetPadding);
|
||||
if (ATLEAST_S) {
|
||||
// Ensures maxSpan >= minSpan
|
||||
maxSpanX = Math.max(maxSpanX, minSpanX);
|
||||
maxSpanY = Math.max(maxSpanY, minSpanY);
|
||||
|
||||
// Use targetCellWidth/Height if it is within the min/max ranges.
|
||||
// Otherwise, use the span of minWidth/Height.
|
||||
if (targetCellWidth >= minSpanX && targetCellWidth <= maxSpanX
|
||||
&& targetCellHeight >= minSpanY && targetCellHeight <= maxSpanY) {
|
||||
spanX = targetCellWidth;
|
||||
spanY = targetCellHeight;
|
||||
}
|
||||
}
|
||||
|
||||
minSpanX = getSpanX(widgetPadding, minResizeWidth, smallestCellWidth);
|
||||
minSpanY = getSpanY(widgetPadding, minResizeHeight, smallestCellHeight);
|
||||
|
||||
// Use maxResizeWidth/Height if they are defined and we're on S or above.
|
||||
maxSpanX =
|
||||
(ATLEAST_S && maxResizeWidth > 0)
|
||||
? getSpanX(widgetPadding, maxResizeWidth, smallestCellWidth)
|
||||
: idp.numColumns;
|
||||
maxSpanY =
|
||||
(ATLEAST_S && maxResizeHeight > 0)
|
||||
? getSpanY(widgetPadding, maxResizeHeight, smallestCellHeight)
|
||||
: idp.numRows;
|
||||
|
||||
// Use targetCellWidth/Height if it is within the min/max ranges and we're on S or above.
|
||||
// Otherwise, fall back to minWidth/Height.
|
||||
if (ATLEAST_S && targetCellWidth >= minSpanX && targetCellWidth <= maxSpanX
|
||||
&& targetCellHeight >= minSpanY && targetCellHeight <= maxSpanY) {
|
||||
spanX = targetCellWidth;
|
||||
spanY = targetCellHeight;
|
||||
} else {
|
||||
spanX = getSpanX(widgetPadding, minWidth, smallestCellWidth);
|
||||
spanY = getSpanY(widgetPadding, minHeight, smallestCellHeight);
|
||||
}
|
||||
this.minSpanX = minSpanX;
|
||||
this.minSpanY = minSpanY;
|
||||
this.maxSpanX = maxSpanX;
|
||||
this.maxSpanY = maxSpanY;
|
||||
this.spanX = spanX;
|
||||
this.spanY = spanY;
|
||||
}
|
||||
|
||||
private int getSpanX(Rect widgetPadding, int widgetWidth, float cellWidth) {
|
||||
private int getSpanX(Rect widgetPadding, int widgetWidth, int cellSpacing, float cellWidth) {
|
||||
return Math.max(1, (int) Math.ceil(
|
||||
(widgetWidth + widgetPadding.left + widgetPadding.right) / cellWidth));
|
||||
(widgetWidth + widgetPadding.left + widgetPadding.right + cellSpacing) / (cellWidth
|
||||
+ cellSpacing)));
|
||||
}
|
||||
|
||||
private int getSpanY(Rect widgetPadding, int widgetHeight, float cellHeight) {
|
||||
private int getSpanY(Rect widgetPadding, int widgetHeight, int cellSpacing, float cellHeight) {
|
||||
return Math.max(1, (int) Math.ceil(
|
||||
(widgetHeight + widgetPadding.top + widgetPadding.bottom) / cellHeight));
|
||||
(widgetHeight + widgetPadding.top + widgetPadding.bottom + cellSpacing) / (
|
||||
cellHeight + cellSpacing)));
|
||||
}
|
||||
|
||||
public String getLabel(PackageManager packageManager) {
|
||||
|
||||
Reference in New Issue
Block a user