Snap for 8591706 from a7c8850a5a to tm-qpr1-release

Change-Id: I5bc8cb8733c5f8749d5345ef7f78cd8fc5c897dc
This commit is contained in:
Android Build Coastguard Worker
2022-05-14 05:15:35 +00:00
36 changed files with 612 additions and 290 deletions
+1
View File
@@ -57,6 +57,7 @@
android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<action android:name="android.intent.action.SHOW_WORK_APPS" />
<category android:name="android.intent.category.HOME" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.MONKEY"/>
@@ -92,6 +92,9 @@ import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.unfold.UnfoldTransitionFactory;
import com.android.systemui.unfold.UnfoldTransitionProgressProvider;
import com.android.systemui.unfold.config.UnfoldTransitionConfig;
import com.android.systemui.unfold.system.ActivityManagerActivityTypeProvider;
import com.android.systemui.unfold.system.DeviceStateManagerFoldProvider;
import com.android.systemui.unfold.config.ResourceUnfoldTransitionConfig;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -343,15 +346,17 @@ public abstract class BaseQuickstepLauncher extends Launcher {
}
private void initUnfoldTransitionProgressProvider() {
final UnfoldTransitionConfig config = UnfoldTransitionFactory.createConfig(this);
final UnfoldTransitionConfig config = new ResourceUnfoldTransitionConfig();
if (config.isEnabled()) {
mUnfoldTransitionProgressProvider =
UnfoldTransitionFactory.createUnfoldTransitionProgressProvider(
this,
/* context= */ this,
config,
ProxyScreenStatusProvider.INSTANCE,
getSystemService(DeviceStateManager.class),
getSystemService(ActivityManager.class),
new DeviceStateManagerFoldProvider(
getSystemService(DeviceStateManager.class), /* context */this),
new ActivityManagerActivityTypeProvider(
getSystemService(ActivityManager.class)),
getSystemService(SensorManager.class),
getMainThreadHandler(),
getMainExecutor(),
@@ -19,6 +19,7 @@ import static com.android.launcher3.taskbar.TaskbarLauncherStateController.FLAG_
import static com.android.systemui.shared.system.WindowManagerWrapper.ITYPE_EXTRA_NAVIGATION_BAR;
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.annotation.ColorInt;
import android.os.RemoteException;
import android.util.Log;
@@ -28,6 +29,7 @@ import android.view.TaskTransitionSpec;
import android.view.WindowManagerGlobal;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import com.android.launcher3.BaseQuickstepLauncher;
@@ -139,6 +141,24 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
mControllers.taskbarStashController.onLongPressToUnstashTaskbar();
}
/**
* Adds the Launcher resume animator to the given animator set.
*
* This should be used to run a Launcher resume animation whose progress matches a
* swipe progress.
*
* @param placeholderDuration a placeholder duration to be used to ensure all full-length
* sub-animations are properly coordinated. This duration should not
* actually be used since this animation tracks a swipe progress.
*/
protected void addLauncherResumeAnimation(AnimatorSet animation, int placeholderDuration) {
animation.play(onLauncherResumedOrPaused(
/* isResumed= */ true,
/* fromInit= */ false,
/* startAnimation= */ false,
placeholderDuration));
}
/**
* Should be called from onResume() and onPause(), and animates the Taskbar accordingly.
*/
@@ -147,9 +167,19 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
}
private void onLauncherResumedOrPaused(boolean isResumed, boolean fromInit) {
onLauncherResumedOrPaused(
isResumed,
fromInit,
/* startAnimation= */ true,
QuickstepTransitionManager.CONTENT_ALPHA_DURATION);
}
@Nullable
private Animator onLauncherResumedOrPaused(
boolean isResumed, boolean fromInit, boolean startAnimation, int duration) {
if (mKeyguardController.isScreenOff()) {
if (!isResumed) {
return;
return null;
} else {
// Resuming implicitly means device unlocked
mKeyguardController.setScreenOn();
@@ -157,8 +187,7 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
}
mTaskbarLauncherStateController.updateStateForFlag(FLAG_RESUMED, isResumed);
mTaskbarLauncherStateController.applyState(
fromInit ? 0 : QuickstepTransitionManager.CONTENT_ALPHA_DURATION);
return mTaskbarLauncherStateController.applyState(fromInit ? 0 : duration, startAnimation);
}
/**
@@ -29,6 +29,7 @@ import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_N
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.app.ActivityOptions;
import android.content.ActivityNotFoundException;
import android.content.Context;
@@ -60,6 +61,8 @@ import com.android.launcher3.BubbleTextView;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.R;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dot.DotInfo;
import com.android.launcher3.folder.Folder;
import com.android.launcher3.folder.FolderIcon;
@@ -734,6 +737,45 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
return mIsNavBarForceVisible;
}
/**
* Displays a single frame of the Launcher start from SUW animation.
*
* This animation is a combination of the Launcher resume animation, which animates the hotseat
* icons into position, the Taskbar unstash to hotseat animation, which animates the Taskbar
* stash bar into the hotseat icons, and an override to prevent showing the Taskbar all apps
* button.
*
* This should be used to run a Taskbar unstash to hotseat animation whose progress matches a
* swipe progress.
*
* @param duration a placeholder duration to be used to ensure all full-length
* sub-animations are properly coordinated. This duration should not actually
* be used since this animation tracks a swipe progress.
*/
protected AnimatorPlaybackController createLauncherStartFromSuwAnim(int duration) {
AnimatorSet fullAnimation = new AnimatorSet();
fullAnimation.setDuration(duration);
TaskbarUIController uiController = mControllers.uiController;
if (uiController instanceof LauncherTaskbarUIController) {
((LauncherTaskbarUIController) uiController).addLauncherResumeAnimation(
fullAnimation, duration);
}
mControllers.taskbarStashController.addUnstashToHotseatAnimation(fullAnimation, duration);
if (!FeatureFlags.ENABLE_ALL_APPS_BUTTON_IN_HOTSEAT.get()) {
ValueAnimator alphaOverride = ValueAnimator.ofFloat(0, 1);
alphaOverride.setDuration(duration);
alphaOverride.addUpdateListener(a -> {
// Override the alpha updates in the icon alignment animation.
mControllers.taskbarViewController.getAllAppsButtonView().setAlpha(0);
});
fullAnimation.play(alphaOverride);
}
return AnimatorPlaybackController.wrap(fullAnimation, duration);
}
/**
* Called when we determine the touchable region.
*
@@ -39,6 +39,7 @@ import androidx.annotation.Nullable;
import com.android.launcher3.BaseQuickstepLauncher;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.statemanager.StatefulActivity;
import com.android.launcher3.taskbar.unfold.NonDestroyableScopedUnfoldTransitionProgressProvider;
import com.android.launcher3.util.DisplayController;
@@ -182,6 +183,17 @@ public class TaskbarManager {
}
}
/**
* Displays a frame of the first Launcher reveal animation.
*
* This should be used to run a first Launcher reveal animation whose progress matches a swipe
* progress.
*/
public AnimatorPlaybackController createLauncherStartFromSuwAnim(int duration) {
return mTaskbarActivityContext == null
? null : mTaskbarActivityContext.createLauncherStartFromSuwAnim(duration);
}
/**
* Called when the user is unlocked
*/
@@ -35,6 +35,8 @@ import android.view.WindowInsets;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatorListeners;
import com.android.launcher3.taskbar.allapps.TaskbarAllAppsSlideInView;
import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
import com.android.quickstep.AnimatedFloat;
@@ -367,13 +369,34 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba
return false;
}
/**
* Adds the Taskbar unstash to Hotseat animator to the animator set.
*
* This should be used to run a Taskbar unstash to Hotseat animation whose progress matches a
* swipe progress.
*
* @param placeholderDuration a placeholder duration to be used to ensure all full-length
* sub-animations are properly coordinated. This duration should not
* actually be used since this animation tracks a swipe progress.
*/
protected void addUnstashToHotseatAnimation(AnimatorSet animation, int placeholderDuration) {
createAnimToIsStashed(
/* isStashed= */ false,
placeholderDuration,
/* startDelay= */ 0,
/* animateBg= */ false);
animation.play(mAnimator);
}
/**
* Create a stash animation and save to {@link #mAnimator}.
* @param isStashed whether it's a stash animation or an unstash animation
* @param duration duration of the animation
* @param startDelay how many milliseconds to delay the animation after starting it.
* @param animateBg whether the taskbar's background should be animated
*/
private void createAnimToIsStashed(boolean isStashed, long duration, long startDelay) {
private void createAnimToIsStashed(
boolean isStashed, long duration, long startDelay, boolean animateBg) {
if (mAnimator != null) {
mAnimator.cancel();
}
@@ -408,10 +431,14 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba
secondHalfDurationScale = 0.5f;
final float stashTranslation = (mUnstashedHeight - mStashedHeight) / 2f;
fullLengthAnimatorSet.playTogether(
mTaskbarBackgroundOffset.animateToValue(1),
mIconTranslationYForStash.animateToValue(stashTranslation)
);
fullLengthAnimatorSet.play(mIconTranslationYForStash.animateToValue(stashTranslation));
if (animateBg) {
fullLengthAnimatorSet.play(mTaskbarBackgroundOffset.animateToValue(1));
} else {
fullLengthAnimatorSet.addListener(AnimatorListeners.forEndCallback(
() -> mTaskbarBackgroundOffset.updateValue(1)));
}
firstHalfAnimatorSet.playTogether(
mIconAlphaForStash.animateToValue(0),
mIconScaleForStash.animateToValue(STASHED_TASKBAR_SCALE)
@@ -424,10 +451,15 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba
secondHalfDurationScale = 0.75f;
fullLengthAnimatorSet.playTogether(
mTaskbarBackgroundOffset.animateToValue(0),
mIconScaleForStash.animateToValue(1),
mIconTranslationYForStash.animateToValue(0)
);
mIconTranslationYForStash.animateToValue(0));
if (animateBg) {
fullLengthAnimatorSet.play(mTaskbarBackgroundOffset.animateToValue(0));
} else {
fullLengthAnimatorSet.addListener(AnimatorListeners.forEndCallback(
() -> mTaskbarBackgroundOffset.updateValue(0)));
}
firstHalfAnimatorSet.playTogether(
mTaskbarStashedHandleAlpha.animateToValue(0)
);
@@ -728,7 +760,7 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba
mIsStashed = isStashed;
// This sets mAnimator.
createAnimToIsStashed(mIsStashed, duration, startDelay);
createAnimToIsStashed(mIsStashed, duration, startDelay, /* animateBg= */ true);
if (start) {
mAnimator.start();
}
@@ -258,21 +258,21 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
setter.addOnFrameListener(anim -> mActivity.setTaskbarWindowHeight(
anim.getAnimatedFraction() > 0 ? expandedHeight : collapsedHeight));
int count = mTaskbarView.getChildCount();
for (int i = 0; i < count; i++) {
for (int i = 0; i < mTaskbarView.getChildCount(); i++) {
View child = mTaskbarView.getChildAt(i);
int positionInHotseat = -1;
boolean isRtl = Utilities.isRtl(child.getResources());
int positionInHotseat;
if (FeatureFlags.ENABLE_ALL_APPS_IN_TASKBAR.get()
&& ((isRtl && i == 0) || (!isRtl && i == count - 1))) {
&& child == mTaskbarView.getAllAppsButtonView()) {
// Note that there is no All Apps button in the hotseat, this position is only used
// as its convenient for animation purposes.
positionInHotseat = isRtl
positionInHotseat = Utilities.isRtl(child.getResources())
? -1
: mActivity.getDeviceProfile().numShownHotseatIcons;
setter.setViewAlpha(child, 0, LINEAR);
if (!FeatureFlags.ENABLE_ALL_APPS_BUTTON_IN_HOTSEAT.get()) {
setter.setViewAlpha(child, 0, LINEAR);
}
} else if (child.getTag() instanceof ItemInfo) {
positionInHotseat = ((ItemInfo) child.getTag()).screenId;
} else {
@@ -51,6 +51,7 @@ import android.os.Bundle;
import android.os.IBinder;
import android.os.Looper;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.util.Log;
import android.view.Choreographer;
import android.view.InputEvent;
@@ -127,6 +128,9 @@ public class TouchInteractionService extends Service
private static final String TAG = "TouchInteractionService";
private static final boolean BUBBLES_HOME_GESTURE_ENABLED =
SystemProperties.getBoolean("persist.wm.debug.bubbles_home_gesture", false);
private static final String KEY_BACK_NOTIFICATION_COUNT = "backNotificationCount";
private static final String NOTIFY_ACTION_BACK = "com.android.quickstep.action.BACK_GESTURE";
private static final String HAS_ENABLED_QUICKSTEP_ONCE = "launcher.has_enabled_quickstep_once";
@@ -698,16 +702,30 @@ public class TouchInteractionService extends Service
base = new TaskbarStashInputConsumer(this, base, mInputMonitorCompat, tac);
}
// If Bubbles is expanded, use the overlay input consumer, which will close Bubbles
// instead of going all the way home when a swipe up is detected.
// Notification panel can be expanded on top of expanded bubbles. Bubbles remain
// expanded in the back. Make sure swipe up is not passed to bubbles in this case.
if ((mDeviceState.isBubblesExpanded() && !mDeviceState.isNotificationPanelExpanded())
|| mDeviceState.isSystemUiDialogShowing()) {
if (mDeviceState.isBubblesExpanded()) {
if (BUBBLES_HOME_GESTURE_ENABLED) {
// Bubbles can handle home gesture itself.
base = getDefaultInputConsumer();
} else {
// If Bubbles is expanded, use the overlay input consumer, which will close
// Bubbles instead of going all the way home when a swipe up is detected.
// Notification panel can be expanded on top of expanded bubbles. Bubbles remain
// expanded in the back. Make sure swipe up is not passed to bubbles in this
// case.
if (!mDeviceState.isNotificationPanelExpanded()) {
base = new SysUiOverlayInputConsumer(
getBaseContext(), mDeviceState, mInputMonitorCompat);
}
}
}
if (mDeviceState.isSystemUiDialogShowing()) {
base = new SysUiOverlayInputConsumer(
getBaseContext(), mDeviceState, mInputMonitorCompat);
}
if (mDeviceState.isScreenPinningActive()) {
// Note: we only allow accessibility to wrap this, and it replaces the previous
// base input consumer (which should be NO_OP anyway since topTaskLocked == true).
@@ -17,6 +17,7 @@ package com.android.quickstep.interaction;
import static com.android.launcher3.Utilities.mapBoundToRange;
import static com.android.launcher3.Utilities.mapRange;
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import android.animation.Animator;
@@ -54,6 +55,8 @@ import androidx.core.graphics.ColorUtils;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.util.Executors;
import com.android.quickstep.AnimatedFloat;
import com.android.quickstep.GestureState;
import com.android.quickstep.TouchInteractionService.TISBinder;
@@ -77,6 +80,8 @@ public class AllSetActivity extends Activity {
private static final float HINT_BOTTOM_FACTOR = 1 - .94f;
private static final int MAX_SWIPE_DURATION = 350;
private TISBindHelper mTISBindHelper;
private TISBinder mBinder;
@@ -89,6 +94,8 @@ public class AllSetActivity extends Activity {
private LottieAnimationView mAnimatedBackground;
private Animator.AnimatorListener mBackgroundAnimatorListener;
private AnimatorPlaybackController mLauncherStartAnim = null;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -136,6 +143,10 @@ public class AllSetActivity extends Activity {
startBackgroundAnimation();
}
private void runOnUiHelperThread(Runnable runnable) {
Executors.UI_HELPER_EXECUTOR.execute(runnable);
}
private void startBackgroundAnimation() {
if (Utilities.ATLEAST_S && mVibrator != null && mVibrator.areAllPrimitivesSupported(
VibrationEffect.Composition.PRIMITIVE_THUD)) {
@@ -144,22 +155,22 @@ public class AllSetActivity extends Activity {
new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
mVibrator.vibrate(getVibrationEffect());
runOnUiHelperThread(() -> mVibrator.vibrate(getVibrationEffect()));
}
@Override
public void onAnimationRepeat(Animator animation) {
mVibrator.vibrate(getVibrationEffect());
runOnUiHelperThread(() -> mVibrator.vibrate(getVibrationEffect()));
}
@Override
public void onAnimationEnd(Animator animation) {
mVibrator.cancel();
runOnUiHelperThread(mVibrator::cancel);
}
@Override
public void onAnimationCancel(Animator animation) {
mVibrator.cancel();
runOnUiHelperThread(mVibrator::cancel);
}
};
}
@@ -232,11 +243,20 @@ public class AllSetActivity extends Activity {
private void onSwipeProgressUpdate() {
mBackground.setProgress(mSwipeProgress.value);
float alpha = Utilities.mapBoundToRange(mSwipeProgress.value, 0, HINT_BOTTOM_FACTOR,
1, 0, LINEAR);
float alpha = Utilities.mapBoundToRange(
mSwipeProgress.value, 0, HINT_BOTTOM_FACTOR, 1, 0, LINEAR);
mContentView.setAlpha(alpha);
mContentView.setTranslationY((alpha - 1) * mSwipeUpShift);
if (mLauncherStartAnim == null) {
mLauncherStartAnim = mBinder.getTaskbarManager().createLauncherStartFromSuwAnim(
MAX_SWIPE_DURATION);
}
if (mLauncherStartAnim != null) {
mLauncherStartAnim.setPlayFraction(Utilities.mapBoundToRange(
mSwipeProgress.value, 0, 1, 0, 1, FAST_OUT_SLOW_IN));
}
if (alpha == 0f) {
mAnimatedBackground.pauseAnimation();
} else if (!mAnimatedBackground.isAnimating()) {
+3
View File
@@ -16,6 +16,9 @@
-->
<resources>
<!-- PagedView -->
<dimen name="min_page_snap_velocity">3600dp</dimen>
<!-- Hotseat -->
<dimen name="spring_loaded_hotseat_top_margin">44dp</dimen>
+21
View File
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<resources>
<!-- The duration of the PagedView page snap animation -->
<integer name="config_pageSnapAnimationDuration">550</integer>
</resources>
+3
View File
@@ -15,6 +15,9 @@
-->
<resources>
<!-- PagedView-->
<dimen name="min_page_snap_velocity">3000dp</dimen>
<!-- DragController -->
<dimen name="drag_flingToDeleteMinVelocity">-1000dp</dimen>
+3
View File
@@ -15,6 +15,9 @@
-->
<resources>
<!-- PagedView -->
<dimen name="min_page_snap_velocity">5300dp</dimen>
<!-- Dynamic grid -->
<dimen name="dynamic_grid_edge_margin">21.93dp</dimen>
<dimen name="cell_layout_padding">29.33dp</dimen>
+4
View File
@@ -15,6 +15,9 @@
-->
<resources>
<!-- PagedView -->
<dimen name="min_page_snap_velocity">3400dp</dimen>
<!-- AllApps -->
<dimen name="all_apps_bottom_sheet_horizontal_padding">28dp</dimen>
@@ -28,6 +31,7 @@
<dimen name="drop_target_button_drawable_horizontal_padding">24dp</dimen>
<dimen name="drop_target_button_drawable_vertical_padding">20dp</dimen>
<dimen name="drop_target_button_gap">32dp</dimen>
<dimen name="drop_target_button_workspace_edge_gap">32dp</dimen>
<dimen name="drop_target_top_margin">110dp</dimen>
<dimen name="drop_target_bottom_margin">48dp</dimen>
+18
View File
@@ -1,3 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<resources>
<!-- Miscellaneous -->
<bool name="config_largeHeap">false</bool>
@@ -25,6 +40,9 @@
<!-- The duration of the animation from search hint to text entry -->
<integer name="config_searchHintAnimationDuration">50</integer>
<!-- The duration of the PagedView page snap animation -->
<integer name="config_pageSnapAnimationDuration">750</integer>
<!-- View tag key used to store SpringAnimation data. -->
<item type="id" name="spring_animation_tag" />
+13 -6
View File
@@ -24,6 +24,8 @@
<dimen name="dynamic_grid_icon_drawable_padding">7dp</dimen>
<!-- Minimum space between workspace and hotseat in spring loaded mode -->
<dimen name="dynamic_grid_min_spring_loaded_space">8dp</dimen>
<!-- Minimum amount of next page visible in spring loaded mode -->
<dimen name="dynamic_grid_spring_loaded_min_next_space_visible">24dp</dimen>
<dimen name="dynamic_grid_cell_border_spacing">16dp</dimen>
<dimen name="cell_layout_padding">10.77dp</dimen>
@@ -58,13 +60,9 @@
<!-- Drop target bar -->
<dimen name="dynamic_grid_drop_target_size">56dp</dimen>
<dimen name="drop_target_vertical_gap">20dp</dimen>
<dimen name="drop_target_top_margin">36dp</dimen>
<dimen name="drop_target_top_margin">32dp</dimen>
<dimen name="drop_target_bottom_margin">16dp</dimen>
<!-- Button drop target bar -->
<dimen name="button_drop_target_min_text_size">10sp</dimen>
<dimen name="button_drop_target_resize_text_increment">1sp</dimen>
<!-- App Widget resize frame -->
<dimen name="widget_handle_margin">13dp</dimen>
<dimen name="resize_frame_background_padding">24dp</dimen>
@@ -99,6 +97,13 @@
<dimen name="fastscroll_width">58dp</dimen>
<dimen name="fastscroll_end_margin">-26dp</dimen>
<!-- PagedView -->
<dimen name="fling_threshold_velocity">500dp</dimen>
<dimen name="easy_fling_threshold_velocity">400dp</dimen>
<dimen name="min_fling_velocity">250dp</dimen>
<!-- The minimum velocity of a page snap after a fling gesture -->
<dimen name="min_page_snap_velocity">1500dp</dimen>
<!-- All Apps -->
<dimen name="all_apps_starting_vertical_translate">300dp</dimen>
<dimen name="all_apps_search_bar_field_height">48dp</dimen>
@@ -229,7 +234,9 @@
<dimen name="drop_target_button_drawable_padding">8dp</dimen>
<dimen name="drop_target_button_drawable_horizontal_padding">16dp</dimen>
<dimen name="drop_target_button_drawable_vertical_padding">8dp</dimen>
<dimen name="drop_target_button_gap">22dp</dimen>
<dimen name="drop_target_button_gap">28dp</dimen>
<dimen name="drop_target_button_workspace_edge_gap">0dp</dimen>
<dimen name="drop_target_button_screen_edge_gap">28dp</dimen>
<!-- the distance an icon must be dragged before button drop targets accept it -->
<dimen name="drag_distanceThreshold">30dp</dimen>
+46 -40
View File
@@ -24,6 +24,7 @@ import android.content.Context;
import android.content.res.Resources;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.text.InputType;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.LayoutInflater;
@@ -49,6 +50,8 @@ public abstract class ButtonDropTarget extends TextView
private static final int[] sTempCords = new int[2];
private static final int DRAG_VIEW_DROP_DURATION = 285;
private static final float DRAG_VIEW_HOVER_OVER_OPACITY = 0.65f;
private static final int MAX_LINES_TEXT_MULTI_LINE = 2;
private static final int MAX_LINES_TEXT_SINGLE_LINE = 1;
public static final int TOOLTIP_DEFAULT = 0;
public static final int TOOLTIP_LEFT = 1;
@@ -72,6 +75,8 @@ public abstract class ButtonDropTarget extends TextView
protected CharSequence mText;
protected Drawable mDrawable;
private boolean mTextVisible = true;
private boolean mIconVisible = true;
private boolean mTextMultiLine = true;
private PopupWindow mToolTip;
private int mToolTipLocation;
@@ -109,8 +114,7 @@ public abstract class ButtonDropTarget extends TextView
// drawableLeft and drawableStart.
mDrawable = getContext().getDrawable(resId).mutate();
mDrawable.setTintList(getTextColors());
centerIcon();
setCompoundDrawablesRelative(mDrawable, null, null, null);
updateIconVisibility();
}
public void setDropTargetBar(DropTargetBar dropTargetBar) {
@@ -306,13 +310,49 @@ public abstract class ButtonDropTarget extends TextView
if (mTextVisible != isVisible || !TextUtils.equals(newText, getText())) {
mTextVisible = isVisible;
setText(newText);
centerIcon();
setCompoundDrawablesRelative(mDrawable, null, null, null);
int drawablePadding = mTextVisible ? mDrawablePadding : 0;
setCompoundDrawablePadding(drawablePadding);
updateIconVisibility();
}
}
/**
* Display button text over multiple lines when isMultiLine is true, single line otherwise.
*/
public void setTextMultiLine(boolean isMultiLine) {
if (mTextMultiLine != isMultiLine) {
mTextMultiLine = isMultiLine;
setSingleLine(!isMultiLine);
setMaxLines(isMultiLine ? MAX_LINES_TEXT_MULTI_LINE : MAX_LINES_TEXT_SINGLE_LINE);
int inputType = InputType.TYPE_CLASS_TEXT;
if (isMultiLine) {
inputType |= InputType.TYPE_TEXT_FLAG_MULTI_LINE;
}
setInputType(inputType);
}
}
protected boolean isTextMultiLine() {
return mTextMultiLine;
}
/**
* Sets the button icon visible when isVisible is true, hides it otherwise.
*/
public void setIconVisible(boolean isVisible) {
if (mIconVisible != isVisible) {
mIconVisible = isVisible;
updateIconVisibility();
}
}
private void updateIconVisibility() {
if (mIconVisible) {
centerIcon();
}
setCompoundDrawablesRelative(mIconVisible ? mDrawable : null, null, null, null);
setCompoundDrawablePadding(mIconVisible && mTextVisible ? mDrawablePadding : 0);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
@@ -324,40 +364,6 @@ public abstract class ButtonDropTarget extends TextView
hideTooltip();
}
/**
* Reduce the size of the text until it fits or reaches a minimum.
*
* The minimum size is defined by {@code R.dimen.button_drop_target_min_text_size} and
* it diminishes by intervals defined by
* {@code R.dimen.button_drop_target_resize_text_increment}
* This functionality is very similar to the option
* {@link TextView#setAutoSizeTextTypeWithDefaults(int)} but can't be used in this view because
* the layout width is {@code WRAP_CONTENT}.
*
* @param availableWidth Available width in the button to fit the text, used in
* {@code ButtonDropTarget#isTextTruncated(int)}
* @return The biggest text size in SP that makes the text fit or if the text can't fit returns
* the min available value
*/
public float resizeTextToFit(int availableWidth) {
float minSize = Utilities.pxToSp(getResources()
.getDimensionPixelSize(R.dimen.button_drop_target_min_text_size));
float step = Utilities.pxToSp(getResources()
.getDimensionPixelSize(R.dimen.button_drop_target_resize_text_increment));
float textSize = Utilities.pxToSp(getTextSize());
while (textSize > minSize) {
if (isTextTruncated(availableWidth)) {
textSize -= step;
setTextSize(textSize);
} else {
return textSize;
}
}
return minSize;
}
public boolean isTextTruncated(int availableWidth) {
availableWidth -= (getPaddingLeft() + getPaddingRight() + mDrawable.getIntrinsicWidth()
+ getCompoundDrawablePadding());
+19 -10
View File
@@ -108,6 +108,7 @@ public class DeviceProfile {
public float workspaceSpringLoadShrunkTop;
public float workspaceSpringLoadShrunkBottom;
public final int workspaceSpringLoadedBottomSpace;
public final int workspaceSpringLoadedMinNextPageVisiblePx;
private final int extraSpace;
public int workspaceTopPadding;
@@ -214,6 +215,8 @@ public class DeviceProfile {
public int dropTargetHorizontalPaddingPx;
public int dropTargetVerticalPaddingPx;
public int dropTargetGapPx;
public int dropTargetButtonWorkspaceEdgeGapPx;
public int dropTargetButtonScreenEdgeGapPx;
// Insets
private final Rect mInsets = new Rect();
@@ -343,9 +346,15 @@ public class DeviceProfile {
dropTargetVerticalPaddingPx = res.getDimensionPixelSize(
R.dimen.drop_target_button_drawable_vertical_padding);
dropTargetGapPx = res.getDimensionPixelSize(R.dimen.drop_target_button_gap);
dropTargetButtonWorkspaceEdgeGapPx = res.getDimensionPixelSize(
R.dimen.drop_target_button_workspace_edge_gap);
dropTargetButtonScreenEdgeGapPx = res.getDimensionPixelSize(
R.dimen.drop_target_button_screen_edge_gap);
workspaceSpringLoadedBottomSpace =
res.getDimensionPixelSize(R.dimen.dynamic_grid_min_spring_loaded_space);
workspaceSpringLoadedMinNextPageVisiblePx = res.getDimensionPixelSize(
R.dimen.dynamic_grid_spring_loaded_min_next_space_visible);
workspaceCellPaddingXPx = res.getDimensionPixelSize(R.dimen.dynamic_grid_cell_padding_x);
@@ -501,7 +510,7 @@ public class DeviceProfile {
*/
private int calculateQsbWidth() {
if (isQsbInline) {
int columns = isTwoPanels ? inv.numColumns * 2 : inv.numColumns;
int columns = getPanelCount() * inv.numColumns;
return getIconToIconWidthForColumns(columns)
- iconSizePx * numShownHotseatIcons
- hotseatBorderSpace * numShownHotseatIcons;
@@ -954,13 +963,6 @@ public class DeviceProfile {
return workspaceSpringLoadShrunkBottom;
}
/**
* Gets the minimum visible amount of the next workspace page when in the spring-loaded state.
*/
private float getWorkspaceSpringLoadedMinimumNextPageVisible() {
return getCellSize().x / 2f;
}
/**
* Gets the scale of the workspace for the spring-loaded edit state.
*/
@@ -972,8 +974,7 @@ public class DeviceProfile {
// Reduce scale if next pages would not be visible after scaling the workspace
int workspaceWidth = availableWidthPx;
float scaledWorkspaceWidth = workspaceWidth * scale;
float maxAvailableWidth =
workspaceWidth - (2 * getWorkspaceSpringLoadedMinimumNextPageVisible());
float maxAvailableWidth = workspaceWidth - (2 * workspaceSpringLoadedMinNextPageVisiblePx);
if (scaledWorkspaceWidth > maxAvailableWidth) {
scale *= maxAvailableWidth / scaledWorkspaceWidth;
}
@@ -1412,11 +1413,19 @@ public class DeviceProfile {
writer.println(prefix + pxToDpStr("dropTargetBarSizePx", dropTargetBarSizePx));
writer.println(
prefix + pxToDpStr("dropTargetBarBottomMarginPx", dropTargetBarBottomMarginPx));
writer.println(prefix + pxToDpStr("dropTargetButtonWorkspaceEdgeGapPx",
dropTargetButtonWorkspaceEdgeGapPx));
writer.println(prefix + pxToDpStr("dropTargetButtonScreenEdgeGapPx",
dropTargetButtonScreenEdgeGapPx));
writer.println(
prefix + pxToDpStr("workspaceSpringLoadShrunkTop", workspaceSpringLoadShrunkTop));
writer.println(prefix + pxToDpStr("workspaceSpringLoadShrunkBottom",
workspaceSpringLoadShrunkBottom));
writer.println(prefix + pxToDpStr("workspaceSpringLoadedBottomSpace",
workspaceSpringLoadedBottomSpace));
writer.println(prefix + pxToDpStr("workspaceSpringLoadedMinNextPageVisiblePx",
workspaceSpringLoadedMinNextPageVisiblePx));
writer.println(
prefix + pxToDpStr("getWorkspaceSpringLoadScale()", getWorkspaceSpringLoadScale()));
}
+132 -95
View File
@@ -39,8 +39,6 @@ import com.android.launcher3.dragndrop.DragController.DragListener;
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.testing.TestProtocol;
import java.util.Arrays;
/*
* The top bar containing various drop targets: Delete/App Info/Uninstall.
*/
@@ -53,6 +51,8 @@ public class DropTargetBar extends FrameLayout
private final Runnable mFadeAnimationEndRunnable =
() -> updateVisibility(DropTargetBar.this);
private final Launcher mLauncher;
@ViewDebug.ExportedProperty(category = "launcher")
protected boolean mDeferOnDragEnd;
@@ -60,16 +60,19 @@ public class DropTargetBar extends FrameLayout
protected boolean mVisible = false;
private ButtonDropTarget[] mDropTargets;
private ButtonDropTarget[] mTempTargets;
private ViewPropertyAnimator mCurrentAnimation;
private boolean mIsVertical = true;
public DropTargetBar(Context context, AttributeSet attrs) {
super(context, attrs);
mLauncher = Launcher.getLauncher(context);
}
public DropTargetBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mLauncher = Launcher.getLauncher(context);
}
@Override
@@ -80,12 +83,13 @@ public class DropTargetBar extends FrameLayout
mDropTargets[i] = (ButtonDropTarget) getChildAt(i);
mDropTargets[i].setDropTargetBar(this);
}
mTempTargets = new ButtonDropTarget[getChildCount()];
}
@Override
public void setInsets(Rect insets) {
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
DeviceProfile grid = Launcher.getLauncher(getContext()).getDeviceProfile();
DeviceProfile grid = mLauncher.getDeviceProfile();
mIsVertical = grid.isVerticalBarLayout();
lp.leftMargin = insets.left;
@@ -116,10 +120,15 @@ public class DropTargetBar extends FrameLayout
lp.height = grid.dropTargetBarSizePx;
lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP;
DeviceProfile dp = mLauncher.getDeviceProfile();
int horizontalPadding = dp.dropTargetHorizontalPaddingPx;
int verticalPadding = dp.dropTargetVerticalPaddingPx;
setLayoutParams(lp);
for (ButtonDropTarget button : mDropTargets) {
button.setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.dropTargetTextSizePx);
button.setToolTipLocation(tooltipLocation);
button.setPadding(horizontalPadding, verticalPadding, horizontalPadding,
verticalPadding);
}
}
@@ -135,36 +144,83 @@ public class DropTargetBar extends FrameLayout
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
int heightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
int visibleCount = getVisibleButtonsCount();
if (visibleCount > 0) {
int availableWidth = width / visibleCount;
boolean textVisible = true;
boolean textResized = false;
float textSize = mDropTargets[0].getTextSize();
for (ButtonDropTarget button : mDropTargets) {
if (button.getVisibility() == GONE) {
continue;
}
if (button.isTextTruncated(availableWidth)) {
textSize = Math.min(textSize, button.resizeTextToFit(availableWidth));
textResized = true;
}
textVisible = textVisible && !button.isTextTruncated(availableWidth);
}
int visibleCount = getVisibleButtons(mTempTargets);
if (visibleCount == 1) {
int widthSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST);
if (textResized) {
for (ButtonDropTarget button : mDropTargets) {
button.setTextSize(textSize);
}
}
ButtonDropTarget firstButton = mTempTargets[0];
firstButton.setTextVisible(true);
firstButton.setIconVisible(true);
firstButton.measure(widthSpec, heightSpec);
} else if (visibleCount == 2) {
DeviceProfile dp = mLauncher.getDeviceProfile();
int verticalPadding = dp.dropTargetVerticalPaddingPx;
int horizontalPadding = dp.dropTargetHorizontalPaddingPx;
int widthSpec = MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST);
int heightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
for (ButtonDropTarget button : mDropTargets) {
if (button.getVisibility() != GONE) {
button.setTextVisible(textVisible);
button.measure(widthSpec, heightSpec);
ButtonDropTarget firstButton = mTempTargets[0];
firstButton.setTextVisible(true);
firstButton.setIconVisible(true);
ButtonDropTarget secondButton = mTempTargets[1];
secondButton.setTextVisible(true);
secondButton.setIconVisible(true);
secondButton.setTextMultiLine(false);
// Reset second button padding in case it was previously changed to multi-line text.
secondButton.setPadding(horizontalPadding, verticalPadding, horizontalPadding,
verticalPadding);
if (dp.isTwoPanels) {
// Both buttons for two panel fit to the width of one Cell Layout (less
// half of the center gap between the buttons).
float scale = dp.getWorkspaceSpringLoadScale();
int scaledPanelWidth = (int) (dp.getCellLayoutWidth() * scale);
int halfButtonGap = dp.dropTargetGapPx / 2;
scaledPanelWidth -= halfButtonGap / 2;
int widthSpec = MeasureSpec.makeMeasureSpec(scaledPanelWidth, MeasureSpec.AT_MOST);
firstButton.measure(widthSpec, heightSpec);
secondButton.measure(widthSpec, heightSpec);
} else {
int availableWidth;
int buttonGap = dp.dropTargetGapPx;
if (mIsVertical) {
// Both buttons plus the button gap do not display past the edge of the
// scaled workspace, less a pre-defined gap from the edge of the workspace.
float scale = dp.getWorkspaceSpringLoadScale();
int panelWidth = (int) (dp.getCellLayoutWidth() * scale);
availableWidth = Math.min(
panelWidth - (2 * dp.dropTargetButtonWorkspaceEdgeGapPx), width);
} else {
// Both buttons plus the button gap display up to a pre-defined margin of
// the unscaled workspace edge.
availableWidth = Math.min(
dp.availableWidthPx - (2 * dp.dropTargetButtonScreenEdgeGapPx),
width);
}
int widthSpec = MeasureSpec.makeMeasureSpec(availableWidth - buttonGap,
MeasureSpec.AT_MOST);
// First button's width is at most the drop target bar's total width less the button
// gap.
firstButton.measure(widthSpec, heightSpec);
int usedWidth = firstButton.getMeasuredWidth() + buttonGap;
int remainingWidth = availableWidth - usedWidth;
widthSpec = MeasureSpec.makeMeasureSpec(remainingWidth, MeasureSpec.AT_MOST);
secondButton.measure(widthSpec, heightSpec);
// Remove both icons and put the second button's text on two lines if text is
// truncated on phones. We assume first button's text is never truncated, so it
// remains single-line.
if (secondButton.isTextTruncated(remainingWidth) && !mIsVertical) {
firstButton.setIconVisible(false);
secondButton.setIconVisible(false);
secondButton.setTextMultiLine(true);
secondButton.setPadding(secondButton.getPaddingLeft(),
secondButton.getPaddingTop() / 2, secondButton.getPaddingRight(),
secondButton.getPaddingBottom() / 2);
}
}
}
@@ -173,98 +229,79 @@ public class DropTargetBar extends FrameLayout
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
int visibleCount = getVisibleButtonsCount();
int visibleCount = getVisibleButtons(mTempTargets);
if (visibleCount == 0) {
return;
}
Launcher launcher = Launcher.getLauncher(getContext());
Workspace<?> workspace = launcher.getWorkspace();
DeviceProfile dp = launcher.getDeviceProfile();
int buttonHorizontalPadding = dp.dropTargetHorizontalPaddingPx;
int buttonVerticalPadding = dp.dropTargetVerticalPaddingPx;
DeviceProfile dp = mLauncher.getDeviceProfile();
int barCenter = (right - left) / 2;
ButtonDropTarget[] visibleButtons = Arrays.stream(mDropTargets)
.filter(b -> b.getVisibility() != GONE)
.toArray(ButtonDropTarget[]::new);
Arrays.stream(visibleButtons).forEach(
b -> b.setPadding(buttonHorizontalPadding, buttonVerticalPadding,
buttonHorizontalPadding, buttonVerticalPadding));
if (mIsVertical) {
// Center vertical bar over scaled workspace, accounting for hotseat offset.
float scale = dp.getWorkspaceSpringLoadScale();
Workspace<?> ws = mLauncher.getWorkspace();
int workspaceCenter = (ws.getLeft() + ws.getRight()) / 2;
int cellLayoutCenter = ((dp.getInsets().left + dp.workspacePadding.left) + (dp.widthPx
- dp.getInsets().right - dp.workspacePadding.right)) / 2;
int cellLayoutCenterOffset = (int) ((cellLayoutCenter - workspaceCenter) * scale);
barCenter = workspaceCenter + cellLayoutCenterOffset;
}
if (visibleCount == 1) {
ButtonDropTarget button = visibleButtons[0];
ButtonDropTarget button = mTempTargets[0];
button.layout(barCenter - (button.getMeasuredWidth() / 2), 0,
barCenter + (button.getMeasuredWidth() / 2), button.getMeasuredHeight());
} else if (visibleCount == 2) {
int buttonGap = dp.dropTargetGapPx;
if (dp.isTwoPanels) {
ButtonDropTarget leftButton = visibleButtons[0];
ButtonDropTarget leftButton = mTempTargets[0];
leftButton.layout(barCenter - leftButton.getMeasuredWidth() - (buttonGap / 2), 0,
barCenter - (buttonGap / 2), leftButton.getMeasuredHeight());
ButtonDropTarget rightButton = visibleButtons[1];
ButtonDropTarget rightButton = mTempTargets[1];
rightButton.layout(barCenter + (buttonGap / 2), 0,
barCenter + rightButton.getMeasuredWidth() + (buttonGap / 2),
barCenter + (buttonGap / 2) + rightButton.getMeasuredWidth(),
rightButton.getMeasuredHeight());
} else if (dp.isTablet) {
int numberOfMargins = visibleCount - 1;
int buttonWidths = Arrays.stream(mDropTargets)
.filter(b -> b.getVisibility() != GONE)
.mapToInt(ButtonDropTarget::getMeasuredWidth)
.sum();
int totalWidth = buttonWidths + (numberOfMargins * buttonGap);
int buttonsStartMargin = barCenter - (totalWidth / 2);
int start = buttonsStartMargin;
for (ButtonDropTarget button : visibleButtons) {
int margin = (start != buttonsStartMargin) ? buttonGap : 0;
button.layout(start + margin, 0, start + margin + button.getMeasuredWidth(),
button.getMeasuredHeight());
start += button.getMeasuredWidth() + margin;
}
} else if (mIsVertical) {
// Center buttons over workspace, not screen.
int verticalCenter = (workspace.getRight() - workspace.getLeft()) / 2;
ButtonDropTarget leftButton = visibleButtons[0];
leftButton.layout(verticalCenter - leftButton.getMeasuredWidth() - (buttonGap / 2),
0, verticalCenter - (buttonGap / 2), leftButton.getMeasuredHeight());
ButtonDropTarget rightButton = visibleButtons[1];
rightButton.layout(verticalCenter + (buttonGap / 2), 0,
verticalCenter + rightButton.getMeasuredWidth() + (buttonGap / 2),
rightButton.getMeasuredHeight());
} else if (dp.isPhone) {
// Buttons aligned to outer edges of scaled workspace.
float scale = dp.getWorkspaceSpringLoadScale();
int workspaceWidth = (int) (launcher.getWorkspace().getNormalChildWidth() * scale);
int start = barCenter - (workspaceWidth / 2);
int end = barCenter + (workspaceWidth / 2);
ButtonDropTarget leftButton = visibleButtons[0];
ButtonDropTarget rightButton = visibleButtons[1];
// If the text within the buttons is too long, the buttons can overlap
int overlap = start + leftButton.getMeasuredWidth() + rightButton.getMeasuredWidth()
- end;
if (overlap > 0) {
end += overlap;
} else {
int start;
int end;
if (mIsVertical) {
// Scaled CellLayout width is assumed to not exceed the bounds of left/right.
float scale = dp.getWorkspaceSpringLoadScale();
int panelWidth = (int) (dp.getCellLayoutWidth() * scale);
start = barCenter - (panelWidth / 2) + dp.dropTargetButtonWorkspaceEdgeGapPx;
end = barCenter + (panelWidth / 2) - dp.dropTargetButtonWorkspaceEdgeGapPx;
} else {
start = Math.max(dp.dropTargetButtonScreenEdgeGapPx, left);
end = Math.min(dp.availableWidthPx - dp.dropTargetButtonScreenEdgeGapPx, right);
}
leftButton.layout(start, 0, start + leftButton.getMeasuredWidth(),
ButtonDropTarget leftButton = mTempTargets[0];
ButtonDropTarget rightButton = mTempTargets[1];
int leftButtonWidth = leftButton.getMeasuredWidth();
int rightButtonWidth = rightButton.getMeasuredWidth();
int buttonPlusGapWidth = leftButtonWidth + buttonGap + rightButtonWidth;
int extraSpace = end - start - buttonPlusGapWidth;
start = (start - left) + (extraSpace / 2);
leftButton.layout(start, 0, start + leftButtonWidth,
leftButton.getMeasuredHeight());
rightButton.layout(end - rightButton.getMeasuredWidth(), 0, end,
int rightButtonStart = start + leftButtonWidth + buttonGap;
rightButton.layout(rightButtonStart, 0, rightButtonStart + rightButtonWidth,
rightButton.getMeasuredHeight());
}
}
}
private int getVisibleButtonsCount() {
private int getVisibleButtons(ButtonDropTarget[] outVisibleButtons) {
int visibleCount = 0;
for (ButtonDropTarget buttons : mDropTargets) {
if (buttons.getVisibility() != GONE) {
for (ButtonDropTarget button : mDropTargets) {
if (button.getVisibility() != GONE) {
outVisibleButtons[visibleCount] = button;
visibleCount++;
}
}
+28 -22
View File
@@ -28,6 +28,8 @@ import static com.android.launcher3.touch.PagedOrientationHandler.VIEW_SCROLL_TO
import android.animation.LayoutTransition;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
@@ -78,27 +80,19 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
public static final int INVALID_PAGE = -1;
protected static final ComputePageScrollsLogic SIMPLE_SCROLL_LOGIC = (v) -> v.getVisibility() != GONE;
public static final int PAGE_SNAP_ANIMATION_DURATION = 750;
private static final float RETURN_TO_ORIGINAL_PAGE_THRESHOLD = 0.33f;
// The page is moved more than halfway, automatically move to the next page on touch up.
private static final float SIGNIFICANT_MOVE_THRESHOLD = 0.4f;
private static final float MAX_SCROLL_PROGRESS = 1.0f;
// The following constants need to be scaled based on density. The scaled versions will be
// assigned to the corresponding member variables below.
private static final int FLING_THRESHOLD_VELOCITY = 500;
private static final int EASY_FLING_THRESHOLD_VELOCITY = 400;
private static final int MIN_SNAP_VELOCITY = 1500;
private static final int MIN_FLING_VELOCITY = 250;
private boolean mFreeScroll = false;
protected final int mFlingThresholdVelocity;
protected final int mEasyFlingThresholdVelocity;
protected final int mMinFlingVelocity;
protected final int mMinSnapVelocity;
private int mFlingThresholdVelocity;
private int mEasyFlingThresholdVelocity;
private int mMinFlingVelocity;
private int mMinSnapVelocity;
private int mPageSnapAnimationDuration;
protected boolean mFirstLayout = true;
@@ -192,11 +186,7 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
mPageSlop = configuration.getScaledPagingTouchSlop();
mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
float density = getResources().getDisplayMetrics().density;
mFlingThresholdVelocity = (int) (FLING_THRESHOLD_VELOCITY * density);
mEasyFlingThresholdVelocity = (int) (EASY_FLING_THRESHOLD_VELOCITY * density);
mMinFlingVelocity = (int) (MIN_FLING_VELOCITY * density);
mMinSnapVelocity = (int) (MIN_SNAP_VELOCITY * density);
updateVelocityValues();
initEdgeEffect();
setDefaultFocusHighlightEnabled(false);
@@ -628,6 +618,22 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
- mInsets.left - mInsets.right;
}
private void updateVelocityValues() {
Resources res = getResources();
mFlingThresholdVelocity = res.getDimensionPixelSize(R.dimen.fling_threshold_velocity);
mEasyFlingThresholdVelocity =
res.getDimensionPixelSize(R.dimen.easy_fling_threshold_velocity);
mMinFlingVelocity = res.getDimensionPixelSize(R.dimen.min_fling_velocity);
mMinSnapVelocity = res.getDimensionPixelSize(R.dimen.min_page_snap_velocity);
mPageSnapAnimationDuration = res.getInteger(R.integer.config_pageSnapAnimationDuration);
}
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
updateVelocityValues();
}
@Override
public void requestLayout() {
mIsLayoutValid = false;
@@ -1616,7 +1622,7 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
}
protected void snapToDestination() {
snapToPage(getDestinationPage(), PAGE_SNAP_ANIMATION_DURATION);
snapToPage(getDestinationPage(), mPageSnapAnimationDuration);
}
// We want the duration of the page snap animation to be influenced by the distance that
@@ -1640,7 +1646,7 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
if (Math.abs(velocity) < mMinFlingVelocity) {
// If the velocity is low enough, then treat this more as an automatic page advance
// as opposed to an apparent physical response to flinging
return snapToPage(whichPage, PAGE_SNAP_ANIMATION_DURATION);
return snapToPage(whichPage, mPageSnapAnimationDuration);
}
// Here we compute a "distance" that will be used in the computation of the overall
@@ -1663,11 +1669,11 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
}
public boolean snapToPage(int whichPage) {
return snapToPage(whichPage, PAGE_SNAP_ANIMATION_DURATION);
return snapToPage(whichPage, mPageSnapAnimationDuration);
}
public boolean snapToPageImmediately(int whichPage) {
return snapToPage(whichPage, PAGE_SNAP_ANIMATION_DURATION, true);
return snapToPage(whichPage, mPageSnapAnimationDuration, true);
}
public boolean snapToPage(int whichPage, int duration) {
@@ -326,7 +326,7 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte
}
protected boolean isPersonalTab() {
return mViewPager.getNextPage() == 0;
return mViewPager == null || mViewPager.getNextPage() == 0;
}
/**
@@ -388,34 +388,34 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte
mInsets.set(insets);
DeviceProfile grid = mActivityContext.getDeviceProfile();
for (int i = 0; i < mAH.size(); i++) {
mAH.get(i).mPadding.bottom = insets.bottom;
mAH.get(i).mPadding.left = mAH.get(i).mPadding.right = grid.allAppsLeftRightPadding;
mAH.get(i).applyPadding();
}
applyAdapterPaddings(grid);
MarginLayoutParams mlp = (MarginLayoutParams) getLayoutParams();
int leftRightMargin = grid.allAppsLeftRightMargin;
mlp.leftMargin = insets.left + leftRightMargin;
mlp.rightMargin = insets.right + leftRightMargin;
mlp.leftMargin = insets.left;
mlp.rightMargin = insets.right;
setLayoutParams(mlp);
if (grid.isVerticalBarLayout()) {
setPadding(grid.workspacePadding.left, 0, grid.workspacePadding.right, 0);
} else {
setPadding(0, grid.allAppsTopPadding, 0, 0);
setPadding(grid.allAppsLeftRightMargin, grid.allAppsTopPadding,
grid.allAppsLeftRightMargin, 0);
}
InsettableFrameLayout.dispatchInsets(this, insets);
}
/**
* Returns a padding in case a scrim is shown on the bottom of the view and a padding is needed.
*/
protected int getNavBarScrimHeight(WindowInsets insets) {
return 0;
}
@Override
public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) {
if (Utilities.ATLEAST_Q) {
mNavBarScrimHeight = insets.getTappableElementInsets().bottom;
} else {
mNavBarScrimHeight = insets.getStableInsetBottom();
}
mNavBarScrimHeight = getNavBarScrimHeight(insets);
applyAdapterPaddings(mActivityContext.getDeviceProfile());
return super.dispatchApplyWindowInsets(insets);
}
@@ -483,6 +483,15 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte
mAllAppsStore.registerIconContainer(mAH.get(AdapterHolder.WORK).mRecyclerView);
}
private void applyAdapterPaddings(DeviceProfile grid) {
int bottomPadding = Math.max(mInsets.bottom, mNavBarScrimHeight);
for (int i = 0; i < mAH.size(); i++) {
mAH.get(i).mPadding.bottom = bottomPadding;
mAH.get(i).mPadding.left = mAH.get(i).mPadding.right = grid.allAppsLeftRightPadding;
mAH.get(i).applyPadding();
}
}
private void setDeviceManagementResources() {
if (mActivityContext.getStringCache() != null) {
Button personalTab = findViewById(R.id.tab_personal);
@@ -18,9 +18,11 @@ package com.android.launcher3.allapps;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.WindowInsets;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.Utilities;
/**
* AllAppsContainerView with launcher specific callbacks
@@ -58,4 +60,13 @@ public class LauncherAllAppsContainerView extends ActivityAllAppsContainerView<L
}
return super.onTouchEvent(ev);
}
@Override
protected int getNavBarScrimHeight(WindowInsets insets) {
if (Utilities.ATLEAST_Q) {
return insets.getTappableElementInsets().bottom;
} else {
return insets.getStableInsetBottom();
}
}
}
@@ -246,6 +246,10 @@ public final class FeatureFlags {
"ENABLE_ALL_APPS_IN_TASKBAR", true,
"Enables accessing All Apps from the system Taskbar.");
public static final BooleanFlag ENABLE_ALL_APPS_BUTTON_IN_HOTSEAT = getDebugFlag(
"ENABLE_ALL_APPS_BUTTON_IN_HOTSEAT", false,
"Enables displaying the all apps button in the hotseat.");
public static final BooleanFlag ENABLE_ALL_APPS_ONE_SEARCH_IN_TASKBAR = getDebugFlag(
"ENABLE_ALL_APPS_ONE_SEARCH_IN_TASKBAR", false,
"Enables One Search box in Taskbar All Apps.");
+4 -3
View File
@@ -72,7 +72,6 @@ import com.android.launcher3.ExtendedEditText;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.OnAlarmListener;
import com.android.launcher3.PagedView;
import com.android.launcher3.R;
import com.android.launcher3.ShortcutAndWidgetContainer;
import com.android.launcher3.Utilities;
@@ -145,7 +144,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
* Time for which the scroll hint is shown before automatically changing page.
*/
public static final int SCROLL_HINT_DURATION = 500;
public static final int RESCROLL_DELAY = PagedView.PAGE_SNAP_ANIMATION_DURATION + 150;
private static final int RESCROLL_EXTRA_DELAY = 150;
public static final int SCROLL_NONE = -1;
public static final int SCROLL_LEFT = 0;
@@ -1523,7 +1522,9 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
// Pause drag event until the scrolling is finished
mScrollPauseAlarm.setOnAlarmListener(new OnScrollFinishedListener(mDragObject));
mScrollPauseAlarm.setAlarm(RESCROLL_DELAY);
int rescrollDelay = getResources().getInteger(
R.integer.config_pageSnapAnimationDuration) + RESCROLL_EXTRA_DELAY;
mScrollPauseAlarm.setAlarm(rescrollDelay);
}
}
@@ -43,6 +43,7 @@ import com.android.launcher3.util.RunnableList;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.Executor;
/**
@@ -203,7 +204,9 @@ public abstract class BaseLoaderResults {
}
private void bind() {
IntSet currentScreenIds = mCallbacks.getPagesToBindSynchronously(mOrderedScreenIds);
final IntSet currentScreenIds =
mCallbacks.getPagesToBindSynchronously(mOrderedScreenIds);
Objects.requireNonNull(currentScreenIds, "Null screen ids provided by " + mCallbacks);
// Separate the items that are on the current screen, and all the other remaining items
ArrayList<ItemInfo> currentWorkspaceItems = new ArrayList<>();
@@ -31,6 +31,7 @@ import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.launcher3.LauncherSettings;
@@ -469,6 +470,7 @@ public class BgDataModel {
* or an empty IntSet
* @param orderedScreenIds All the page ids to be bound
*/
@NonNull
default IntSet getPagesToBindSynchronously(IntArray orderedScreenIds) {
return new IntSet();
}
@@ -51,7 +51,7 @@ public class ModelUtils {
* specified screen.
*/
public static <T extends ItemInfo> void filterCurrentWorkspaceItems(
IntSet currentScreenIds,
final IntSet currentScreenIds,
ArrayList<T> allWorkspaceItems,
ArrayList<T> currentScreenItems,
ArrayList<T> otherScreenItems) {
@@ -120,23 +120,20 @@ public class SecondaryDragLayer extends BaseDragLayer<SecondaryDisplayLauncher>
int maxWidth =
grid.allAppsCellWidthPx * grid.numShownAllAppsColumns + horizontalPadding;
int appsWidth = Math.min(width, maxWidth);
int appsWidth = Math.min(width - getPaddingLeft() - getPaddingRight(), maxWidth);
int maxHeight =
grid.allAppsCellHeightPx * grid.numShownAllAppsColumns + verticalPadding;
int appsHeight = Math.min(height, maxHeight);
int appsHeight = Math.min(height - getPaddingTop() - getPaddingBottom(), maxHeight);
mAppsView.measure(
makeMeasureSpec(appsWidth, EXACTLY), makeMeasureSpec(appsHeight, EXACTLY));
} else if (child == mAllAppsButton) {
int appsButtonSpec = makeMeasureSpec(grid.iconSizePx, EXACTLY);
mAllAppsButton.measure(appsButtonSpec, appsButtonSpec);
} else if (child == mWorkspace) {
measureChildWithMargins(mWorkspace, widthMeasureSpec, 0, heightMeasureSpec,
grid.iconSizePx + grid.edgeMarginPx);
} else {
measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
}
@@ -109,7 +109,7 @@ public class RotationHelper implements OnSharedPreferenceChangeListener,
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) {
if (mDestroyed) return;
if (mDestroyed || mIgnoreAutoRotateSettings) return;
boolean wasRotationEnabled = mHomeRotationEnabled;
mHomeRotationEnabled = mSharedPrefs.getBoolean(ALLOW_ROTATION_PREFERENCE_KEY,
getAllowRotationDefaultValue(mActivity.getDeviceProfile()));
@@ -18,7 +18,6 @@ package com.android.launcher3.widget;
import static com.android.launcher3.Utilities.ATLEAST_R;
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
import static com.android.launcher3.widget.BaseWidgetSheet.MAX_WIDTH_SCALE_FOR_LARGER_SCREEN;
import android.animation.PropertyValuesHolder;
import android.annotation.SuppressLint;
@@ -106,7 +105,10 @@ public class AddItemWidgetsBottomSheet extends AbstractSlideInView<AddItemActivi
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
DeviceProfile deviceProfile = mActivityContext.getDeviceProfile();
int widthUsed;
if (mInsets.bottom > 0) {
if (deviceProfile.isTablet) {
int margin = deviceProfile.allAppsLeftRightMargin;
widthUsed = Math.max(2 * margin, 2 * (mInsets.left + mInsets.right));
} else if (mInsets.bottom > 0) {
widthUsed = mInsets.left + mInsets.right;
} else {
Rect padding = deviceProfile.workspacePadding;
@@ -114,18 +116,8 @@ public class AddItemWidgetsBottomSheet extends AbstractSlideInView<AddItemActivi
2 * (mInsets.left + mInsets.right));
}
if (deviceProfile.isTablet || deviceProfile.isTwoPanels) {
// In large screen devices, we restrict the width of the widgets picker to show part of
// the home screen. Let's ensure the minimum width used is at least the minimum width
// that isn't taken by the widgets picker.
int minUsedWidth = (int) (deviceProfile.availableWidthPx
* (1 - MAX_WIDTH_SCALE_FOR_LARGER_SCREEN));
widthUsed = Math.max(widthUsed, minUsedWidth);
}
int heightUsed = mInsets.top + deviceProfile.edgeMarginPx;
measureChildWithMargins(mContent, widthMeasureSpec,
widthUsed, heightMeasureSpec, heightUsed);
widthUsed, heightMeasureSpec, deviceProfile.bottomSheetTopPadding);
setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec),
MeasureSpec.getSize(heightMeasureSpec));
}
@@ -16,6 +16,8 @@
package com.android.launcher3.widget;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect;
import android.util.AttributeSet;
@@ -23,6 +25,7 @@ import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.view.WindowInsets;
import android.widget.Toast;
import androidx.annotation.GuardedBy;
@@ -43,6 +46,7 @@ import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.touch.ItemLongClickListener;
import com.android.launcher3.util.SystemUiController;
import com.android.launcher3.util.Themes;
import com.android.launcher3.util.window.WindowManagerProxy;
import com.android.launcher3.views.AbstractSlideInView;
import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.views.ArrowTipView;
@@ -55,11 +59,6 @@ public abstract class BaseWidgetSheet extends AbstractSlideInView<Launcher>
PopupDataProvider.PopupDataChangeListener, Insettable {
/** The default number of cells that can fit horizontally in a widget sheet. */
protected static final int DEFAULT_MAX_HORIZONTAL_SPANS = 4;
/**
* The maximum scale, [0, 1], of the device screen width that the widgets picker can consume
* on large screen devices.
*/
protected static final float MAX_WIDTH_SCALE_FOR_LARGER_SCREEN = 0.89f;
protected static final String KEY_WIDGETS_EDUCATION_TIP_SEEN =
"launcher.widgets_education_tip_seen";
@@ -70,10 +69,15 @@ public abstract class BaseWidgetSheet extends AbstractSlideInView<Launcher>
private int mContentHorizontalMarginInPx;
protected int mNavBarScrimHeight;
private final Paint mNavBarScrimPaint;
public BaseWidgetSheet(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mContentHorizontalMarginInPx = getResources().getDimensionPixelSize(
R.dimen.widget_list_horizontal_margin);
mNavBarScrimPaint = new Paint();
mNavBarScrimPaint.setColor(Themes.getAttrColor(context, R.attr.allAppsNavBarScrimColor));
}
protected int getScrimColor(Context context) {
@@ -83,6 +87,9 @@ public abstract class BaseWidgetSheet extends AbstractSlideInView<Launcher>
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
WindowInsets windowInsets = WindowManagerProxy.INSTANCE.get(getContext())
.normalizeWindowInsets(getContext(), getRootWindowInsets(), new Rect());
mNavBarScrimHeight = getNavBarScrimHeight(windowInsets);
mActivityContext.getPopupDataProvider().setChangeListener(this);
}
@@ -136,6 +143,30 @@ public abstract class BaseWidgetSheet extends AbstractSlideInView<Launcher>
}
}
private int getNavBarScrimHeight(WindowInsets insets) {
if (Utilities.ATLEAST_Q) {
return insets.getTappableElementInsets().bottom;
} else {
return insets.getStableInsetBottom();
}
}
@Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
mNavBarScrimHeight = getNavBarScrimHeight(insets);
return super.onApplyWindowInsets(insets);
}
@Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
if (mNavBarScrimHeight > 0) {
canvas.drawRect(0, getHeight() - mNavBarScrimHeight, getWidth(), getHeight(),
mNavBarScrimPaint);
}
}
/** Called when the horizontal margin of the content view has changed. */
protected abstract void onContentHorizontalMarginChanged(int contentHorizontalMarginInPx);
@@ -147,7 +178,10 @@ public abstract class BaseWidgetSheet extends AbstractSlideInView<Launcher>
protected void doMeasure(int widthMeasureSpec, int heightMeasureSpec) {
DeviceProfile deviceProfile = mActivityContext.getDeviceProfile();
int widthUsed;
if (mInsets.bottom > 0) {
if (deviceProfile.isTablet) {
int margin = deviceProfile.allAppsLeftRightMargin;
widthUsed = Math.max(2 * margin, 2 * (mInsets.left + mInsets.right));
} else if (mInsets.bottom > 0) {
widthUsed = mInsets.left + mInsets.right;
} else {
Rect padding = deviceProfile.workspacePadding;
@@ -155,15 +189,6 @@ public abstract class BaseWidgetSheet extends AbstractSlideInView<Launcher>
2 * (mInsets.left + mInsets.right));
}
if (deviceProfile.isTablet || deviceProfile.isTwoPanels) {
// In large screen devices, we restrict the width of the widgets picker to show part of
// the home screen. Let's ensure the minimum width used is at least the minimum width
// that isn't taken by the widgets picker.
int minUsedWidth = (int) (deviceProfile.availableWidthPx
* (1 - MAX_WIDTH_SCALE_FOR_LARGER_SCREEN));
widthUsed = Math.max(widthUsed, minUsedWidth);
}
measureChildWithMargins(mContent, widthMeasureSpec,
widthUsed, heightMeasureSpec, deviceProfile.bottomSheetTopPadding);
setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec),
@@ -247,10 +247,12 @@ public class WidgetsBottomSheet extends BaseWidgetSheet {
@Override
public void setInsets(Rect insets) {
super.setInsets(insets);
int bottomPadding = Math.max(insets.bottom, mNavBarScrimHeight);
mContent.setPadding(mContent.getPaddingStart(),
mContent.getPaddingTop(), mContent.getPaddingEnd(), insets.bottom);
if (insets.bottom > 0) {
mContent.getPaddingTop(), mContent.getPaddingEnd(),
bottomPadding);
if (bottomPadding > 0) {
setupNavBarColor();
} else {
clearNavBarColor();
@@ -328,15 +328,15 @@ public class WidgetsFullSheet extends BaseWidgetSheet
@Override
public void setInsets(Rect insets) {
super.setInsets(insets);
setBottomPadding(mAdapters.get(AdapterHolder.PRIMARY).mWidgetsRecyclerView, insets.bottom);
setBottomPadding(mAdapters.get(AdapterHolder.SEARCH).mWidgetsRecyclerView, insets.bottom);
int bottomPadding = Math.max(insets.bottom, mNavBarScrimHeight);
setBottomPadding(mAdapters.get(AdapterHolder.PRIMARY).mWidgetsRecyclerView, bottomPadding);
setBottomPadding(mAdapters.get(AdapterHolder.SEARCH).mWidgetsRecyclerView, bottomPadding);
if (mHasWorkProfile) {
setBottomPadding(mAdapters.get(AdapterHolder.WORK).mWidgetsRecyclerView, insets.bottom);
setBottomPadding(mAdapters.get(AdapterHolder.WORK).mWidgetsRecyclerView, bottomPadding);
}
((MarginLayoutParams) mNoWidgetsView.getLayoutParams()).bottomMargin = insets.bottom;
((MarginLayoutParams) mNoWidgetsView.getLayoutParams()).bottomMargin = bottomPadding;
if (insets.bottom > 0) {
if (bottomPadding > 0) {
setupNavBarColor();
} else {
clearNavBarColor();
@@ -48,11 +48,13 @@ import com.android.launcher3.tapl.HomeAppIconMenuItem;
import com.android.launcher3.tapl.Widgets;
import com.android.launcher3.tapl.Workspace;
import com.android.launcher3.util.TestUtil;
import com.android.launcher3.util.rule.ScreenRecordRule;
import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
import com.android.launcher3.widget.picker.WidgetsFullSheet;
import com.android.launcher3.widget.picker.WidgetsRecyclerView;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -66,6 +68,10 @@ public class TaplTestsLauncher3 extends AbstractLauncherUiTest {
private static final String DUMMY_APP_NAME = "Aardwolf";
private static final String MAPS_APP_NAME = "Maps";
private static final String STORE_APP_NAME = "Play Store";
private static final String GMAIL_APP_NAME = "Gmail";
@Rule
public ScreenRecordRule mScreenRecordRule = new ScreenRecordRule();
@Before
public void setUp() throws Exception {
@@ -374,28 +380,23 @@ public class TaplTestsLauncher3 extends AbstractLauncherUiTest {
@Test
@PortraitLandscape
public void testDragToFolder() throws Exception {
final HomeAppIcon playStoreIcon = createShortcutIfNotExist("Play Store", 0, 1);
final HomeAppIcon gmailIcon = createShortcutIfNotExist("Gmail", 1, 1);
@ScreenRecord
public void testDragToFolder() {
// TODO: add the use case to drag an icon to an existing folder. Currently it either fails
// on tablets or phones due to difference in resolution.
final HomeAppIcon playStoreIcon = createShortcutIfNotExist(STORE_APP_NAME, 0, 1);
final HomeAppIcon gmailIcon = createShortcutInCenterIfNotExist(GMAIL_APP_NAME);
FolderIcon folderIcon = gmailIcon.dragToIcon(playStoreIcon);
Folder folder = folderIcon.open();
folder.getAppIcon("Play Store");
folder.getAppIcon("Gmail");
folder.getAppIcon(STORE_APP_NAME);
folder.getAppIcon(GMAIL_APP_NAME);
Workspace workspace = folder.close();
assertNull("Gmail should be moved to a folder.",
workspace.tryGetWorkspaceAppIcon("Gmail"));
assertNull("Play Store should be moved to a folder.",
workspace.tryGetWorkspaceAppIcon("Play Store"));
final HomeAppIcon youTubeIcon = createShortcutInCenterIfNotExist("YouTube");
folderIcon = youTubeIcon.dragToIcon(folderIcon);
folder = folderIcon.open();
folder.getAppIcon("YouTube");
folder.close();
assertNull(STORE_APP_NAME + " should be moved to a folder.",
workspace.tryGetWorkspaceAppIcon(STORE_APP_NAME));
assertNull(GMAIL_APP_NAME + " should be moved to a folder.",
workspace.tryGetWorkspaceAppIcon(GMAIL_APP_NAME));
}
@Test
@@ -105,7 +105,6 @@ public abstract class Launchable {
expectLongClickEvents);
}
return dragStartCenter;
}
@@ -1552,11 +1552,11 @@ public final class LauncherInstrumentation {
// vx0: initial speed at the x-dimension, set as twice the avg speed
// dx: the constant deceleration at the x-dimension
double vx0 = 2 * (to.x - from.x) / duration;
double vx0 = 2.0 * (to.x - from.x) / duration;
double dx = vx0 / duration;
// vy0: initial speed at the y-dimension, set as twice the avg speed
// dy: the constant deceleration at the y-dimension
double vy0 = 2 * (to.y - from.y) / duration;
double vy0 = 2.0 * (to.y - from.y) / duration;
double dy = vy0 / duration;
for (long i = 0; i < steps; ++i) {