Merge "Fixes BinderTests when enable shell transition."
diff --git a/quickstep/AndroidManifest.xml b/quickstep/AndroidManifest.xml
index 0f92274..25b39ed 100644
--- a/quickstep/AndroidManifest.xml
+++ b/quickstep/AndroidManifest.xml
@@ -28,6 +28,7 @@
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
<uses-permission android:name="android.permission.START_TASKS_FROM_RECENTS"/>
<uses-permission android:name="android.permission.REMOVE_TASKS"/>
+ <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>
<uses-permission android:name="android.permission.MANAGE_ACTIVITY_TASKS"/>
<uses-permission android:name="android.permission.STATUS_BAR"/>
<uses-permission android:name="android.permission.STOP_APP_SWITCHES"/>
diff --git a/quickstep/res/layout/overview_actions_container.xml b/quickstep/res/layout/overview_actions_container.xml
index dd8afc2..1c7b509 100644
--- a/quickstep/res/layout/overview_actions_container.xml
+++ b/quickstep/res/layout/overview_actions_container.xml
@@ -51,7 +51,6 @@
style="@style/OverviewActionButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:drawableStart="@drawable/ic_split_screen"
android:text="@string/action_split"
android:theme="@style/ThemeControlHighlightWorkspaceColor"
android:visibility="gone" />
diff --git a/quickstep/res/values/config.xml b/quickstep/res/values/config.xml
index 31c0f5f..3a4bb10 100644
--- a/quickstep/res/values/config.xml
+++ b/quickstep/res/values/config.xml
@@ -39,4 +39,8 @@
<string name="wellbeing_provider_pkg" translatable="false"/>
<integer name="max_depth_blur_radius">23</integer>
+
+ <!-- Accessibility actions -->
+ <item type="id" name="action_move_to_top_or_left" />
+ <item type="id" name="action_move_to_bottom_or_right" />
</resources>
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index 151b8e4..70a4a7d 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -233,4 +233,9 @@
<string name="taskbar_edu_close">Close</string>
<!-- Text on button to finish a tutorial [CHAR_LIMIT=16] -->
<string name="taskbar_edu_done">Done</string>
+
+ <!-- Label for moving drop target to the top or left side of the screen, depending on orientation (from the taskbar only). -->
+ <string name="move_drop_target_top_or_left">Move to top/left</string>
+ <!-- Label for moving drop target to the bottom or right side of the screen, depending on orientation (from the taskbar only). -->
+ <string name="move_drop_target_bottom_or_right">Move to bottom/right</string>
</resources>
diff --git a/quickstep/src/com/android/launcher3/QuickstepAccessibilityDelegate.java b/quickstep/src/com/android/launcher3/QuickstepAccessibilityDelegate.java
index 96559cb..962fd91 100644
--- a/quickstep/src/com/android/launcher3/QuickstepAccessibilityDelegate.java
+++ b/quickstep/src/com/android/launcher3/QuickstepAccessibilityDelegate.java
@@ -44,7 +44,7 @@
@Override
protected boolean performAction(View host, ItemInfo item, int action, boolean fromKeyboard) {
- QuickstepLauncher launcher = (QuickstepLauncher) mLauncher;
+ QuickstepLauncher launcher = (QuickstepLauncher) mContext;
if (action == PIN_PREDICTION) {
if (launcher.getHotseatPredictionController() == null) {
return false;
diff --git a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
index f9a0bb1..6ab49f8 100644
--- a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
+++ b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
@@ -229,9 +229,9 @@
"Item info: %s found with invalid container: %s",
info,
containerInfo));
- } else {
- return (FolderInfo) containerInfo;
}
+ // Allow crash to help debug b/173838775
+ return (FolderInfo) containerInfo;
}
return null;
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java
index 90c035f..f1e6747 100644
--- a/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java
@@ -60,6 +60,7 @@
@Override
protected void onDestroy() {
+ super.onDestroy();
mRecentsActivity.setTaskbarUIController(null);
mRecentsActivity.getStateManager().removeStateListener(mStateListener);
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index 7d23439..2622700 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -99,6 +99,7 @@
@Override
protected void onDestroy() {
+ super.onDestroy();
onLauncherResumedOrPaused(false);
mTaskbarLauncherStateController.onDestroy();
diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
index f6e0426..ce1e8b6b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
@@ -31,12 +31,14 @@
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
import android.animation.ArgbEvaluator;
import android.animation.ObjectAnimator;
import android.annotation.DrawableRes;
import android.annotation.IdRes;
import android.annotation.LayoutRes;
+import android.content.pm.ActivityInfo.Config;
import android.content.res.ColorStateList;
import android.graphics.Rect;
import android.graphics.Region;
@@ -85,6 +87,7 @@
private static final int FLAG_DISABLE_RECENTS = 1 << 8;
private static final int FLAG_DISABLE_BACK = 1 << 9;
private static final int FLAG_NOTIFICATION_SHADE_EXPANDED = 1 << 10;
+ private static final int FLAG_SCREEN_PINNING_ACTIVE = 1 << 10;
private static final int MASK_IME_SWITCHER_VISIBLE = FLAG_SWITCHER_SUPPORTED | FLAG_IME_VISIBLE;
@@ -151,7 +154,9 @@
mPropertyHolders.add(new StatePropertyHolder(
mControllers.taskbarViewController.getTaskbarIconAlpha()
.getProperty(ALPHA_INDEX_KEYGUARD),
- flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0, MultiValueAlpha.VALUE, 1, 0));
+ flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0
+ && (flags & FLAG_SCREEN_PINNING_ACTIVE) == 0,
+ MultiValueAlpha.VALUE, 1, 0));
mPropertyHolders.add(new StatePropertyHolder(mControllers.taskbarDragLayerController
.getKeyguardBgTaskbar(),
@@ -285,6 +290,7 @@
int shadeExpandedFlags = SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED
| SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
boolean isNotificationShadeExpanded = (sysUiStateFlags & shadeExpandedFlags) != 0;
+ boolean isScreenPinningActive = (sysUiStateFlags & SYSUI_STATE_SCREEN_PINNING) != 0;
// TODO(b/202218289) we're getting IME as not visible on lockscreen from system
updateStateForFlag(FLAG_IME_VISIBLE, isImeVisible);
@@ -294,6 +300,7 @@
updateStateForFlag(FLAG_DISABLE_RECENTS, isRecentsDisabled);
updateStateForFlag(FLAG_DISABLE_BACK, isBackDisabled);
updateStateForFlag(FLAG_NOTIFICATION_SHADE_EXPANDED, isNotificationShadeExpanded);
+ updateStateForFlag(FLAG_SCREEN_PINNING_ACTIVE, isScreenPinningActive);
if (mA11yButton != null) {
// Only used in 3 button
@@ -445,6 +452,12 @@
return mFloatingRotationButtonBounds.contains((int) ev.getX(), (int) ev.getY());
}
+ public void onConfigurationChanged(@Config int configChanges) {
+ if (mFloatingRotationButton != null) {
+ mFloatingRotationButton.onConfigurationChanged(configChanges);
+ }
+ }
+
public void onDestroy() {
mPropertyHolders.clear();
mControllers.rotationButtonController.unregisterListeners();
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index bc68173..883515e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -30,6 +30,7 @@
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ActivityInfo.Config;
import android.content.pm.LauncherApps;
import android.graphics.Insets;
import android.graphics.PixelFormat;
@@ -52,6 +53,7 @@
import androidx.annotation.Nullable;
import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.BubbleTextView;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.R;
@@ -112,6 +114,8 @@
// The flag to know if the window is excluded from magnification region computation.
private boolean mIsExcludeFromMagnificationRegion = false;
+ private final TaskbarShortcutMenuAccessibilityDelegate mAccessibilityDelegate;
+
public TaskbarActivityContext(Context windowContext, DeviceProfile dp,
TaskbarNavButtonController buttonController, ScopedUnfoldTransitionProgressProvider
unfoldTransitionProgressProvider) {
@@ -147,6 +151,8 @@
mLeftCorner = display.getRoundedCorner(RoundedCorner.POSITION_BOTTOM_LEFT);
mRightCorner = display.getRoundedCorner(RoundedCorner.POSITION_BOTTOM_RIGHT);
+ mAccessibilityDelegate = new TaskbarShortcutMenuAccessibilityDelegate(this);
+
// Construct controllers.
mControllers = new TaskbarControllers(this,
new TaskbarDragController(this),
@@ -208,6 +214,10 @@
mWindowManager.addView(mDragLayer, mWindowLayoutParams);
}
+ public void onConfigurationChanged(@Config int configChanges) {
+ mControllers.onConfigurationChanged(configChanges);
+ }
+
public boolean isThreeButtonNav() {
return mNavMode == Mode.THREE_BUTTONS;
}
@@ -328,6 +338,11 @@
return mControllers.taskbarPopupController.getPopupDataProvider();
}
+ @Override
+ public View.AccessibilityDelegate getAccessibilityDelegate() {
+ return mAccessibilityDelegate;
+ }
+
/**
* Sets a new data-source for this taskbar instance
*/
@@ -370,6 +385,7 @@
mControllers.taskbarStashController.updateStateForSysuiFlags(systemUiStateFlags, fromInit);
mControllers.taskbarScrimViewController.updateStateForSysuiFlags(systemUiStateFlags,
fromInit);
+ mControllers.navButtonController.updateSysuiFlags(systemUiStateFlags);
}
/**
@@ -558,4 +574,9 @@
}
mWindowManager.updateViewLayout(mDragLayer, mWindowLayoutParams);
}
+
+ public void showPopupMenuForIcon(BubbleTextView btv) {
+ setTaskbarWindowFullscreen(true);
+ btv.post(() -> mControllers.taskbarPopupController.showForIcon(btv));
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
index e19b750..488c822 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
@@ -15,6 +15,8 @@
*/
package com.android.launcher3.taskbar;
+import android.content.pm.ActivityInfo.Config;
+
import androidx.annotation.NonNull;
import com.android.systemui.shared.rotation.RotationButtonController;
@@ -109,6 +111,10 @@
mPostInitCallbacks.clear();
}
+ public void onConfigurationChanged(@Config int configChanges) {
+ navbarButtonsViewController.onConfigurationChanged(configChanges);
+ }
+
/**
* Cleans up all controllers.
*/
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
index b3a9f8d..3315f8c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
@@ -51,6 +51,8 @@
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.popup.PopupContainerWithArrow;
+import com.android.launcher3.shortcuts.DeepShortcutView;
+import com.android.launcher3.shortcuts.ShortcutDragPreviewProvider;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.ClipDescriptionCompat;
import com.android.systemui.shared.system.LauncherAppsCompat;
@@ -88,6 +90,21 @@
* @return Whether {@link View#startDragAndDrop} started successfully.
*/
protected boolean startDragOnLongClick(View view) {
+ return startDragOnLongClick(view, null, null);
+ }
+
+ protected boolean startDragOnLongClick(
+ DeepShortcutView shortcutView, Point iconShift) {
+ return startDragOnLongClick(
+ shortcutView.getBubbleText(),
+ new ShortcutDragPreviewProvider(shortcutView.getIconView(), iconShift),
+ iconShift);
+ }
+
+ private boolean startDragOnLongClick(
+ View view,
+ @Nullable DragPreviewProvider dragPreviewProvider,
+ @Nullable Point iconShift) {
if (!(view instanceof BubbleTextView)) {
return false;
}
@@ -96,7 +113,10 @@
mActivity.setTaskbarWindowFullscreen(true);
btv.post(() -> {
- startInternalDrag(btv);
+ DragView dragView = startInternalDrag(btv, dragPreviewProvider);
+ if (iconShift != null) {
+ dragView.animateShift(-iconShift.x, -iconShift.y);
+ }
btv.getIcon().setIsDisabled(true);
mControllers.taskbarAutohideSuspendController.updateFlag(
TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_DRAGGING, true);
@@ -104,7 +124,8 @@
return true;
}
- private void startInternalDrag(BubbleTextView btv) {
+ private DragView startInternalDrag(
+ BubbleTextView btv, @Nullable DragPreviewProvider dragPreviewProvider) {
float iconScale = btv.getIcon().getAnimatedScale();
// Clear the pressed state if necessary
@@ -112,7 +133,8 @@
btv.setPressed(false);
btv.clearPressedBackground();
- final DragPreviewProvider previewProvider = new DragPreviewProvider(btv);
+ final DragPreviewProvider previewProvider = dragPreviewProvider == null
+ ? new DragPreviewProvider(btv) : dragPreviewProvider;
final Drawable drawable = previewProvider.createDrawable();
final float scale = previewProvider.getScaleAndPosition(drawable, mTempXY);
int dragLayerX = mTempXY[0];
@@ -149,7 +171,7 @@
}
}
- startDrag(
+ return startDrag(
drawable,
/* view = */ null,
/* originalView = */ btv,
@@ -241,7 +263,8 @@
@Override
public void onProvideShadowMetrics(Point shadowSize, Point shadowTouchPoint) {
- shadowSize.set(mDragIconSize, mDragIconSize);
+ int iconSize = Math.max(mDragIconSize, btv.getWidth());
+ shadowSize.set(iconSize, iconSize);
// The registration point was taken before the icon scaled to mDragIconSize, so
// offset the registration to where the touch is on the new size.
int offsetX = (mDragIconSize - mDragObject.dragView.getDragRegionWidth()) / 2;
@@ -273,6 +296,12 @@
});
intent = new Intent();
if (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
+ intent.putExtra(ClipDescriptionCompat.EXTRA_PENDING_INTENT,
+ launcherApps.getShortcutIntent(
+ item.getIntent().getPackage(),
+ item.getDeepShortcutId(),
+ null,
+ item.user));
intent.putExtra(Intent.EXTRA_PACKAGE_NAME, item.getIntent().getPackage());
intent.putExtra(Intent.EXTRA_SHORTCUT_ID, item.getDeepShortcutId());
} else {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
index 152b255..f3c8cf3 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
@@ -15,7 +15,6 @@
*/
package com.android.launcher3.taskbar;
-import static com.android.launcher3.LauncherState.HOTSEAT_ICONS;
import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_APP;
import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_STASHED_LAUNCHER_STATE;
import static com.android.launcher3.taskbar.TaskbarStashController.TASKBAR_STASH_DURATION;
@@ -68,9 +67,6 @@
private int mPrevState;
private int mState;
- private LauncherState mTargetStateOverride = null;
- private LauncherState mTargetStateOverrideForStateTransition = null;
-
private boolean mIsAnimatingToLauncherViaGesture;
private boolean mIsAnimatingToLauncherViaResume;
@@ -79,7 +75,6 @@
@Override
public void onStateTransitionStart(LauncherState toState) {
- mTargetStateOverrideForStateTransition = toState;
updateStateForFlag(FLAG_TRANSITION_STATE_START_STASHED,
toState.isTaskbarStashed());
applyState();
@@ -134,18 +129,6 @@
updateStateForFlag(FLAG_RECENTS_ANIMATION_RUNNING, true);
animatorSet.play(stashController.applyStateWithoutStart(duration));
animatorSet.play(applyState(duration, false));
- animatorSet.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animator) {
- mTargetStateOverride = null;
- animator.removeListener(this);
- }
-
- @Override
- public void onAnimationStart(Animator animator) {
- mTargetStateOverride = toState;
- }
- });
TaskBarRecentsAnimationListener listener = new TaskBarRecentsAnimationListener(callbacks);
callbacks.addListener(listener);
@@ -284,7 +267,6 @@
// Reset hotseat alpha to default
mLauncher.getHotseat().setIconsAlpha(1);
}
- mTargetStateOverrideForStateTransition = null;
}
@Override
@@ -296,8 +278,6 @@
animatorSet.play(mIconAlignmentForLauncherState.animateToValue(
getCurrentIconAlignmentRatioForLauncherState(),
isTransitionStateStashed ? 0 : 1));
- } else {
- mTargetStateOverrideForStateTransition = null;
}
}
@@ -318,20 +298,14 @@
}
private void onIconAlignmentRatioChangedForStateTransition() {
- onIconAlignmentRatioChanged(
- mTargetStateOverrideForStateTransition != null
- ? mTargetStateOverrideForStateTransition
- : mLauncher.getStateManager().getState(),
- this::getCurrentIconAlignmentRatioForLauncherState);
+ onIconAlignmentRatioChanged(this::getCurrentIconAlignmentRatioForLauncherState);
}
private void onIconAlignmentRatioChanged() {
- onIconAlignmentRatioChanged(mTargetStateOverride != null ? mTargetStateOverride
- : mLauncher.getStateManager().getState(), this::getCurrentIconAlignmentRatio);
+ onIconAlignmentRatioChanged(this::getCurrentIconAlignmentRatio);
}
- private void onIconAlignmentRatioChanged(LauncherState state,
- Supplier<Float> alignmentSupplier) {
+ private void onIconAlignmentRatioChanged(Supplier<Float> alignmentSupplier) {
if (mControllers == null) {
return;
}
@@ -341,7 +315,8 @@
mTaskbarBackgroundAlpha.updateValue(1 - alignment);
- setIconAlpha(state, alignment);
+ // Switch taskbar and hotseat in last frame
+ setTaskbarViewVisible(alignment < 1);
}
private float getCurrentIconAlignmentRatio() {
@@ -352,15 +327,6 @@
return mIconAlignmentForLauncherState.value;
}
- private void setIconAlpha(LauncherState state, float progress) {
- if ((state.getVisibleElements(mLauncher) & HOTSEAT_ICONS) != 0) {
- // If the hotseat icons are visible, then switch taskbar in last frame
- setTaskbarViewVisible(progress < 1);
- } else {
- mIconAlphaForHome.setValue(1 - progress);
- }
- }
-
private void setTaskbarViewVisible(boolean isVisible) {
mIconAlphaForHome.setValue(isVisible ? 1 : 0);
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index 8a86157..7f2e37c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -30,8 +30,8 @@
import android.content.res.Configuration;
import android.hardware.display.DisplayManager;
import android.net.Uri;
+import android.os.Handler;
import android.provider.Settings;
-import android.util.Log;
import android.view.Display;
import androidx.annotation.NonNull;
@@ -94,7 +94,8 @@
Display display =
service.getSystemService(DisplayManager.class).getDisplay(DEFAULT_DISPLAY);
mContext = service.createWindowContext(display, TYPE_NAVIGATION_BAR_PANEL, null);
- mNavButtonController = new TaskbarNavButtonController(service);
+ mNavButtonController = new TaskbarNavButtonController(service,
+ SystemUiProxy.INSTANCE.get(mContext), new Handler());
mUserSetupCompleteListener = isUserSetupComplete -> recreateTaskbar();
mComponentCallbacks = new ComponentCallbacks() {
private Configuration mOldConfig = mContext.getResources().getConfiguration();
@@ -107,6 +108,11 @@
if ((configDiff & configsRequiringRecreate) != 0) {
// Color has changed, recreate taskbar to reload background color & icons.
recreateTaskbar();
+ } else {
+ // Config change might be handled without re-creating the taskbar
+ if (mTaskbarActivityContext != null) {
+ mTaskbarActivityContext.onConfigurationChanged(configDiff);
+ }
}
mOldConfig = newConfig;
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
index ae23eda..d233365 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
@@ -19,8 +19,10 @@
import static com.android.internal.app.AssistUtils.INVOCATION_TYPE_HOME_BUTTON_LONG_PRESS;
import static com.android.internal.app.AssistUtils.INVOCATION_TYPE_KEY;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
import android.os.Bundle;
+import android.os.Handler;
import androidx.annotation.IntDef;
@@ -40,6 +42,13 @@
*/
public class TaskbarNavButtonController {
+ /** Allow some time in between the long press for back and recents. */
+ static final int SCREEN_PIN_LONG_PRESS_THRESHOLD = 200;
+ static final int SCREEN_PIN_LONG_PRESS_RESET = SCREEN_PIN_LONG_PRESS_THRESHOLD + 100;
+
+ private long mLastScreenPinLongPress;
+ private boolean mScreenPinned;
+
@Retention(RetentionPolicy.SOURCE)
@IntDef(value = {
BUTTON_BACK,
@@ -57,10 +66,20 @@
static final int BUTTON_IME_SWITCH = BUTTON_RECENTS << 1;
static final int BUTTON_A11Y = BUTTON_IME_SWITCH << 1;
- private final TouchInteractionService mService;
+ private static final int SCREEN_UNPIN_COMBO = BUTTON_BACK | BUTTON_RECENTS;
+ private int mLongPressedButtons = 0;
- public TaskbarNavButtonController(TouchInteractionService service) {
+ private final TouchInteractionService mService;
+ private final SystemUiProxy mSystemUiProxy;
+ private final Handler mHandler;
+
+ private final Runnable mResetLongPress = this::resetScreenUnpin;
+
+ public TaskbarNavButtonController(TouchInteractionService service,
+ SystemUiProxy systemUiProxy, Handler handler) {
mService = service;
+ mSystemUiProxy = systemUiProxy;
+ mHandler = handler;
}
public void onButtonClick(@TaskbarButton int buttonType) {
@@ -72,13 +91,13 @@
navigateHome();
break;
case BUTTON_RECENTS:
- navigateToOverview();;
+ navigateToOverview();
break;
case BUTTON_IME_SWITCH:
showIMESwitcher();
break;
case BUTTON_A11Y:
- notifyImeClick(false /* longClick */);
+ notifyA11yClick(false /* longClick */);
break;
}
}
@@ -89,46 +108,98 @@
startAssistant();
return true;
case BUTTON_A11Y:
- notifyImeClick(true /* longClick */);
+ notifyA11yClick(true /* longClick */);
return true;
case BUTTON_BACK:
- case BUTTON_IME_SWITCH:
case BUTTON_RECENTS:
+ mLongPressedButtons |= buttonType;
+ return determineScreenUnpin();
+ case BUTTON_IME_SWITCH:
default:
return false;
}
}
+ /**
+ * Checks if the user has long pressed back and recents buttons
+ * "together" (within {@link #SCREEN_PIN_LONG_PRESS_THRESHOLD})ms
+ * If so, then requests the system to turn off screen pinning.
+ *
+ * @return true if the long press is a valid user action in attempting to unpin an app
+ * Will always return {@code false} when screen pinning is not active.
+ * NOTE: Returning true does not mean that screen pinning has stopped
+ */
+ private boolean determineScreenUnpin() {
+ long timeNow = System.currentTimeMillis();
+ if (!mScreenPinned) {
+ return false;
+ }
+
+ if (mLastScreenPinLongPress == 0) {
+ // First button long press registered, just mark time and wait for second button press
+ mLastScreenPinLongPress = System.currentTimeMillis();
+ mHandler.postDelayed(mResetLongPress, SCREEN_PIN_LONG_PRESS_RESET);
+ return true;
+ }
+
+ if ((timeNow - mLastScreenPinLongPress) > SCREEN_PIN_LONG_PRESS_THRESHOLD) {
+ // Too long in-between presses, reset the clock
+ resetScreenUnpin();
+ return false;
+ }
+
+ if ((mLongPressedButtons & SCREEN_UNPIN_COMBO) == SCREEN_UNPIN_COMBO) {
+ // Hooray! They did it (finally...)
+ mSystemUiProxy.stopScreenPinning();
+ mHandler.removeCallbacks(mResetLongPress);
+ resetScreenUnpin();
+ }
+ return true;
+ }
+
+ private void resetScreenUnpin() {
+ mLongPressedButtons = 0;
+ mLastScreenPinLongPress = 0;
+ }
+
+ public void updateSysuiFlags(int sysuiFlags) {
+ mScreenPinned = (sysuiFlags & SYSUI_STATE_SCREEN_PINNING) != 0;
+ }
+
private void navigateHome() {
mService.getOverviewCommandHelper().addCommand(OverviewCommandHelper.TYPE_HOME);
}
private void navigateToOverview() {
+ if (mScreenPinned) {
+ return;
+ }
TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "onOverviewToggle");
mService.getOverviewCommandHelper().addCommand(OverviewCommandHelper.TYPE_TOGGLE);
}
private void executeBack() {
- SystemUiProxy.INSTANCE.getNoCreate().onBackPressed();
+ mSystemUiProxy.onBackPressed();
}
private void showIMESwitcher() {
- SystemUiProxy.INSTANCE.getNoCreate().onImeSwitcherPressed();
+ mSystemUiProxy.onImeSwitcherPressed();
}
- private void notifyImeClick(boolean longClick) {
- SystemUiProxy systemUiProxy = SystemUiProxy.INSTANCE.getNoCreate();
+ private void notifyA11yClick(boolean longClick) {
if (longClick) {
- systemUiProxy.notifyAccessibilityButtonLongClicked();
+ mSystemUiProxy.notifyAccessibilityButtonLongClicked();
} else {
- systemUiProxy.notifyAccessibilityButtonClicked(mService.getDisplayId());
+ mSystemUiProxy.notifyAccessibilityButtonClicked(mService.getDisplayId());
}
}
private void startAssistant() {
+ if (mScreenPinned) {
+ return;
+ }
Bundle args = new Bundle();
args.putInt(INVOCATION_TYPE_KEY, INVOCATION_TYPE_HOME_BUTTON_LONG_PRESS);
- SystemUiProxy systemUiProxy = SystemUiProxy.INSTANCE.getNoCreate();
- systemUiProxy.startAssistant(args);
+ mSystemUiProxy.startAssistant(args);
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
index 06c75fc..2dee506 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
@@ -15,6 +15,10 @@
*/
package com.android.launcher3.taskbar;
+import android.graphics.Point;
+import android.view.MotionEvent;
+import android.view.View;
+
import androidx.annotation.NonNull;
import com.android.launcher3.BubbleTextView;
@@ -30,6 +34,7 @@
import com.android.launcher3.popup.PopupDataProvider;
import com.android.launcher3.popup.PopupLiveUpdateHandler;
import com.android.launcher3.popup.SystemShortcut;
+import com.android.launcher3.shortcuts.DeepShortcutView;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.LauncherBindableItemsContainer;
import com.android.launcher3.util.PackageUserKey;
@@ -131,8 +136,14 @@
(PopupContainerWithArrow) context.getLayoutInflater().inflate(
R.layout.popup_container, context.getDragLayer(), false);
container.addOnAttachStateChangeListener(
- new PopupLiveUpdateHandler<>(mContext, container));
+ new PopupLiveUpdateHandler<TaskbarActivityContext>(mContext, container) {
+ @Override
+ protected void showPopupContainerForIcon(BubbleTextView originalIcon) {
+ showForIcon(originalIcon);
+ }
+ });
// TODO (b/198438631): configure for taskbar/context
+ container.setPopupItemDragHandler(new TaskbarPopupItemDragHandler());
container.populateAndShow(icon,
mPopupDataProvider.getShortcutCountForItem(item),
@@ -145,4 +156,43 @@
container.requestFocus();
return container;
}
+
+ private class TaskbarPopupItemDragHandler implements
+ PopupContainerWithArrow.PopupItemDragHandler {
+
+ protected final Point mIconLastTouchPos = new Point();
+
+ TaskbarPopupItemDragHandler() {}
+
+ @Override
+ public boolean onTouch(View view, MotionEvent ev) {
+ // Touched a shortcut, update where it was touched so we can drag from there on
+ // long click.
+ switch (ev.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ case MotionEvent.ACTION_MOVE:
+ mIconLastTouchPos.set((int) ev.getX(), (int) ev.getY());
+ break;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean onLongClick(View v) {
+ // Return early if not the correct view
+ if (!(v.getParent() instanceof DeepShortcutView)) return false;
+
+ DeepShortcutView sv = (DeepShortcutView) v.getParent();
+ sv.setWillDrawIcon(false);
+
+ // Move the icon to align with the center-top of the touch point
+ Point iconShift = new Point();
+ iconShift.x = mIconLastTouchPos.x - sv.getIconCenter().x;
+ iconShift.y = mIconLastTouchPos.y - mContext.getDeviceProfile().iconSizePx;
+
+ mControllers.taskbarDragController.startDragOnLongClick(sv, iconShift);
+
+ return false;
+ }
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarShortcutMenuAccessibilityDelegate.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarShortcutMenuAccessibilityDelegate.java
new file mode 100644
index 0000000..1589582
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarShortcutMenuAccessibilityDelegate.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.taskbar;
+
+import static com.android.launcher3.accessibility.LauncherAccessibilityDelegate.DEEP_SHORTCUTS;
+import static com.android.launcher3.accessibility.LauncherAccessibilityDelegate.SHORTCUTS_AND_NOTIFICATIONS;
+import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
+import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
+
+import android.content.Intent;
+import android.content.pm.LauncherApps;
+import android.view.KeyEvent;
+import android.view.View;
+
+import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.LauncherSettings;
+import com.android.launcher3.R;
+import com.android.launcher3.accessibility.BaseAccessibilityDelegate;
+import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.notification.NotificationListener;
+import com.android.launcher3.util.ShortcutUtil;
+import com.android.quickstep.SystemUiProxy;
+import com.android.systemui.shared.system.LauncherAppsCompat;
+
+import java.util.List;
+
+/**
+ * Accessibility delegate for the Taskbar. This provides an accessible interface for taskbar
+ * features.
+ */
+public class TaskbarShortcutMenuAccessibilityDelegate
+ extends BaseAccessibilityDelegate<TaskbarActivityContext> {
+
+ public static final int MOVE_TO_TOP_OR_LEFT = R.id.action_move_to_top_or_left;
+ public static final int MOVE_TO_BOTTOM_OR_RIGHT = R.id.action_move_to_bottom_or_right;
+
+ private final LauncherApps mLauncherApps;
+
+ public TaskbarShortcutMenuAccessibilityDelegate(TaskbarActivityContext context) {
+ super(context);
+ mLauncherApps = context.getSystemService(LauncherApps.class);
+
+ mActions.put(DEEP_SHORTCUTS, new LauncherAction(DEEP_SHORTCUTS,
+ R.string.action_deep_shortcut, KeyEvent.KEYCODE_S));
+ mActions.put(SHORTCUTS_AND_NOTIFICATIONS, new LauncherAction(DEEP_SHORTCUTS,
+ R.string.shortcuts_menu_with_notifications_description, KeyEvent.KEYCODE_S));
+ mActions.put(MOVE_TO_TOP_OR_LEFT, new LauncherAction(
+ MOVE_TO_TOP_OR_LEFT, R.string.move_drop_target_top_or_left, KeyEvent.KEYCODE_L));
+ mActions.put(MOVE_TO_BOTTOM_OR_RIGHT, new LauncherAction(
+ MOVE_TO_BOTTOM_OR_RIGHT,
+ R.string.move_drop_target_bottom_or_right,
+ KeyEvent.KEYCODE_R));
+ }
+
+ @Override
+ protected void getSupportedActions(View host, ItemInfo item, List<LauncherAction> out) {
+ if (ShortcutUtil.supportsShortcuts(item) && FeatureFlags.ENABLE_TASKBAR_POPUP_MENU.get()) {
+ out.add(mActions.get(NotificationListener.getInstanceIfConnected() != null
+ ? SHORTCUTS_AND_NOTIFICATIONS : DEEP_SHORTCUTS));
+ }
+ out.add(mActions.get(MOVE_TO_TOP_OR_LEFT));
+ out.add(mActions.get(MOVE_TO_BOTTOM_OR_RIGHT));
+ }
+
+ @Override
+ protected boolean performAction(View host, ItemInfo item, int action, boolean fromKeyboard) {
+ if (item instanceof WorkspaceItemInfo
+ && (action == MOVE_TO_TOP_OR_LEFT || action == MOVE_TO_BOTTOM_OR_RIGHT)) {
+ WorkspaceItemInfo info = (WorkspaceItemInfo) item;
+ int side = action == MOVE_TO_TOP_OR_LEFT
+ ? SPLIT_POSITION_TOP_OR_LEFT : SPLIT_POSITION_BOTTOM_OR_RIGHT;
+
+ if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
+ SystemUiProxy.INSTANCE.get(mContext).startShortcut(
+ info.getIntent().getPackage(),
+ info.getDeepShortcutId(),
+ side,
+ /* bundleOpts= */ null,
+ info.user);
+ } else {
+ SystemUiProxy.INSTANCE.get(mContext).startIntent(
+ LauncherAppsCompat.getMainActivityLaunchIntent(
+ mLauncherApps,
+ item.getIntent().getComponent(),
+ /* startActivityOptions= */null,
+ item.user),
+ new Intent(), side, null);
+ }
+ return true;
+ } else if (action == DEEP_SHORTCUTS || action == SHORTCUTS_AND_NOTIFICATIONS) {
+ mContext.showPopupMenuForIcon((BubbleTextView) host);
+
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ protected boolean beginAccessibleDrag(View item, ItemInfo info, boolean fromKeyboard) {
+ return false;
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
index f713dca..f6bc785 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
@@ -18,6 +18,8 @@
import android.graphics.Rect;
import android.view.View;
+import androidx.annotation.CallSuper;
+
import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.model.data.WorkspaceItemInfo;
@@ -33,11 +35,15 @@
// Initialized in init.
protected TaskbarControllers mControllers;
+ @CallSuper
protected void init(TaskbarControllers taskbarControllers) {
mControllers = taskbarControllers;
}
- protected void onDestroy() { }
+ @CallSuper
+ protected void onDestroy() {
+ mControllers = null;
+ }
protected boolean isTaskbarTouchable() {
return true;
diff --git a/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java b/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
index ee6e8ce..351ec4a 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
@@ -16,6 +16,7 @@
package com.android.launcher3.uioverrides;
import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
+import static com.android.launcher3.icons.BitmapInfo.FLAG_THEMED;
import android.animation.Animator;
import android.animation.AnimatorSet;
@@ -236,7 +237,7 @@
mSlotMachineIcons = new ArrayList<>(iconsToAnimate.size() + 2);
mSlotMachineIcons.add(getIcon());
iconsToAnimate.stream()
- .map(iconInfo -> iconInfo.newThemedIcon(mContext))
+ .map(iconInfo -> iconInfo.newIcon(mContext, FLAG_THEMED))
.forEach(mSlotMachineIcons::add);
if (endWithOriginalIcon) {
mSlotMachineIcons.add(getIcon());
diff --git a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
index b21d677..19897a1 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
@@ -66,6 +66,12 @@
// In Overview, we may be layering app surfaces behind Launcher, so we need to notify
// DepthController to prevent optimizations which might occlude the layers behind
mLauncher.getDepthController().setHasContentBehindLauncher(state.overviewUi);
+
+ if (isSplitSelectionState(state)) {
+ mRecentsView.applySplitPrimaryScrollOffset();
+ } else {
+ mRecentsView.resetSplitPrimaryScrollOffset();
+ }
}
@Override
@@ -90,9 +96,10 @@
LauncherState currentState = mLauncher.getStateManager().getState();
if (isSplitSelectionState(toState) && !isSplitSelectionState(currentState)) {
builder.add(mRecentsView.createSplitSelectInitAnimation().buildAnim());
+ }
+ if (isSplitSelectionState(toState)) {
mRecentsView.applySplitPrimaryScrollOffset();
- } else if (!isSplitSelectionState(toState) && isSplitSelectionState(currentState)) {
- builder.add(mRecentsView.cancelSplitSelect(true).buildAnim());
+ } else {
mRecentsView.resetSplitPrimaryScrollOffset();
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/SplitScreenSelectState.java b/quickstep/src/com/android/launcher3/uioverrides/states/SplitScreenSelectState.java
index 106375a..4f5f27a 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/SplitScreenSelectState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/SplitScreenSelectState.java
@@ -31,11 +31,6 @@
}
@Override
- public void onBackPressed(Launcher launcher) {
- launcher.getStateManager().goToState(OVERVIEW);
- }
-
- @Override
public int getVisibleElements(Launcher launcher) {
return SPLIT_PLACHOLDER_VIEW;
}
diff --git a/quickstep/src/com/android/quickstep/RecentTasksList.java b/quickstep/src/com/android/quickstep/RecentTasksList.java
index 097850f..c5f4a53 100644
--- a/quickstep/src/com/android/quickstep/RecentTasksList.java
+++ b/quickstep/src/com/android/quickstep/RecentTasksList.java
@@ -36,7 +36,6 @@
import com.android.wm.shell.util.GroupedRecentTaskInfo;
import com.android.wm.shell.util.StagedSplitBounds;
-import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.function.Consumer;
@@ -220,26 +219,6 @@
return newTasks;
}
- public void dump(String prefix, PrintWriter writer) {
- writer.println(prefix + "RecentTasksList:");
- writer.println(prefix + " mChangeId=" + mChangeId);
- writer.println(prefix + " mResultsUi=[id=" + mResultsUi.mRequestId + ", tasks=");
- for (GroupTask task : mResultsUi) {
- writer.println(prefix + " t1=" + task.task1.key.id
- + " t2=" + (task.hasMultipleTasks() ? task.task2.key.id : "-1"));
- }
- writer.println(prefix + " ]");
- int currentUserId = Process.myUserHandle().getIdentifier();
- ArrayList<GroupedRecentTaskInfo> rawTasks =
- mSysUiProxy.getRecentTasks(Integer.MAX_VALUE, currentUserId);
- writer.println(prefix + " rawTasks=[");
- for (GroupedRecentTaskInfo task : rawTasks) {
- writer.println(prefix + " t1=" + task.mTaskInfo1.taskId
- + " t2=" + (task.mTaskInfo2 != null ? task.mTaskInfo2.taskId : "-1"));
- }
- writer.println(prefix + " ]");
- }
-
private static class TaskLoadResult extends ArrayList<GroupTask> {
final int mRequestId;
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
index dd6392c..b502676 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
@@ -23,6 +23,7 @@
import android.view.RemoteAnimationTarget;
import androidx.annotation.BinderThread;
+import androidx.annotation.NonNull;
import androidx.annotation.UiThread;
import com.android.launcher3.Utilities;
@@ -77,7 +78,7 @@
public void notifyAnimationCanceled() {
mCancelled = true;
- onAnimationCanceled(null);
+ onAnimationCanceled(new HashMap<>());
}
// Called only in Q platform
@@ -167,16 +168,17 @@
* Callback from the system when the recents animation is canceled. {@param thumbnailData}
* is passed back for rendering screenshot to replace live tile.
*/
- default void onRecentsAnimationCanceled(HashMap<Integer, ThumbnailData> thumbnailDatas) {}
+ default void onRecentsAnimationCanceled(
+ @NonNull HashMap<Integer, ThumbnailData> thumbnailDatas) {}
/**
* Callback made whenever the recents animation is finished.
*/
- default void onRecentsAnimationFinished(RecentsAnimationController controller) {}
+ default void onRecentsAnimationFinished(@NonNull RecentsAnimationController controller) {}
/**
* Callback made when a task started from the recents is ready for an app transition.
*/
- default void onTasksAppeared(RemoteAnimationTargetCompat[] appearedTaskTarget) {}
+ default void onTasksAppeared(@NonNull RemoteAnimationTargetCompat[] appearedTaskTarget) {}
}
}
diff --git a/quickstep/src/com/android/quickstep/RecentsModel.java b/quickstep/src/com/android/quickstep/RecentsModel.java
index 5d77a6e..e539a8c 100644
--- a/quickstep/src/com/android/quickstep/RecentsModel.java
+++ b/quickstep/src/com/android/quickstep/RecentsModel.java
@@ -43,7 +43,6 @@
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.TaskStackChangeListeners;
-import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
@@ -221,11 +220,6 @@
mThumbnailChangeListeners.remove(listener);
}
- public void dump(String prefix, PrintWriter writer) {
- writer.println(prefix + "RecentsModel:");
- mTaskList.dump(" ", writer);
- }
-
/**
* Listener for receiving various task properties changes
*/
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index 2543e6c..6c623bc 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -83,16 +83,14 @@
MAIN_EXECUTOR.execute(() -> clearProxy());
};
- // Save the listeners passed into the proxy since OverviewProxyService may not have been bound
- // yet, and we'll need to set/register these listeners with SysUI when they do. Note that it is
- // up to the caller to clear the listeners to prevent leaks as these can be held indefinitely
- // in case SysUI needs to rebind.
- private IPipAnimationListener mPipAnimationListener;
- private ISplitScreenListener mSplitScreenListener;
- private IStartingWindowListener mStartingWindowListener;
- private ISmartspaceCallback mSmartspaceCallback;
- private IRecentTasksListener mRecentTasksListener;
- private final ArrayList<RemoteTransitionCompat> mRemoteTransitions = new ArrayList<>();
+ // Save the listeners passed into the proxy since when set/register these listeners,
+ // setProxy may not have been called, eg. OverviewProxyService is not connected yet.
+ private IPipAnimationListener mPendingPipAnimationListener;
+ private ISplitScreenListener mPendingSplitScreenListener;
+ private IStartingWindowListener mPendingStartingWindowListener;
+ private ISmartspaceCallback mPendingSmartspaceCallback;
+ private IRecentTasksListener mPendingRecentTasksListener;
+ private final ArrayList<RemoteTransitionCompat> mPendingRemoteTransitions = new ArrayList<>();
// Used to dedupe calls to SystemUI
private int mLastShelfHeight;
@@ -169,23 +167,29 @@
mRecentTasks = recentTasks;
linkToDeath();
// re-attach the listeners once missing due to setProxy has not been initialized yet.
- if (mPipAnimationListener != null && mPip != null) {
- setPinnedStackAnimationListener(mPipAnimationListener);
+ if (mPendingPipAnimationListener != null && mPip != null) {
+ setPinnedStackAnimationListener(mPendingPipAnimationListener);
+ mPendingPipAnimationListener = null;
}
- if (mSplitScreenListener != null && mSplitScreen != null) {
- registerSplitScreenListener(mSplitScreenListener);
+ if (mPendingSplitScreenListener != null && mSplitScreen != null) {
+ registerSplitScreenListener(mPendingSplitScreenListener);
+ mPendingSplitScreenListener = null;
}
- if (mStartingWindowListener != null && mStartingWindow != null) {
- setStartingWindowListener(mStartingWindowListener);
+ if (mPendingStartingWindowListener != null && mStartingWindow != null) {
+ setStartingWindowListener(mPendingStartingWindowListener);
+ mPendingStartingWindowListener = null;
}
- if (mSmartspaceCallback != null && mSmartspaceTransitionController != null) {
- setSmartspaceCallback(mSmartspaceCallback);
+ if (mPendingSmartspaceCallback != null && mSmartspaceTransitionController != null) {
+ setSmartspaceCallback(mPendingSmartspaceCallback);
+ mPendingSmartspaceCallback = null;
}
- for (int i = mRemoteTransitions.size() - 1; i >= 0; --i) {
- registerRemoteTransition(mRemoteTransitions.get(i));
+ for (int i = mPendingRemoteTransitions.size() - 1; i >= 0; --i) {
+ registerRemoteTransition(mPendingRemoteTransitions.get(i));
}
- if (mRecentTasksListener != null && mRecentTasks != null) {
- registerRecentTasksListener(mRecentTasksListener);
+ mPendingRemoteTransitions.clear();
+ if (mPendingRecentTasksListener != null && mRecentTasks != null) {
+ registerRecentTasksListener(mPendingRecentTasksListener);
+ mPendingRecentTasksListener = null;
}
if (mPendingSetNavButtonAlpha != null) {
@@ -509,8 +513,9 @@
} catch (RemoteException e) {
Log.w(TAG, "Failed call setPinnedStackAnimationListener", e);
}
+ } else {
+ mPendingPipAnimationListener = listener;
}
- mPipAnimationListener = listener;
}
public Rect startSwipePipToHome(ComponentName componentName, ActivityInfo activityInfo,
@@ -548,8 +553,9 @@
} catch (RemoteException e) {
Log.w(TAG, "Failed call registerSplitScreenListener");
}
+ } else {
+ mPendingSplitScreenListener = listener;
}
- mSplitScreenListener = listener;
}
public void unregisterSplitScreenListener(ISplitScreenListener listener) {
@@ -560,7 +566,7 @@
Log.w(TAG, "Failed call unregisterSplitScreenListener");
}
}
- mSplitScreenListener = null;
+ mPendingSplitScreenListener = null;
}
/** Start multiple tasks in split-screen simultaneously. */
@@ -593,11 +599,11 @@
}
}
- public void startShortcut(String packageName, String shortcutId, int stage, int position,
+ public void startShortcut(String packageName, String shortcutId, int position,
Bundle options, UserHandle user) {
if (mSplitScreen != null) {
try {
- mSplitScreen.startShortcut(packageName, shortcutId, stage, position, options,
+ mSplitScreen.startShortcut(packageName, shortcutId, position, options,
user);
} catch (RemoteException e) {
Log.w(TAG, "Failed call startShortcut");
@@ -605,11 +611,11 @@
}
}
- public void startIntent(PendingIntent intent, Intent fillInIntent, int stage, int position,
+ public void startIntent(PendingIntent intent, Intent fillInIntent, int position,
Bundle options) {
if (mSplitScreen != null) {
try {
- mSplitScreen.startIntent(intent, fillInIntent, stage, position, options);
+ mSplitScreen.startIntent(intent, fillInIntent, position, options);
} catch (RemoteException e) {
Log.w(TAG, "Failed call startIntent");
}
@@ -681,8 +687,9 @@
} catch (RemoteException e) {
Log.w(TAG, "Failed call registerRemoteTransition");
}
+ } else {
+ mPendingRemoteTransitions.add(remoteTransition);
}
- mRemoteTransitions.add(remoteTransition);
}
public void unregisterRemoteTransition(RemoteTransitionCompat remoteTransition) {
@@ -693,7 +700,7 @@
Log.w(TAG, "Failed call registerRemoteTransition");
}
}
- mRemoteTransitions.remove(remoteTransition);
+ mPendingRemoteTransitions.remove(remoteTransition);
}
//
@@ -710,8 +717,9 @@
} catch (RemoteException e) {
Log.w(TAG, "Failed call setStartingWindowListener", e);
}
+ } else {
+ mPendingStartingWindowListener = listener;
}
- mStartingWindowListener = listener;
}
//
@@ -725,8 +733,9 @@
} catch (RemoteException e) {
Log.w(TAG, "Failed call setStartingWindowListener", e);
}
+ } else {
+ mPendingSmartspaceCallback = callback;
}
- mSmartspaceCallback = callback;
}
//
@@ -740,8 +749,9 @@
} catch (RemoteException e) {
Log.w(TAG, "Failed call registerRecentTasksListener", e);
}
+ } else {
+ mPendingRecentTasksListener = listener;
}
- mRecentTasksListener = listener;
}
public void unregisterRecentTasksListener(IRecentTasksListener listener) {
@@ -752,7 +762,7 @@
Log.w(TAG, "Failed call unregisterRecentTasksListener");
}
}
- mRecentTasksListener = null;
+ mPendingRecentTasksListener = null;
}
public ArrayList<GroupedRecentTaskInfo> getRecentTasks(int numTasks, int userId) {
diff --git a/quickstep/src/com/android/quickstep/TaskIconCache.java b/quickstep/src/com/android/quickstep/TaskIconCache.java
index fa61fff..b5d6fae 100644
--- a/quickstep/src/com/android/quickstep/TaskIconCache.java
+++ b/quickstep/src/com/android/quickstep/TaskIconCache.java
@@ -26,10 +26,8 @@
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
-import android.os.Build;
import android.os.UserHandle;
import android.text.TextUtils;
-import android.util.SparseArray;
import android.view.accessibility.AccessibilityManager;
import androidx.annotation.WorkerThread;
@@ -37,6 +35,7 @@
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.icons.BaseIconFactory;
+import com.android.launcher3.icons.BaseIconFactory.IconOptions;
import com.android.launcher3.icons.BitmapInfo;
import com.android.launcher3.icons.IconProvider;
import com.android.launcher3.util.DisplayController;
@@ -63,7 +62,7 @@
private final Context mContext;
private final TaskKeyLruCache<TaskCacheEntry> mIconCache;
- private final SparseArray<BitmapInfo> mDefaultIcons = new SparseArray<>();
+ private final BitmapInfo[] mDefaultIcons = new BitmapInfo[1];
private final IconProvider mIconProvider;
private BaseIconFactory mIconFactory;
@@ -154,7 +153,6 @@
// TODO: Load icon resource (b/143363444)
Bitmap icon = TaskDescriptionCompat.getIcon(desc, key.userId);
if (icon != null) {
- /* isInstantApp */
entry.icon = getBitmapInfo(
new BitmapDrawable(mContext.getResources(), icon),
key.userId,
@@ -210,14 +208,12 @@
@WorkerThread
private Drawable getDefaultIcon(int userId) {
synchronized (mDefaultIcons) {
- BitmapInfo info = mDefaultIcons.get(userId);
- if (info == null) {
+ if (mDefaultIcons[0] == null) {
try (BaseIconFactory bif = getIconFactory()) {
- info = bif.makeDefaultIcon(UserHandle.of(userId));
+ mDefaultIcons[0] = bif.makeDefaultIcon();
}
- mDefaultIcons.put(userId, info);
}
- return info.newIcon(mContext);
+ return mDefaultIcons[0].clone().withUser(UserHandle.of(userId)).newIcon(mContext);
}
}
@@ -229,8 +225,8 @@
bif.setWrapperBackgroundColor(primaryColor);
// User version code O, so that the icon is always wrapped in an adaptive icon container
- return bif.createBadgedIconBitmap(drawable, UserHandle.of(userId),
- Build.VERSION_CODES.O, isInstantApp);
+ return bif.createBadgedIconBitmap(drawable,
+ new IconOptions().setUser(UserHandle.of(userId)).setInstantApp(isInstantApp));
}
}
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index e77ec78..97fc6d7 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -316,7 +316,7 @@
mt[i] = localMt;
Matrix localMti = new Matrix();
- localMti.invert(localMt);
+ localMt.invert(localMti);
mti[i] = localMti;
}
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index d1f39d2..707b905 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -948,7 +948,6 @@
pw.println(" resumed=" + resumed);
pw.println(" mConsumer=" + mConsumer.getName());
ActiveGestureLog.INSTANCE.dump("", pw);
- RecentsModel.INSTANCE.get(this).dump("", pw);
pw.println("ProtoTrace:");
pw.println(" file=" + ProtoTracer.INSTANCE.get(this).getTraceFile());
}
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
index c82b931..5b4eb8b 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
@@ -31,6 +31,7 @@
import androidx.annotation.Nullable;
+import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.statemanager.StateManager.StateListener;
@@ -73,6 +74,7 @@
@Override
public void startHome() {
mActivity.startHome();
+ AbstractFloatingView.closeAllOpenViews(mActivity, mActivity.isStarted());
}
/**
diff --git a/quickstep/src/com/android/quickstep/util/BaseUnfoldMoveFromCenterAnimator.java b/quickstep/src/com/android/quickstep/util/BaseUnfoldMoveFromCenterAnimator.java
new file mode 100644
index 0000000..861ff96
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/BaseUnfoldMoveFromCenterAnimator.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2021 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.quickstep.util;
+
+import android.annotation.CallSuper;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+
+import com.android.systemui.shared.animation.UnfoldMoveFromCenterAnimator;
+import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Animation that moves launcher icons and widgets from center to the sides (final position)
+ */
+public abstract class BaseUnfoldMoveFromCenterAnimator implements TransitionProgressListener {
+
+ private final UnfoldMoveFromCenterAnimator mMoveFromCenterAnimation;
+
+ private final Map<ViewGroup, Boolean> mOriginalClipToPadding = new HashMap<>();
+ private final Map<ViewGroup, Boolean> mOriginalClipChildren = new HashMap<>();
+
+ public BaseUnfoldMoveFromCenterAnimator(WindowManager windowManager) {
+ mMoveFromCenterAnimation = new UnfoldMoveFromCenterAnimator(windowManager,
+ new LauncherViewsMoveFromCenterTranslationApplier());
+ }
+
+ @CallSuper
+ @Override
+ public void onTransitionStarted() {
+ mMoveFromCenterAnimation.updateDisplayProperties();
+ onPrepareViewsForAnimation();
+ onTransitionProgress(0f);
+ }
+
+ @CallSuper
+ @Override
+ public void onTransitionProgress(float progress) {
+ mMoveFromCenterAnimation.onTransitionProgress(progress);
+ }
+
+ @CallSuper
+ @Override
+ public void onTransitionFinished() {
+ mMoveFromCenterAnimation.onTransitionFinished();
+ mMoveFromCenterAnimation.clearRegisteredViews();
+
+ mOriginalClipChildren.clear();
+ mOriginalClipToPadding.clear();
+ }
+
+ protected void onPrepareViewsForAnimation() {
+
+ }
+
+ protected void registerViewForAnimation(View view) {
+ mMoveFromCenterAnimation.registerViewForAnimation(view);
+ }
+
+ protected void disableClipping(ViewGroup view) {
+ mOriginalClipToPadding.put(view, view.getClipToPadding());
+ mOriginalClipChildren.put(view, view.getClipChildren());
+ view.setClipToPadding(false);
+ view.setClipChildren(false);
+ }
+
+ protected void restoreClipping(ViewGroup view) {
+ final Boolean originalClipToPadding = mOriginalClipToPadding.get(view);
+ if (originalClipToPadding != null) {
+ view.setClipToPadding(originalClipToPadding);
+ }
+ final Boolean originalClipChildren = mOriginalClipChildren.get(view);
+ if (originalClipChildren != null) {
+ view.setClipChildren(originalClipChildren);
+ }
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java b/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java
index b39412b..6b6bd6a 100644
--- a/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java
+++ b/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java
@@ -18,14 +18,17 @@
import static com.android.launcher3.Utilities.comp;
import android.annotation.Nullable;
-import android.view.ViewTreeObserver;
import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
+
+import androidx.core.view.OneShotPreDrawListener;
import com.android.launcher3.Hotseat;
import com.android.launcher3.Launcher;
import com.android.launcher3.util.HorizontalInsettableView;
import com.android.systemui.unfold.UnfoldTransitionProgressProvider;
import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener;
+import com.android.systemui.unfold.util.NaturalRotationUnfoldProgressProvider;
import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider;
/**
@@ -43,6 +46,7 @@
private HorizontalInsettableView mQsbInsettable;
private final ScopedUnfoldTransitionProgressProvider mProgressProvider;
+ private final NaturalRotationUnfoldProgressProvider mNaturalOrientationProgressProvider;
public LauncherUnfoldAnimationController(
Launcher launcher,
@@ -51,10 +55,19 @@
mLauncher = launcher;
mProgressProvider = new ScopedUnfoldTransitionProgressProvider(
unfoldTransitionProgressProvider);
+ mNaturalOrientationProgressProvider = new NaturalRotationUnfoldProgressProvider(launcher,
+ WindowManagerGlobal.getWindowManagerService(), mProgressProvider);
+ mNaturalOrientationProgressProvider.init();
+ // Animated in all orientations
mProgressProvider.addCallback(new UnfoldMoveFromCenterWorkspaceAnimator(launcher,
windowManager));
- mProgressProvider.addCallback(new QsbAnimationListener());
+
+ // Animated only in natural orientation
+ mNaturalOrientationProgressProvider
+ .addCallback(new QsbAnimationListener());
+ mNaturalOrientationProgressProvider
+ .addCallback(new UnfoldMoveFromCenterHotseatAnimator(launcher, windowManager));
}
/**
@@ -66,17 +79,8 @@
mQsbInsettable = (HorizontalInsettableView) hotseat.getQsb();
}
- final ViewTreeObserver obs = mLauncher.getWorkspace().getViewTreeObserver();
- obs.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
- @Override
- public boolean onPreDraw() {
- if (obs.isAlive()) {
- mProgressProvider.setReadyToHandleTransition(true);
- obs.removeOnPreDrawListener(this);
- }
- return true;
- }
- });
+ OneShotPreDrawListener.add(mLauncher.getWorkspace(),
+ () -> mProgressProvider.setReadyToHandleTransition(true));
}
/**
@@ -92,6 +96,7 @@
*/
public void onDestroy() {
mProgressProvider.destroy();
+ mNaturalOrientationProgressProvider.destroy();
}
private class QsbAnimationListener implements TransitionProgressListener {
diff --git a/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterHotseatAnimator.java b/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterHotseatAnimator.java
new file mode 100644
index 0000000..dc97dd6
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterHotseatAnimator.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2021 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.quickstep.util;
+
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+
+import com.android.launcher3.Hotseat;
+import com.android.launcher3.Launcher;
+
+/**
+ * Animation that moves hotseat icons from center to the sides (final position)
+ */
+public class UnfoldMoveFromCenterHotseatAnimator extends BaseUnfoldMoveFromCenterAnimator {
+
+ private final Launcher mLauncher;
+
+ public UnfoldMoveFromCenterHotseatAnimator(Launcher launcher, WindowManager windowManager) {
+ super(windowManager);
+ mLauncher = launcher;
+ }
+
+ @Override
+ protected void onPrepareViewsForAnimation() {
+ Hotseat hotseat = mLauncher.getHotseat();
+
+ ViewGroup hotseatIcons = hotseat.getShortcutsAndWidgets();
+ disableClipping(hotseat);
+
+ for (int i = 0; i < hotseatIcons.getChildCount(); i++) {
+ View child = hotseatIcons.getChildAt(i);
+ registerViewForAnimation(child);
+ }
+ }
+
+ @Override
+ public void onTransitionFinished() {
+ restoreClipping(mLauncher.getHotseat());
+ super.onTransitionFinished();
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterWorkspaceAnimator.java b/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterWorkspaceAnimator.java
index 95403b2..3d72398 100644
--- a/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterWorkspaceAnimator.java
+++ b/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterWorkspaceAnimator.java
@@ -16,44 +16,28 @@
package com.android.quickstep.util;
import android.view.View;
-import android.view.ViewGroup;
import android.view.WindowManager;
import com.android.launcher3.CellLayout;
-import com.android.launcher3.Hotseat;
import com.android.launcher3.Launcher;
import com.android.launcher3.ShortcutAndWidgetContainer;
import com.android.launcher3.Workspace;
-import com.android.systemui.shared.animation.UnfoldMoveFromCenterAnimator;
-import com.android.systemui.unfold.UnfoldTransitionProgressProvider;
-
-import java.util.HashMap;
-import java.util.Map;
/**
* Animation that moves launcher icons and widgets from center to the sides (final position)
*/
-public class UnfoldMoveFromCenterWorkspaceAnimator
- implements UnfoldTransitionProgressProvider.TransitionProgressListener {
+public class UnfoldMoveFromCenterWorkspaceAnimator extends BaseUnfoldMoveFromCenterAnimator {
private final Launcher mLauncher;
- private final UnfoldMoveFromCenterAnimator mMoveFromCenterAnimation;
-
- private final Map<ViewGroup, Boolean> mOriginalClipToPadding = new HashMap<>();
- private final Map<ViewGroup, Boolean> mOriginalClipChildren = new HashMap<>();
public UnfoldMoveFromCenterWorkspaceAnimator(Launcher launcher, WindowManager windowManager) {
+ super(windowManager);
mLauncher = launcher;
- mMoveFromCenterAnimation = new UnfoldMoveFromCenterAnimator(windowManager,
- new LauncherViewsMoveFromCenterTranslationApplier());
}
@Override
- public void onTransitionStarted() {
- mMoveFromCenterAnimation.updateDisplayProperties();
-
+ protected void onPrepareViewsForAnimation() {
Workspace workspace = mLauncher.getWorkspace();
- Hotseat hotseat = mLauncher.getHotseat();
// App icons and widgets
workspace
@@ -65,57 +49,17 @@
for (int i = 0; i < itemsContainer.getChildCount(); i++) {
View child = itemsContainer.getChildAt(i);
- mMoveFromCenterAnimation.registerViewForAnimation(child);
+ registerViewForAnimation(child);
}
});
disableClipping(workspace);
-
- // Hotseat icons
- ViewGroup hotseatIcons = hotseat.getShortcutsAndWidgets();
- disableClipping(hotseat);
-
- for (int i = 0; i < hotseatIcons.getChildCount(); i++) {
- View child = hotseatIcons.getChildAt(i);
- mMoveFromCenterAnimation.registerViewForAnimation(child);
- }
-
- onTransitionProgress(0f);
- }
-
- @Override
- public void onTransitionProgress(float progress) {
- mMoveFromCenterAnimation.onTransitionProgress(progress);
}
@Override
public void onTransitionFinished() {
- mMoveFromCenterAnimation.onTransitionFinished();
- mMoveFromCenterAnimation.clearRegisteredViews();
-
restoreClipping(mLauncher.getWorkspace());
mLauncher.getWorkspace().forEachVisiblePage(page -> restoreClipping((CellLayout) page));
- restoreClipping(mLauncher.getHotseat());
-
- mOriginalClipChildren.clear();
- mOriginalClipToPadding.clear();
- }
-
- private void disableClipping(ViewGroup view) {
- mOriginalClipToPadding.put(view, view.getClipToPadding());
- mOriginalClipChildren.put(view, view.getClipChildren());
- view.setClipToPadding(false);
- view.setClipChildren(false);
- }
-
- private void restoreClipping(ViewGroup view) {
- final Boolean originalClipToPadding = mOriginalClipToPadding.get(view);
- if (originalClipToPadding != null) {
- view.setClipToPadding(originalClipToPadding);
- }
- final Boolean originalClipChildren = mOriginalClipChildren.get(view);
- if (originalClipChildren != null) {
- view.setClipChildren(originalClipChildren);
- }
+ super.onTransitionFinished();
}
}
diff --git a/quickstep/src/com/android/quickstep/views/FloatingTaskView.java b/quickstep/src/com/android/quickstep/views/FloatingTaskView.java
index 325ec04..a343e0a 100644
--- a/quickstep/src/com/android/quickstep/views/FloatingTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/FloatingTaskView.java
@@ -129,9 +129,7 @@
public void update(RectF position, float progress, float windowRadius) {
MarginLayoutParams lp = (MarginLayoutParams) getLayoutParams();
- float dX = mIsRtl
- ? position.left - (lp.getMarginStart() - lp.width)
- : position.left - lp.getMarginStart();
+ float dX = position.left - lp.getMarginStart();
float dY = position.top - lp.topMargin;
setTranslationX(dX);
@@ -157,16 +155,10 @@
lp.ignoreInsets = true;
// Position the floating view exactly on top of the original
lp.topMargin = Math.round(pos.top);
- if (mIsRtl) {
- lp.setMarginStart(Math.round(mLauncher.getDeviceProfile().widthPx - pos.right));
- } else {
- lp.setMarginStart(Math.round(pos.left));
- }
+ lp.setMarginStart(Math.round(pos.left));
// Set the properties here already to make sure they are available when running the first
// animation frame.
- int left = mIsRtl
- ? mLauncher.getDeviceProfile().widthPx - lp.getMarginStart() - lp.width
- : lp.leftMargin;
+ int left = lp.leftMargin;
layout(left, lp.topMargin, left + lp.width, lp.topMargin + lp.height);
}
diff --git a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
index 00f541d..9311261 100644
--- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
@@ -157,10 +157,20 @@
@Nullable
@Override
public RunnableList launchTaskAnimated() {
- getRecentsView().getSplitPlaceholder().launchTasks(this /*groupedTaskView*/,
- null /*callback*/,
+ if (mTask == null || mSecondaryTask == null) {
+ return null;
+ }
+
+ RunnableList endCallback = new RunnableList();
+ RecentsView recentsView = getRecentsView();
+ // Callbacks run from remote animation when recents animation not currently running
+ recentsView.getSplitPlaceholder().launchTasks(this /*groupedTaskView*/,
+ success -> endCallback.executeAllAndDestroy(),
false /* freezeTaskList */);
- return null;
+
+ // Callbacks get run from recentsView for case when recents animation already running
+ recentsView.addSideTaskLaunchCallback(endCallback);
+ return endCallback;
}
@Override
@@ -248,4 +258,10 @@
super.updateSnapshotRadius();
mSnapshotView2.setFullscreenParams(mCurrentFullscreenParams);
}
+
+ @Override
+ protected void setIconAndDimTransitionProgress(float progress, boolean invert) {
+ super.setIconAndDimTransitionProgress(progress, invert);
+ mIconView2.setAlpha(mIconView.getAlpha());
+ }
}
diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
index d001690..3e06f55 100644
--- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -32,6 +32,7 @@
import androidx.annotation.Nullable;
+import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BaseQuickstepLauncher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.statehandlers.DepthController;
@@ -70,6 +71,7 @@
@Override
public void startHome() {
mActivity.getStateManager().goToState(NORMAL);
+ AbstractFloatingView.closeAllOpenViews(mActivity, mActivity.isStarted());
}
@Override
diff --git a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
index b6bf59f..81c07a6 100644
--- a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
+++ b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
@@ -22,6 +22,7 @@
import android.util.AttributeSet;
import android.view.View;
import android.view.View.OnClickListener;
+import android.widget.Button;
import android.widget.FrameLayout;
import androidx.annotation.IntDef;
@@ -80,7 +81,7 @@
private static final int INDEX_HIDDEN_FLAGS_ALPHA = 3;
private final MultiValueAlpha mMultiValueAlpha;
- private View mSplitButton;
+ private Button mSplitButton;
@ActionsHiddenFlags
private int mHiddenFlags;
@@ -215,6 +216,10 @@
mDp = dp;
updateVerticalMargin(SysUINavigationMode.getMode(getContext()));
requestLayout();
+
+ mSplitButton.setCompoundDrawablesWithIntrinsicBounds(
+ (dp.isLandscape ? R.drawable.ic_split_horizontal : R.drawable.ic_split_vertical),
+ 0, 0, 0);
}
public void setSplitButtonVisible(boolean visible) {
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index eb657c1..2ad586d 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -1041,6 +1041,17 @@
}
}
+ public boolean isTaskViewFullyVisible(TaskView tv) {
+ if (showAsGrid()) {
+ int screenStart = mOrientationHandler.getPrimaryScroll(this);
+ int screenEnd = screenStart + mOrientationHandler.getMeasuredSize(this);
+ return isTaskViewFullyWithinBounds(tv, screenStart, screenEnd);
+ } else {
+ // For now, just check if it's the active task
+ return indexOfChild(tv) == getNextPage();
+ }
+ }
+
@Nullable
private TaskView getLastGridTaskView() {
return getLastGridTaskView(getTopRowIdArray(), getBottomRowIdArray());
@@ -1087,6 +1098,15 @@
&& taskEnd <= end);
}
+ private boolean isTaskViewFullyWithinBounds(TaskView tv, int start, int end) {
+ int taskStart = mOrientationHandler.getChildStart(tv) + (int) tv.getOffsetAdjustment(
+ showAsFullscreen(), showAsGrid());
+ int taskSize = (int) (mOrientationHandler.getMeasuredSize(tv) * tv.getSizeAdjustment(
+ showAsFullscreen()));
+ int taskEnd = taskStart + taskSize;
+ return taskStart >= start && taskEnd <= end;
+ }
+
/**
* Returns true if the task is in expected scroll position.
*
@@ -1123,9 +1143,6 @@
// Reset the running task when leaving overview since it can still have a reference to
// its thumbnail
mTmpRunningTasks = null;
- if (mSplitSelectStateController.isSplitSelectActive()) {
- cancelSplitSelect(false);
- }
// Remove grouped tasks and recycle once we exit overview
int taskCount = getTaskViewCount();
for (int i = 0; i < taskCount; i++) {
@@ -1510,6 +1527,16 @@
}
}
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
+ // resetTaskVisuals is called at the end of dismiss animation which could update
+ // primary and secondary translation of the live tile cut out. We will need to do so
+ // here accordingly.
+ runActionOnRemoteHandles(remoteTargetHandle -> {
+ TaskViewSimulator simulator = remoteTargetHandle.getTaskViewSimulator();
+ simulator.taskPrimaryTranslation.value = 0;
+ simulator.taskSecondaryTranslation.value = 0;
+ simulator.fullScreenProgress.value = 0;
+ simulator.recentsViewScale.value = 1;
+ });
// Similar to setRunningTaskHidden below, reapply the state before runningTaskView is
// null.
if (!mRunningTaskShowScreenshot) {
@@ -3930,109 +3957,6 @@
pendingAnimation.buildAnim().start();
}
- public PendingAnimation cancelSplitSelect(boolean animate) {
- SplitSelectStateController splitController = mSplitSelectStateController;
- @StagePosition int stagePosition = splitController.getActiveSplitStagePosition();
- Rect initialBounds = splitController.getInitialBounds();
- splitController.resetState();
- int duration = mActivity.getStateManager().getState().getTransitionDuration(getContext());
- PendingAnimation pendingAnim = new PendingAnimation(duration);
- mSplitToast.cancel();
- mSplitUnsupportedToast.cancel();
- if (!animate) {
- resetFromSplitSelectionState();
- return pendingAnim;
- }
-
- addViewInLayout(mSplitHiddenTaskView, mSplitHiddenTaskViewIndex,
- mSplitHiddenTaskView.getLayoutParams());
- mSplitHiddenTaskView.setAlpha(0);
- int[] oldScroll = new int[getChildCount()];
- getPageScrolls(oldScroll, false,
- view -> view.getVisibility() != GONE && view != mSplitHiddenTaskView);
-
- int[] newScroll = new int[getChildCount()];
- getPageScrolls(newScroll, false, SIMPLE_SCROLL_LOGIC);
-
- boolean needsCurveUpdates = false;
- for (int i = mSplitHiddenTaskViewIndex; i >= 0; i--) {
- View child = getChildAt(i);
- if (child == mSplitHiddenTaskView) {
- TaskView taskView = (TaskView) child;
-
- int dir = mOrientationHandler.getSplitTaskViewDismissDirection(stagePosition,
- mActivity.getDeviceProfile());
- FloatProperty<TaskView> dismissingTaskViewTranslate;
- Rect hiddenBounds = new Rect(taskView.getLeft(), taskView.getTop(),
- taskView.getRight(), taskView.getBottom());
- int distanceDelta = 0;
- if (dir == PagedOrientationHandler.SPLIT_TRANSLATE_SECONDARY_NEGATIVE) {
- dismissingTaskViewTranslate = taskView
- .getSecondaryDissmissTranslationProperty();
- distanceDelta = initialBounds.top - hiddenBounds.top;
- taskView.layout(initialBounds.left, hiddenBounds.top, initialBounds.right,
- hiddenBounds.bottom);
- } else {
- dismissingTaskViewTranslate = taskView
- .getPrimaryDismissTranslationProperty();
- distanceDelta = initialBounds.left - hiddenBounds.left;
- taskView.layout(hiddenBounds.left, initialBounds.top, hiddenBounds.right,
- initialBounds.bottom);
- if (dir == PagedOrientationHandler.SPLIT_TRANSLATE_PRIMARY_POSITIVE) {
- distanceDelta *= -1;
- }
- }
- pendingAnim.add(ObjectAnimator.ofFloat(mSplitHiddenTaskView,
- dismissingTaskViewTranslate,
- distanceDelta));
- pendingAnim.add(ObjectAnimator.ofFloat(mSplitHiddenTaskView, ALPHA, 1));
- } else {
- // If insertion is on last index (furthest from clear all), we directly add the view
- // else we translate all views to the right of insertion index further right,
- // ignore views to left
- if (showAsGrid()) {
- // TODO(b/186800707) handle more elegantly for grid
- continue;
- }
- int scrollDiff = newScroll[i] - oldScroll[i];
- if (scrollDiff != 0) {
- FloatProperty translationProperty = child instanceof TaskView
- ? ((TaskView) child).getPrimaryDismissTranslationProperty()
- : mOrientationHandler.getPrimaryViewTranslate();
-
- ResourceProvider rp = DynamicResource.provider(mActivity);
- SpringProperty sp = new SpringProperty(SpringProperty.FLAG_CAN_SPRING_ON_END)
- .setDampingRatio(
- rp.getFloat(R.dimen.dismiss_task_trans_x_damping_ratio))
- .setStiffness(rp.getFloat(R.dimen.dismiss_task_trans_x_stiffness));
- pendingAnim.add(ObjectAnimator.ofFloat(child, translationProperty, scrollDiff)
- .setDuration(duration), ACCEL, sp);
- needsCurveUpdates = true;
- }
- }
- }
-
- if (needsCurveUpdates) {
- pendingAnim.addOnFrameCallback(this::updateCurveProperties);
- }
-
- pendingAnim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- // TODO(b/186800707) Figure out how to undo for grid view
- // Need to handle cases where dismissed task is
- // * Top Row
- // * Bottom Row
- // * Focused Task
- updateGridProperties();
- resetFromSplitSelectionState();
- updateScrollSynchronously();
- }
- });
-
- return pendingAnim;
- }
-
/** TODO(b/181707736) More gracefully handle exiting split selection state */
private void resetFromSplitSelectionState() {
if (!mActivity.getDeviceProfile().overviewShowAsGrid) {
@@ -4950,6 +4874,62 @@
}
@Override
+ public boolean scrollLeft() {
+ if (!showAsGrid()) {
+ return super.scrollLeft();
+ }
+
+ int targetPage = getNextPage();
+ if (targetPage >= 0) {
+ // Find the next page that is not fully visible.
+ TaskView taskView = getTaskViewAt(targetPage);
+ while ((taskView == null || isTaskViewFullyVisible(taskView)) && targetPage - 1 >= 0) {
+ taskView = getTaskViewAt(--targetPage);
+ }
+ // Target a scroll where targetPage is on left of screen but still fully visible.
+ int lastTaskEnd = (mIsRtl
+ ? mLastComputedGridSize.left
+ : mLastComputedGridSize.right)
+ + (mIsRtl ? mPageSpacing : -mPageSpacing);
+ int normalTaskEnd = mIsRtl
+ ? mLastComputedGridTaskSize.left
+ : mLastComputedGridTaskSize.right;
+ int targetScroll = getScrollForPage(targetPage) + normalTaskEnd - lastTaskEnd;
+ // Find a page that is close to targetScroll while not over it.
+ while (targetPage - 1 >= 0
+ && (mIsRtl
+ ? getScrollForPage(targetPage - 1) < targetScroll
+ : getScrollForPage(targetPage - 1) > targetScroll)) {
+ targetPage--;
+ }
+ snapToPage(targetPage);
+ return true;
+ }
+
+ return mAllowOverScroll;
+ }
+
+ @Override
+ public boolean scrollRight() {
+ if (!showAsGrid()) {
+ return super.scrollRight();
+ }
+
+ int targetPage = getNextPage();
+ if (targetPage < getChildCount()) {
+ // Find the next page that is not fully visible.
+ TaskView taskView = getTaskViewAt(targetPage);
+ while ((taskView != null && isTaskViewFullyVisible(taskView))
+ && targetPage + 1 < getChildCount()) {
+ taskView = getTaskViewAt(++targetPage);
+ }
+ snapToPage(targetPage);
+ return true;
+ }
+ return mAllowOverScroll;
+ }
+
+ @Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
dispatchScrollChanged();
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index e8077cf..467d225 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -599,7 +599,9 @@
if (confirmSecondSplitSelectApp()) {
return;
}
- if (ENABLE_QUICKSTEP_LIVE_TILE.get() && isRunningTask()) {
+ RecentsView recentsView = getRecentsView();
+ RemoteTargetHandle[] remoteTargetHandles = recentsView.mRemoteTargetHandles;
+ if (ENABLE_QUICKSTEP_LIVE_TILE.get() && isRunningTask() && remoteTargetHandles != null) {
if (!mIsClickableAsLiveTile) {
return;
}
@@ -612,9 +614,7 @@
}
mIsClickableAsLiveTile = false;
- RecentsView recentsView = getRecentsView();
RemoteAnimationTargets targets;
- RemoteTargetHandle[] remoteTargetHandles = recentsView.mRemoteTargetHandles;
if (remoteTargetHandles.length == 1) {
targets = remoteTargetHandles[0].getTransformParams().getTargetSet();
} else {
@@ -912,7 +912,7 @@
return deviceProfile.overviewShowAsGrid && !isFocusedTask();
}
- private void setIconAndDimTransitionProgress(float progress, boolean invert) {
+ protected void setIconAndDimTransitionProgress(float progress, boolean invert) {
if (invert) {
progress = 1 - progress;
}
diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java
new file mode 100644
index 0000000..ba1a60d
--- /dev/null
+++ b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java
@@ -0,0 +1,159 @@
+package com.android.launcher3.taskbar;
+
+import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_A11Y;
+import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_BACK;
+import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_HOME;
+import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_IME_SWITCH;
+import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_RECENTS;
+import static com.android.launcher3.taskbar.TaskbarNavButtonController.SCREEN_PIN_LONG_PRESS_THRESHOLD;
+import static com.android.quickstep.OverviewCommandHelper.TYPE_HOME;
+import static com.android.quickstep.OverviewCommandHelper.TYPE_TOGGLE;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.os.Handler;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.quickstep.OverviewCommandHelper;
+import com.android.quickstep.SystemUiProxy;
+import com.android.quickstep.TouchInteractionService;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+public class TaskbarNavButtonControllerTest {
+
+ private final static int DISPLAY_ID = 2;
+
+ @Mock
+ SystemUiProxy mockSystemUiProxy;
+ @Mock
+ TouchInteractionService mockService;
+ @Mock
+ OverviewCommandHelper mockCommandHelper;
+ @Mock
+ Handler mockHandler;
+
+ private TaskbarNavButtonController mNavButtonController;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ when(mockService.getDisplayId()).thenReturn(DISPLAY_ID);
+ when(mockService.getOverviewCommandHelper()).thenReturn(mockCommandHelper);
+ mNavButtonController = new TaskbarNavButtonController(mockService,
+ mockSystemUiProxy, mockHandler);
+ }
+
+ @Test
+ public void testPressBack() {
+ mNavButtonController.onButtonClick(BUTTON_BACK);
+ verify(mockSystemUiProxy, times(1)).onBackPressed();
+ }
+
+ @Test
+ public void testPressImeSwitcher() {
+ mNavButtonController.onButtonClick(BUTTON_IME_SWITCH);
+ verify(mockSystemUiProxy, times(1)).onImeSwitcherPressed();
+ }
+
+ @Test
+ public void testPressA11yShortClick() {
+ mNavButtonController.onButtonClick(BUTTON_A11Y);
+ verify(mockSystemUiProxy, times(1))
+ .notifyAccessibilityButtonClicked(DISPLAY_ID);
+ }
+
+ @Test
+ public void testPressA11yLongClick() {
+ mNavButtonController.onButtonLongClick(BUTTON_A11Y);
+ verify(mockSystemUiProxy, times(1)).notifyAccessibilityButtonLongClicked();
+ }
+
+ @Test
+ public void testLongPressHome() {
+ mNavButtonController.onButtonLongClick(BUTTON_HOME);
+ verify(mockSystemUiProxy, times(1)).startAssistant(any());
+ }
+
+ @Test
+ public void testPressHome() {
+ mNavButtonController.onButtonClick(BUTTON_HOME);
+ verify(mockCommandHelper, times(1)).addCommand(TYPE_HOME);
+ }
+
+ @Test
+ public void testPressRecents() {
+ mNavButtonController.onButtonClick(BUTTON_RECENTS);
+ verify(mockCommandHelper, times(1)).addCommand(TYPE_TOGGLE);
+ }
+
+ @Test
+ public void testPressRecentsWithScreenPinned() {
+ mNavButtonController.updateSysuiFlags(SYSUI_STATE_SCREEN_PINNING);
+ mNavButtonController.onButtonClick(BUTTON_RECENTS);
+ verify(mockCommandHelper, times(0)).addCommand(TYPE_TOGGLE);
+ }
+
+ @Test
+ public void testLongPressBackRecentsNotPinned() {
+ mNavButtonController.onButtonLongClick(BUTTON_RECENTS);
+ mNavButtonController.onButtonLongClick(BUTTON_BACK);
+ verify(mockSystemUiProxy, times(0)).stopScreenPinning();
+ }
+
+ @Test
+ public void testLongPressBackRecentsPinned() {
+ mNavButtonController.updateSysuiFlags(SYSUI_STATE_SCREEN_PINNING);
+ mNavButtonController.onButtonLongClick(BUTTON_RECENTS);
+ mNavButtonController.onButtonLongClick(BUTTON_BACK);
+ verify(mockSystemUiProxy, times(1)).stopScreenPinning();
+ }
+
+ @Test
+ public void testLongPressBackRecentsTooLongPinned() {
+ mNavButtonController.updateSysuiFlags(SYSUI_STATE_SCREEN_PINNING);
+ mNavButtonController.onButtonLongClick(BUTTON_RECENTS);
+ try {
+ Thread.sleep(SCREEN_PIN_LONG_PRESS_THRESHOLD + 5);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ mNavButtonController.onButtonLongClick(BUTTON_BACK);
+ verify(mockSystemUiProxy, times(0)).stopScreenPinning();
+ }
+
+ @Test
+ public void testLongPressBackRecentsMultipleAttemptPinned() {
+ mNavButtonController.updateSysuiFlags(SYSUI_STATE_SCREEN_PINNING);
+ mNavButtonController.onButtonLongClick(BUTTON_RECENTS);
+ try {
+ Thread.sleep(SCREEN_PIN_LONG_PRESS_THRESHOLD + 5);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ mNavButtonController.onButtonLongClick(BUTTON_BACK);
+ verify(mockSystemUiProxy, times(0)).stopScreenPinning();
+
+ // Try again w/in threshold
+ mNavButtonController.onButtonLongClick(BUTTON_RECENTS);
+ mNavButtonController.onButtonLongClick(BUTTON_BACK);
+ verify(mockSystemUiProxy, times(1)).stopScreenPinning();
+ }
+
+ @Test
+ public void testLongPressHomeScreenPinned() {
+ mNavButtonController.updateSysuiFlags(SYSUI_STATE_SCREEN_PINNING);
+ mNavButtonController.onButtonLongClick(BUTTON_HOME);
+ verify(mockSystemUiProxy, times(0)).startAssistant(any());
+ }
+}
diff --git a/res/drawable/ic_split_horizontal.xml b/res/drawable/ic_split_horizontal.xml
new file mode 100644
index 0000000..ee710d0
--- /dev/null
+++ b/res/drawable/ic_split_horizontal.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="20dp"
+ android:height="16dp"
+ android:viewportWidth="20"
+ android:viewportHeight="16">
+ <path
+ android:pathData="M18,14L13,14L13,2L18,2L18,14ZM20,14L20,2C20,0.9 19.1,-0 18,-0L13,-0C11.9,-0 11,0.9 11,2L11,14C11,15.1 11.9,16 13,16L18,16C19.1,16 20,15.1 20,14ZM7,14L2,14L2,2L7,2L7,14ZM9,14L9,2C9,0.9 8.1,-0 7,-0L2,-0C0.9,-0 -0,0.9 -0,2L-0,14C-0,15.1 0.9,16 2,16L7,16C8.1,16 9,15.1 9,14Z"
+ android:fillColor="#000000"/>
+</vector>
diff --git a/res/drawable/ic_split_left.xml b/res/drawable/ic_split_left.xml
new file mode 100644
index 0000000..fc9f699
--- /dev/null
+++ b/res/drawable/ic_split_left.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="20dp"
+ android:height="16dp"
+ android:viewportWidth="20"
+ android:viewportHeight="16">
+ <path
+ android:pathData="M-0,2L-0,14C-0,15.1 0.9,16 2,16L7,16C8.1,16 9,15.1 9,14L9,2C9,0.9 8.1,-0 7,-0L2,-0C0.9,-0 -0,0.9 -0,2ZM13,2L18,2L18,14L13,14L13,2ZM11,2L11,14C11,15.1 11.9,16 13,16L18,16C19.1,16 20,15.1 20,14L20,2C20,0.9 19.1,-0 18,-0L13,-0C11.9,-0 11,0.9 11,2Z"
+ android:fillColor="#000000"/>
+</vector>
diff --git a/res/drawable/ic_split_right.xml b/res/drawable/ic_split_right.xml
new file mode 100644
index 0000000..cc15622
--- /dev/null
+++ b/res/drawable/ic_split_right.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="20dp"
+ android:height="16dp"
+ android:viewportWidth="20"
+ android:viewportHeight="16">
+ <path
+ android:pathData="M20,14L20,2C20,0.9 19.1,-0 18,-0L13,-0C11.9,-0 11,0.9 11,2L11,14C11,15.1 11.9,16 13,16L18,16C19.1,16 20,15.1 20,14ZM7,14L2,14L2,2L7,2L7,14ZM9,14L9,2C9,0.9 8.1,-0 7,-0L2,-0C0.9,-0 -0,0.9 -0,2L-0,14C-0,15.1 0.9,16 2,16L7,16C8.1,16 9,15.1 9,14Z"
+ android:fillColor="#000000"/>
+</vector>
diff --git a/res/drawable/ic_split_top.xml b/res/drawable/ic_split_top.xml
new file mode 100644
index 0000000..f8c15bd
--- /dev/null
+++ b/res/drawable/ic_split_top.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="16dp"
+ android:height="20dp"
+ android:viewportWidth="16"
+ android:viewportHeight="20">
+ <path
+ android:pathData="M14,0H2C0.9,0 0,0.9 0,2V7C0,8.1 0.9,9 2,9H14C15.1,9 16,8.1 16,7V2C16,0.9 15.1,0 14,0ZM14,13V18H2V13H14ZM14,11H2C0.9,11 0,11.9 0,13V18C0,19.1 0.9,20 2,20H14C15.1,20 16,19.1 16,18V13C16,11.9 15.1,11 14,11Z"
+ android:fillColor="#000000"/>
+</vector>
diff --git a/res/drawable/ic_split_vertical.xml b/res/drawable/ic_split_vertical.xml
new file mode 100644
index 0000000..9bc9785
--- /dev/null
+++ b/res/drawable/ic_split_vertical.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:pathData="M18,4V9H6V4H18ZM18,2H6C4.9,2 4,2.9 4,4V9C4,10.1 4.9,11 6,11H18C19.1,11 20,10.1 20,9V4C20,2.9 19.1,2 18,2ZM18,15V20H6V15H18ZM18,13H6C4.9,13 4,13.9 4,15V20C4,21.1 4.9,22 6,22H18C19.1,22 20,21.1 20,20V15C20,13.9 19.1,13 18,13Z"
+ android:fillColor="#000000"/>
+</vector>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index ea6ddbe..878ef3f 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -329,6 +329,9 @@
<!-- Size of the maximum radius for the enforced rounded rectangles. -->
<dimen name="enforced_rounded_corner_max_radius">16dp</dimen>
+<!-- Base Swipe Detector, speed in dp/s -->
+ <dimen name="base_swift_detector_fling_release_velocity">1dp</dimen>
+
<!-- Overview placeholder to compile in Launcher3 without Quickstep -->
<dimen name="task_thumbnail_icon_size">0dp</dimen>
<dimen name="task_thumbnail_icon_drawable_size">0dp</dimen>
diff --git a/src/com/android/launcher3/AutoInstallsLayout.java b/src/com/android/launcher3/AutoInstallsLayout.java
index 5b655a4..64666b0 100644
--- a/src/com/android/launcher3/AutoInstallsLayout.java
+++ b/src/com/android/launcher3/AutoInstallsLayout.java
@@ -27,9 +27,7 @@
import android.database.sqlite.SQLiteDatabase;
import android.graphics.drawable.Drawable;
import android.net.Uri;
-import android.os.Build.VERSION;
import android.os.Bundle;
-import android.os.Process;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.AttributeSet;
@@ -449,7 +447,7 @@
// Auto installs should always support the current platform version.
LauncherIcons li = LauncherIcons.obtain(mContext);
mValues.put(LauncherSettings.Favorites.ICON, GraphicsUtils.flattenBitmap(
- li.createBadgedIconBitmap(icon, Process.myUserHandle(), VERSION.SDK_INT).icon));
+ li.createBadgedIconBitmap(icon).icon));
li.recycle();
mValues.put(Favorites.ICON_PACKAGE, mIconRes.getResourcePackageName(iconId));
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 5a6365a..5d41741 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -18,6 +18,8 @@
import static com.android.launcher3.config.FeatureFlags.ENABLE_ICON_LABEL_AUTO_SCALING;
import static com.android.launcher3.graphics.PreloadIconDrawable.newPendingIcon;
+import static com.android.launcher3.icons.BitmapInfo.FLAG_NO_BADGE;
+import static com.android.launcher3.icons.BitmapInfo.FLAG_THEMED;
import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
import android.animation.Animator;
@@ -48,7 +50,7 @@
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
-import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
+import com.android.launcher3.accessibility.BaseAccessibilityDelegate;
import com.android.launcher3.dot.DotInfo;
import com.android.launcher3.dragndrop.DraggableView;
import com.android.launcher3.folder.FolderIcon;
@@ -145,6 +147,8 @@
private final int mIconSize;
@ViewDebug.ExportedProperty(category = "launcher")
+ private boolean mHideBadge = false;
+ @ViewDebug.ExportedProperty(category = "launcher")
private boolean mIsIconVisible = true;
@ViewDebug.ExportedProperty(category = "launcher")
private int mTextColor;
@@ -241,6 +245,10 @@
super.onFocusChanged(focused, direction, previouslyFocusedRect);
}
+ public void setHideBadge(boolean hideBadge) {
+ mHideBadge = hideBadge;
+ }
+
/**
* Resets the view so it can be recycled.
*/
@@ -296,7 +304,7 @@
@Override
public void setAccessibilityDelegate(AccessibilityDelegate delegate) {
- if (delegate instanceof LauncherAccessibilityDelegate) {
+ if (delegate instanceof BaseAccessibilityDelegate) {
super.setAccessibilityDelegate(delegate);
} else {
// NO-OP
@@ -364,7 +372,11 @@
protected void applyIconAndLabel(ItemInfoWithIcon info) {
boolean useTheme = mDisplay == DISPLAY_WORKSPACE || mDisplay == DISPLAY_FOLDER
|| mDisplay == DISPLAY_TASKBAR;
- FastBitmapDrawable iconDrawable = info.newIcon(getContext(), useTheme);
+ int flags = useTheme ? FLAG_THEMED : 0;
+ if (mHideBadge) {
+ flags |= FLAG_NO_BADGE;
+ }
+ FastBitmapDrawable iconDrawable = info.newIcon(getContext(), flags);
mDotParams.color = IconPalette.getMutedColor(iconDrawable.getIconColor(), 0.54f);
setIcon(iconDrawable);
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 0656125..ab9b980 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -115,8 +115,8 @@
import androidx.annotation.VisibleForTesting;
import com.android.launcher3.DropTarget.DragObject;
+import com.android.launcher3.accessibility.BaseAccessibilityDelegate.LauncherAction;
import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
-import com.android.launcher3.accessibility.LauncherAccessibilityDelegate.LauncherAction;
import com.android.launcher3.allapps.AllAppsContainerView;
import com.android.launcher3.allapps.AllAppsStore;
import com.android.launcher3.allapps.AllAppsTransitionController;
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 1ce7ebe..2c14f07 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -1749,20 +1749,23 @@
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
final boolean pagesFlipped = isPageOrderFlipped();
- int offset = (mAllowOverScroll ? 0 : 1);
- info.setScrollable(getPageCount() > offset);
- if (getCurrentPage() < getPageCount() - offset) {
+ info.setScrollable(getPageCount() > 0);
+ int primaryScroll = mOrientationHandler.getPrimaryScroll(this);
+ if (getCurrentPage() < getPageCount() - getPanelCount()
+ || (getCurrentPage() == getPageCount() - getPanelCount()
+ && primaryScroll != getScrollForPage(getPageCount() - getPanelCount()))) {
info.addAction(pagesFlipped ?
- AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_BACKWARD
- : AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD);
+ AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_BACKWARD
+ : AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD);
info.addAction(mIsRtl ?
AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_LEFT
: AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_RIGHT);
}
- if (getCurrentPage() >= offset) {
+ if (getCurrentPage() > 0
+ || (getCurrentPage() == 0 && primaryScroll != getScrollForPage(0))) {
info.addAction(pagesFlipped ?
- AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD
- : AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_BACKWARD);
+ AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD
+ : AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_BACKWARD);
info.addAction(mIsRtl ?
AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_RIGHT
: AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_LEFT);
@@ -1807,16 +1810,16 @@
} break;
case android.R.id.accessibilityActionPageRight: {
if (!mIsRtl) {
- return scrollRight();
+ return scrollRight();
} else {
- return scrollLeft();
+ return scrollLeft();
}
}
case android.R.id.accessibilityActionPageLeft: {
if (!mIsRtl) {
- return scrollLeft();
+ return scrollLeft();
} else {
- return scrollRight();
+ return scrollRight();
}
}
}
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index d2fe483..ac194d2 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -16,6 +16,7 @@
package com.android.launcher3;
+import static com.android.launcher3.icons.BitmapInfo.FLAG_THEMED;
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_ICON_BADGED;
import android.annotation.TargetApi;
@@ -36,7 +37,6 @@
import android.content.res.Configuration;
import android.content.res.Resources;
import android.database.ContentObserver;
-import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.LightingColorFilter;
@@ -48,12 +48,12 @@
import android.graphics.drawable.AdaptiveIconDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
-import android.graphics.drawable.InsetDrawable;
import android.net.Uri;
import android.os.Build;
import android.os.DeadObjectException;
import android.os.Handler;
import android.os.Message;
+import android.os.Process;
import android.os.TransactionTooLargeException;
import android.provider.Settings;
import android.text.Spannable;
@@ -78,7 +78,6 @@
import com.android.launcher3.graphics.TintedDrawableSpan;
import com.android.launcher3.icons.BitmapInfo;
import com.android.launcher3.icons.FastBitmapDrawable;
-import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.icons.ShortcutCachingLogic;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.ItemInfoWithIcon;
@@ -110,8 +109,6 @@
private static final Pattern sTrimPattern =
Pattern.compile("^[\\s|\\p{javaSpaceChar}]*(.*)[\\s|\\p{javaSpaceChar}]*$");
- private static final float[] sTmpFloatArray = new float[4];
-
private static final int[] sLoc0 = new int[2];
private static final int[] sLoc1 = new int[2];
private static final Matrix sMatrix = new Matrix();
@@ -738,27 +735,23 @@
@TargetApi(Build.VERSION_CODES.O)
public static Drawable getBadge(Context context, ItemInfo info, Object obj) {
LauncherAppState appState = LauncherAppState.getInstance(context);
- int iconSize = appState.getInvariantDeviceProfile().iconBitmapSize;
if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
boolean iconBadged = (info instanceof ItemInfoWithIcon)
&& (((ItemInfoWithIcon) info).runtimeStatusFlags & FLAG_ICON_BADGED) > 0;
if ((info.id == ItemInfo.NO_ID && !iconBadged)
|| !(obj instanceof ShortcutInfo)) {
// The item is not yet added on home screen.
- return new FixedSizeEmptyDrawable(iconSize);
+ return new ColorDrawable(Color.TRANSPARENT);
}
ShortcutInfo si = (ShortcutInfo) obj;
- Bitmap badge = LauncherAppState.getInstance(appState.getContext())
- .getIconCache().getShortcutInfoBadge(si).icon;
- float badgeSize = LauncherIcons.getBadgeSizeForIconSize(iconSize);
- float insetFraction = (iconSize - badgeSize) / iconSize;
- return new InsetDrawable(new FastBitmapDrawable(badge),
- insetFraction, insetFraction, 0, 0);
+ return LauncherAppState.getInstance(appState.getContext())
+ .getIconCache().getShortcutInfoBadge(si).newIcon(context, FLAG_THEMED);
} else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) {
return ((FolderAdaptiveIcon) obj).getBadge();
} else {
- return context.getPackageManager()
- .getUserBadgedIcon(new FixedSizeEmptyDrawable(iconSize), info.user);
+ return Process.myUserHandle().equals(info.user)
+ ? new ColorDrawable(Color.TRANSPARENT)
+ : context.getDrawable(R.drawable.ic_work_app_badge);
}
}
@@ -864,24 +857,4 @@
v.getLocationOnScreen(pos);
return new Rect(pos[0], pos[1], pos[0] + v.getWidth(), pos[1] + v.getHeight());
}
-
- private static class FixedSizeEmptyDrawable extends ColorDrawable {
-
- private final int mSize;
-
- public FixedSizeEmptyDrawable(int size) {
- super(Color.TRANSPARENT);
- mSize = size;
- }
-
- @Override
- public int getIntrinsicHeight() {
- return mSize;
- }
-
- @Override
- public int getIntrinsicWidth() {
- return mSize;
- }
- }
}
diff --git a/src/com/android/launcher3/accessibility/BaseAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/BaseAccessibilityDelegate.java
new file mode 100644
index 0000000..14b2431
--- /dev/null
+++ b/src/com/android/launcher3/accessibility/BaseAccessibilityDelegate.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2021 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.accessibility;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.util.SparseArray;
+import android.view.View;
+import android.view.accessibility.AccessibilityNodeInfo;
+
+import com.android.launcher3.DropTarget;
+import com.android.launcher3.LauncherSettings;
+import com.android.launcher3.dragndrop.DragController;
+import com.android.launcher3.dragndrop.DragOptions;
+import com.android.launcher3.model.data.FolderInfo;
+import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.model.data.LauncherAppWidgetInfo;
+import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.popup.PopupContainerWithArrow;
+import com.android.launcher3.util.Thunk;
+import com.android.launcher3.views.ActivityContext;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public abstract class BaseAccessibilityDelegate<T extends Context & ActivityContext>
+ extends View.AccessibilityDelegate implements DragController.DragListener {
+
+ public enum DragType {
+ ICON,
+ FOLDER,
+ WIDGET
+ }
+
+ public static class DragInfo {
+ public DragType dragType;
+ public ItemInfo info;
+ public View item;
+ }
+
+ protected final SparseArray<LauncherAction> mActions = new SparseArray<>();
+ protected final T mContext;
+
+ protected DragInfo mDragInfo = null;
+
+ protected BaseAccessibilityDelegate(T context) {
+ mContext = context;
+ }
+
+ @Override
+ public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(host, info);
+ if (host.getTag() instanceof ItemInfo) {
+ ItemInfo item = (ItemInfo) host.getTag();
+
+ List<LauncherAction> actions = new ArrayList<>();
+ getSupportedActions(host, item, actions);
+ actions.forEach(la -> info.addAction(la.accessibilityAction));
+
+ if (!itemSupportsLongClick(host, item)) {
+ info.setLongClickable(false);
+ info.removeAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_LONG_CLICK);
+ }
+ }
+ }
+
+ /**
+ * Adds all the accessibility actions that can be handled.
+ */
+ protected abstract void getSupportedActions(View host, ItemInfo item, List<LauncherAction> out);
+
+ private boolean itemSupportsLongClick(View host, ItemInfo info) {
+ return PopupContainerWithArrow.canShow(host, info);
+ }
+
+ protected boolean itemSupportsAccessibleDrag(ItemInfo item) {
+ if (item instanceof WorkspaceItemInfo) {
+ // Support the action unless the item is in a context menu.
+ return item.screenId >= 0
+ && item.container != LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
+ }
+ return (item instanceof LauncherAppWidgetInfo)
+ || (item instanceof FolderInfo);
+ }
+
+ @Override
+ public boolean performAccessibilityAction(View host, int action, Bundle args) {
+ if ((host.getTag() instanceof ItemInfo)
+ && performAction(host, (ItemInfo) host.getTag(), action, false)) {
+ return true;
+ }
+ return super.performAccessibilityAction(host, action, args);
+ }
+
+ protected abstract boolean performAction(
+ View host, ItemInfo item, int action, boolean fromKeyboard);
+
+ @Thunk
+ protected void announceConfirmation(String confirmation) {
+ mContext.getDragLayer().announceForAccessibility(confirmation);
+
+ }
+
+ public boolean isInAccessibleDrag() {
+ return mDragInfo != null;
+ }
+
+ public DragInfo getDragInfo() {
+ return mDragInfo;
+ }
+
+ /**
+ * @param clickedTarget the actual view that was clicked
+ * @param dropLocation relative to {@param clickedTarget}. If provided, its center is used
+ * as the actual drop location otherwise the views center is used.
+ */
+ public void handleAccessibleDrop(View clickedTarget, Rect dropLocation,
+ String confirmation) {
+ if (!isInAccessibleDrag()) return;
+
+ int[] loc = new int[2];
+ if (dropLocation == null) {
+ loc[0] = clickedTarget.getWidth() / 2;
+ loc[1] = clickedTarget.getHeight() / 2;
+ } else {
+ loc[0] = dropLocation.centerX();
+ loc[1] = dropLocation.centerY();
+ }
+
+ mContext.getDragLayer().getDescendantCoordRelativeToSelf(clickedTarget, loc);
+ mContext.getDragController().completeAccessibleDrag(loc);
+
+ if (!TextUtils.isEmpty(confirmation)) {
+ announceConfirmation(confirmation);
+ }
+ }
+
+ protected abstract boolean beginAccessibleDrag(View item, ItemInfo info, boolean fromKeyboard);
+
+
+ @Override
+ public void onDragEnd() {
+ mContext.getDragController().removeDragListener(this);
+ mDragInfo = null;
+ }
+
+ @Override
+ public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) {
+ // No-op
+ }
+
+ public class LauncherAction {
+ public final int keyCode;
+ public final AccessibilityNodeInfo.AccessibilityAction accessibilityAction;
+
+ private final BaseAccessibilityDelegate<T> mDelegate;
+
+ public LauncherAction(int id, int labelRes, int keyCode) {
+ this.keyCode = keyCode;
+ accessibilityAction = new AccessibilityNodeInfo.AccessibilityAction(
+ id, mContext.getString(labelRes));
+ mDelegate = BaseAccessibilityDelegate.this;
+ }
+
+ /**
+ * Invokes the action for the provided host
+ */
+ public boolean invokeFromKeyboard(View host) {
+ if (host != null && host.getTag() instanceof ItemInfo) {
+ return mDelegate.performAction(
+ host, (ItemInfo) host.getTag(), accessibilityAction.getId(), true);
+ } else {
+ return false;
+ }
+ }
+ }
+}
diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
index 157df5d..18c05eb 100644
--- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
@@ -10,27 +10,19 @@
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.RectF;
-import android.os.Bundle;
import android.os.Handler;
-import android.text.TextUtils;
import android.util.Log;
-import android.util.SparseArray;
import android.view.KeyEvent;
import android.view.View;
-import android.view.View.AccessibilityDelegate;
-import android.view.accessibility.AccessibilityNodeInfo;
-import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.ButtonDropTarget;
import com.android.launcher3.CellLayout;
-import com.android.launcher3.DropTarget.DragObject;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.PendingAddItemInfo;
import com.android.launcher3.R;
import com.android.launcher3.Workspace;
-import com.android.launcher3.dragndrop.DragController.DragListener;
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.dragndrop.DragView;
import com.android.launcher3.folder.Folder;
@@ -57,7 +49,7 @@
import java.util.Collections;
import java.util.List;
-public class LauncherAccessibilityDelegate extends AccessibilityDelegate implements DragListener {
+public class LauncherAccessibilityDelegate extends BaseAccessibilityDelegate<Launcher> {
private static final String TAG = "LauncherAccessibilityDelegate";
@@ -73,25 +65,8 @@
public static final int DEEP_SHORTCUTS = R.id.action_deep_shortcuts;
public static final int SHORTCUTS_AND_NOTIFICATIONS = R.id.action_shortcuts_and_notifications;
- public enum DragType {
- ICON,
- FOLDER,
- WIDGET
- }
-
- public static class DragInfo {
- public DragType dragType;
- public ItemInfo info;
- public View item;
- }
-
- protected final SparseArray<LauncherAction> mActions = new SparseArray<>();
- protected final Launcher mLauncher;
-
- private DragInfo mDragInfo = null;
-
public LauncherAccessibilityDelegate(Launcher launcher) {
- mLauncher = launcher;
+ super(launcher);
mActions.put(REMOVE, new LauncherAction(
REMOVE, R.string.remove_drop_target_label, KeyEvent.KEYCODE_X));
@@ -116,25 +91,6 @@
}
@Override
- public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
- super.onInitializeAccessibilityNodeInfo(host, info);
- if (host.getTag() instanceof ItemInfo) {
- ItemInfo item = (ItemInfo) host.getTag();
-
- List<LauncherAction> actions = new ArrayList<>();
- getSupportedActions(host, item, actions);
- actions.forEach(la -> info.addAction(la.accessibilityAction));
-
- if (!itemSupportsLongClick(host, item)) {
- info.setLongClickable(false);
- info.removeAction(AccessibilityAction.ACTION_LONG_CLICK);
- }
- }
- }
-
- /**
- * Adds all the accessibility actions that can be handled.
- */
protected void getSupportedActions(View host, ItemInfo item, List<LauncherAction> out) {
// If the request came from keyboard, do not add custom shortcuts as that is already
// exposed as a direct shortcut
@@ -143,7 +99,7 @@
? SHORTCUTS_AND_NOTIFICATIONS : DEEP_SHORTCUTS));
}
- for (ButtonDropTarget target : mLauncher.getDropTargetBar().getDropTargets()) {
+ for (ButtonDropTarget target : mContext.getDropTargetBar().getDropTargets()) {
if (target.supportsAccessibilityDrop(item, host)) {
out.add(mActions.get(target.getAccessibilityAction()));
}
@@ -183,31 +139,7 @@
return result;
}
- private boolean itemSupportsLongClick(View host, ItemInfo info) {
- return PopupContainerWithArrow.canShow(host, info);
- }
-
- private boolean itemSupportsAccessibleDrag(ItemInfo item) {
- if (item instanceof WorkspaceItemInfo) {
- // Support the action unless the item is in a context menu.
- return item.screenId >= 0 && item.container != Favorites.CONTAINER_HOTSEAT_PREDICTION;
- }
- return (item instanceof LauncherAppWidgetInfo)
- || (item instanceof FolderInfo);
- }
-
@Override
- public boolean performAccessibilityAction(View host, int action, Bundle args) {
- if ((host.getTag() instanceof ItemInfo)
- && performAction(host, (ItemInfo) host.getTag(), action, false)) {
- return true;
- }
- return super.performAccessibilityAction(host, action, args);
- }
-
- /**
- * Performs the provided action on the host
- */
protected boolean performAction(final View host, final ItemInfo item, int action,
boolean fromKeyboard) {
if (action == ACTION_LONG_CLICK) {
@@ -226,36 +158,36 @@
if (screenId == -1) {
return false;
}
- mLauncher.getStateManager().goToState(NORMAL, true, forSuccessCallback(() -> {
+ mContext.getStateManager().goToState(NORMAL, true, forSuccessCallback(() -> {
if (item instanceof AppInfo) {
WorkspaceItemInfo info = ((AppInfo) item).makeWorkspaceItem();
- mLauncher.getModelWriter().addItemToDatabase(info,
+ mContext.getModelWriter().addItemToDatabase(info,
Favorites.CONTAINER_DESKTOP,
screenId, coordinates[0], coordinates[1]);
- mLauncher.bindItems(
+ mContext.bindItems(
Collections.singletonList(info),
/* forceAnimateIcons= */ true,
/* focusFirstItemForAccessibility= */ true);
announceConfirmation(R.string.item_added_to_workspace);
} else if (item instanceof PendingAddItemInfo) {
PendingAddItemInfo info = (PendingAddItemInfo) item;
- Workspace workspace = mLauncher.getWorkspace();
+ Workspace workspace = mContext.getWorkspace();
workspace.snapToPage(workspace.getPageIndexForScreenId(screenId));
- mLauncher.addPendingItem(info, Favorites.CONTAINER_DESKTOP,
+ mContext.addPendingItem(info, Favorites.CONTAINER_DESKTOP,
screenId, coordinates, info.spanX, info.spanY);
}
else if (item instanceof WorkspaceItemInfo) {
WorkspaceItemInfo info = ((WorkspaceItemInfo) item).clone();
- mLauncher.getModelWriter().addItemToDatabase(info,
+ mContext.getModelWriter().addItemToDatabase(info,
Favorites.CONTAINER_DESKTOP,
screenId, coordinates[0], coordinates[1]);
- mLauncher.bindItems(Collections.singletonList(info), true, true);
+ mContext.bindItems(Collections.singletonList(info), true, true);
}
}));
return true;
} else if (action == MOVE_TO_WORKSPACE) {
- Folder folder = Folder.getOpen(mLauncher);
+ Folder folder = Folder.getOpen(mContext);
folder.close(true);
WorkspaceItemInfo info = (WorkspaceItemInfo) item;
folder.getInfo().remove(info, false);
@@ -265,14 +197,14 @@
if (screenId == -1) {
return false;
}
- mLauncher.getModelWriter().moveItemInDatabase(info,
+ mContext.getModelWriter().moveItemInDatabase(info,
Favorites.CONTAINER_DESKTOP,
screenId, coordinates[0], coordinates[1]);
// Bind the item in next frame so that if a new workspace page was created,
// it will get laid out.
new Handler().post(() -> {
- mLauncher.bindItems(Collections.singletonList(item), true);
+ mContext.bindItems(Collections.singletonList(item), true);
announceConfirmation(R.string.item_moved);
});
return true;
@@ -280,15 +212,15 @@
final LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) item;
List<OptionItem> actions = getSupportedResizeActions(host, info);
Rect pos = new Rect();
- mLauncher.getDragLayer().getDescendantRectRelativeToSelf(host, pos);
- ArrowPopup popup = OptionsPopupView.show(mLauncher, new RectF(pos), actions, false);
+ mContext.getDragLayer().getDescendantRectRelativeToSelf(host, pos);
+ ArrowPopup popup = OptionsPopupView.show(mContext, new RectF(pos), actions, false);
popup.requestFocus();
popup.setOnCloseCallback(host::requestFocus);
return true;
} else if (action == DEEP_SHORTCUTS || action == SHORTCUTS_AND_NOTIFICATIONS) {
return PopupContainerWithArrow.showForIcon((BubbleTextView) host) != null;
} else {
- for (ButtonDropTarget dropTarget : mLauncher.getDropTargetBar().getDropTargets()) {
+ for (ButtonDropTarget dropTarget : mContext.getDropTargetBar().getDropTargets()) {
if (dropTarget.supportsAccessibilityDrop(item, host)
&& action == dropTarget.getAccessibilityAction()) {
dropTarget.onAccessibilityDrop(host, item);
@@ -315,7 +247,7 @@
if ((providerInfo.resizeMode & AppWidgetProviderInfo.RESIZE_HORIZONTAL) != 0) {
if (layout.isRegionVacant(info.cellX + info.spanX, info.cellY, 1, info.spanY) ||
layout.isRegionVacant(info.cellX - 1, info.cellY, 1, info.spanY)) {
- actions.add(new OptionItem(mLauncher,
+ actions.add(new OptionItem(mContext,
R.string.action_increase_width,
R.drawable.ic_widget_width_increase,
IGNORE,
@@ -323,7 +255,7 @@
}
if (info.spanX > info.minSpanX && info.spanX > 1) {
- actions.add(new OptionItem(mLauncher,
+ actions.add(new OptionItem(mContext,
R.string.action_decrease_width,
R.drawable.ic_widget_width_decrease,
IGNORE,
@@ -334,7 +266,7 @@
if ((providerInfo.resizeMode & AppWidgetProviderInfo.RESIZE_VERTICAL) != 0) {
if (layout.isRegionVacant(info.cellX, info.cellY + info.spanY, info.spanX, 1) ||
layout.isRegionVacant(info.cellX, info.cellY - 1, info.spanX, 1)) {
- actions.add(new OptionItem(mLauncher,
+ actions.add(new OptionItem(mContext,
R.string.action_increase_height,
R.drawable.ic_widget_height_increase,
IGNORE,
@@ -342,7 +274,7 @@
}
if (info.spanY > info.minSpanY && info.spanY > 1) {
- actions.add(new OptionItem(mLauncher,
+ actions.add(new OptionItem(mContext,
R.string.action_decrease_height,
R.drawable.ic_widget_height_decrease,
IGNORE,
@@ -382,58 +314,20 @@
}
layout.markCellsAsOccupiedForView(host);
- WidgetSizes.updateWidgetSizeRanges(((LauncherAppWidgetHostView) host), mLauncher,
+ WidgetSizes.updateWidgetSizeRanges(((LauncherAppWidgetHostView) host), mContext,
info.spanX, info.spanY);
host.requestLayout();
- mLauncher.getModelWriter().updateItemInDatabase(info);
- announceConfirmation(mLauncher.getString(R.string.widget_resized, info.spanX, info.spanY));
+ mContext.getModelWriter().updateItemInDatabase(info);
+ announceConfirmation(mContext.getString(R.string.widget_resized, info.spanX, info.spanY));
return true;
}
@Thunk void announceConfirmation(int resId) {
- announceConfirmation(mLauncher.getResources().getString(resId));
+ announceConfirmation(mContext.getResources().getString(resId));
}
- @Thunk void announceConfirmation(String confirmation) {
- mLauncher.getDragLayer().announceForAccessibility(confirmation);
-
- }
-
- public boolean isInAccessibleDrag() {
- return mDragInfo != null;
- }
-
- public DragInfo getDragInfo() {
- return mDragInfo;
- }
-
- /**
- * @param clickedTarget the actual view that was clicked
- * @param dropLocation relative to {@param clickedTarget}. If provided, its center is used
- * as the actual drop location otherwise the views center is used.
- */
- public void handleAccessibleDrop(View clickedTarget, Rect dropLocation,
- String confirmation) {
- if (!isInAccessibleDrag()) return;
-
- int[] loc = new int[2];
- if (dropLocation == null) {
- loc[0] = clickedTarget.getWidth() / 2;
- loc[1] = clickedTarget.getHeight() / 2;
- } else {
- loc[0] = dropLocation.centerX();
- loc[1] = dropLocation.centerY();
- }
-
- mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(clickedTarget, loc);
- mLauncher.getDragController().completeAccessibleDrag(loc);
-
- if (!TextUtils.isEmpty(confirmation)) {
- announceConfirmation(confirmation);
- }
- }
-
- private boolean beginAccessibleDrag(View item, ItemInfo info, boolean fromKeyboard) {
+ @Override
+ protected boolean beginAccessibleDrag(View item, ItemInfo info, boolean fromKeyboard) {
if (!itemSupportsAccessibleDrag(info)) {
return false;
}
@@ -449,8 +343,8 @@
}
Rect pos = new Rect();
- mLauncher.getDragLayer().getDescendantRectRelativeToSelf(item, pos);
- mLauncher.getDragController().addDragListener(this);
+ mContext.getDragLayer().getDescendantRectRelativeToSelf(item, pos);
+ mContext.getDragController().addDragListener(this);
DragOptions options = new DragOptions();
options.isAccessibleDrag = true;
@@ -458,31 +352,20 @@
options.simulatedDndStartPoint = new Point(pos.centerX(), pos.centerY());
if (fromKeyboard) {
- KeyboardDragAndDropView popup = (KeyboardDragAndDropView) mLauncher.getLayoutInflater()
- .inflate(R.layout.keyboard_drag_and_drop, mLauncher.getDragLayer(), false);
+ KeyboardDragAndDropView popup = (KeyboardDragAndDropView) mContext.getLayoutInflater()
+ .inflate(R.layout.keyboard_drag_and_drop, mContext.getDragLayer(), false);
popup.showForIcon(item, info, options);
} else {
- ItemLongClickListener.beginDrag(item, mLauncher, info, options);
+ ItemLongClickListener.beginDrag(item, mContext, info, options);
}
return true;
}
- @Override
- public void onDragStart(DragObject dragObject, DragOptions options) {
- // No-op
- }
-
- @Override
- public void onDragEnd() {
- mLauncher.getDragController().removeDragListener(this);
- mDragInfo = null;
- }
-
/**
* Find empty space on the workspace and returns the screenId.
*/
protected int findSpaceOnWorkspace(ItemInfo info, int[] outCoordinates) {
- Workspace workspace = mLauncher.getWorkspace();
+ Workspace workspace = mContext.getWorkspace();
IntArray workspaceScreens = workspace.getScreenOrder();
int screenId;
@@ -520,29 +403,4 @@
}
return screenId;
}
-
- public class LauncherAction {
- public final int keyCode;
- public final AccessibilityAction accessibilityAction;
-
- private final LauncherAccessibilityDelegate mDelegate;
-
- public LauncherAction(int id, int labelRes, int keyCode) {
- this.keyCode = keyCode;
- accessibilityAction = new AccessibilityAction(id, mLauncher.getString(labelRes));
- mDelegate = LauncherAccessibilityDelegate.this;
- }
-
- /**
- * Invokes the action for the provided host
- */
- public boolean invokeFromKeyboard(View host) {
- if (host != null && host.getTag() instanceof ItemInfo) {
- return mDelegate.performAction(
- host, (ItemInfo) host.getTag(), accessibilityAction.getId(), true);
- } else {
- return false;
- }
- }
- }
}
diff --git a/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java
index bf5a24b..fb847ec 100644
--- a/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java
@@ -71,12 +71,12 @@
if (screenId == -1) {
return false;
}
- mLauncher.getStateManager().goToState(NORMAL, true, forSuccessCallback(() -> {
- mLauncher.getModelWriter().addItemToDatabase(info,
+ mContext.getStateManager().goToState(NORMAL, true, forSuccessCallback(() -> {
+ mContext.getModelWriter().addItemToDatabase(info,
LauncherSettings.Favorites.CONTAINER_DESKTOP,
screenId, coordinates[0], coordinates[1]);
- mLauncher.bindItems(Collections.singletonList(info), true);
- AbstractFloatingView.closeAllOpenViews(mLauncher);
+ mContext.bindItems(Collections.singletonList(info), true);
+ AbstractFloatingView.closeAllOpenViews(mContext);
announceConfirmation(R.string.item_added_to_workspace);
}));
return true;
diff --git a/src/com/android/launcher3/accessibility/WorkspaceAccessibilityHelper.java b/src/com/android/launcher3/accessibility/WorkspaceAccessibilityHelper.java
index a331924..a8624dd 100644
--- a/src/com/android/launcher3/accessibility/WorkspaceAccessibilityHelper.java
+++ b/src/com/android/launcher3/accessibility/WorkspaceAccessibilityHelper.java
@@ -22,7 +22,7 @@
import com.android.launcher3.CellLayout;
import com.android.launcher3.R;
-import com.android.launcher3.accessibility.LauncherAccessibilityDelegate.DragType;
+import com.android.launcher3.accessibility.BaseAccessibilityDelegate.DragType;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 98cb5ae..1fa6360 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -95,6 +95,9 @@
public static final BooleanFlag ENABLE_ONE_SEARCH = new DeviceFlag("ENABLE_ONE_SEARCH", false,
"Use homescreen search box to complete allApps searches");
+ public static final BooleanFlag COLLECT_SEARCH_HISTORY = new DeviceFlag(
+ "COLLECT_SEARCH_HISTORY", false, "Allow launcher to collect search history for log");
+
public static final BooleanFlag ENABLE_TWOLINE_ALLAPPS = getDebugFlag(
"ENABLE_TWOLINE_ALLAPPS", false, "Enables two line label inside all apps.");
diff --git a/src/com/android/launcher3/dragndrop/DragView.java b/src/com/android/launcher3/dragndrop/DragView.java
index fa65945..8313571 100644
--- a/src/com/android/launcher3/dragndrop/DragView.java
+++ b/src/com/android/launcher3/dragndrop/DragView.java
@@ -21,6 +21,7 @@
import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
import static com.android.launcher3.Utilities.getBadge;
+import static com.android.launcher3.icons.FastBitmapDrawable.getDisabledColorFilter;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
import android.animation.Animator;
@@ -31,9 +32,9 @@
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.annotation.TargetApi;
import android.content.Context;
-import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
+import android.graphics.ColorFilter;
import android.graphics.Path;
import android.graphics.Picture;
import android.graphics.Point;
@@ -225,9 +226,8 @@
bounds.inset(blurMargin, blurMargin);
// Badge is applied after icon normalization so the bounds for badge should not
// be scaled down due to icon normalization.
- Rect badgeBounds = new Rect(bounds);
mBadge = getBadge(mActivity, info, outObj[0]);
- mBadge.setBounds(badgeBounds);
+ FastBitmapDrawable.setBadgeBounds(mBadge, bounds);
// Do not draw the background in case of folder as its translucent
final boolean shouldDrawBackground = !(dr instanceof FolderAdaptiveIcon);
@@ -280,11 +280,10 @@
removeAllViewsInLayout();
if (info.isDisabled()) {
- FastBitmapDrawable d = new FastBitmapDrawable((Bitmap) null);
- d.setIsDisabled(true);
- mBgSpringDrawable.setColorFilter(d.getColorFilter());
- mFgSpringDrawable.setColorFilter(d.getColorFilter());
- mBadge.setColorFilter(d.getColorFilter());
+ ColorFilter filter = getDisabledColorFilter();
+ mBgSpringDrawable.setColorFilter(filter);
+ mFgSpringDrawable.setColorFilter(filter);
+ mBadge.setColorFilter(filter);
}
invalidate();
}));
diff --git a/src/com/android/launcher3/folder/PreviewItemManager.java b/src/com/android/launcher3/folder/PreviewItemManager.java
index 8bef6ad..6355b62 100644
--- a/src/com/android/launcher3/folder/PreviewItemManager.java
+++ b/src/com/android/launcher3/folder/PreviewItemManager.java
@@ -21,6 +21,7 @@
import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.MAX_NUM_ITEMS_IN_PREVIEW;
import static com.android.launcher3.folder.FolderIcon.DROP_IN_ANIMATION_DURATION;
import static com.android.launcher3.graphics.PreloadIconDrawable.newPendingIcon;
+import static com.android.launcher3.icons.BitmapInfo.FLAG_THEMED;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -429,7 +430,7 @@
drawable.setLevel(item.getProgressLevel());
p.drawable = drawable;
} else {
- p.drawable = item.newIcon(mContext, true);
+ p.drawable = item.newIcon(mContext, FLAG_THEMED);
}
p.drawable.setBounds(0, 0, mIconSize, mIconSize);
p.item = item;
diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
index 73e18f4..abf002f 100644
--- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
+++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
@@ -43,7 +43,6 @@
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
-import android.os.Process;
import android.util.AttributeSet;
import android.util.SparseIntArray;
import android.view.ContextThemeWrapper;
@@ -202,10 +201,10 @@
BaseIconFactory iconFactory =
new BaseIconFactory(context, mIdp.fillResIconDpi, mIdp.iconBitmapSize) { };
- BitmapInfo iconInfo = iconFactory.createBadgedIconBitmap(new AdaptiveIconDrawable(
- new ColorDrawable(Color.WHITE), new ColorDrawable(Color.WHITE)),
- Process.myUserHandle(),
- Build.VERSION.SDK_INT);
+ BitmapInfo iconInfo = iconFactory.createBadgedIconBitmap(
+ new AdaptiveIconDrawable(
+ new ColorDrawable(Color.WHITE),
+ new ColorDrawable(Color.WHITE)));
mWorkspaceItemInfo = new WorkspaceItemInfo();
mWorkspaceItemInfo.bitmap = iconInfo;
diff --git a/src/com/android/launcher3/icons/ComponentWithLabelAndIcon.java b/src/com/android/launcher3/icons/ComponentWithLabelAndIcon.java
index 248a57d..c8606b1 100644
--- a/src/com/android/launcher3/icons/ComponentWithLabelAndIcon.java
+++ b/src/com/android/launcher3/icons/ComponentWithLabelAndIcon.java
@@ -21,6 +21,7 @@
import androidx.annotation.NonNull;
import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.icons.BaseIconFactory.IconOptions;
/**
* Extension of ComponentWithLabel to also support loading icons
@@ -47,7 +48,7 @@
return super.loadIcon(context, object);
}
try (LauncherIcons li = LauncherIcons.obtain(context)) {
- return li.createBadgedIconBitmap(d, object.getUser(), 0);
+ return li.createBadgedIconBitmap(d, new IconOptions().setUser(object.getUser()));
}
}
}
diff --git a/src/com/android/launcher3/icons/IconCache.java b/src/com/android/launcher3/icons/IconCache.java
index 936eeb9..f512ced 100644
--- a/src/com/android/launcher3/icons/IconCache.java
+++ b/src/com/android/launcher3/icons/IconCache.java
@@ -216,14 +216,7 @@
* Fill in {@param info} with the icon for {@param si}
*/
public void getShortcutIcon(ItemInfoWithIcon info, ShortcutInfo si) {
- getShortcutIcon(info, si, true, mIsUsingFallbackOrNonDefaultIconCheck);
- }
-
- /**
- * Fill in {@param info} with an unbadged icon for {@param si}
- */
- public void getUnbadgedShortcutIcon(ItemInfoWithIcon info, ShortcutInfo si) {
- getShortcutIcon(info, si, false, mIsUsingFallbackOrNonDefaultIconCheck);
+ getShortcutIcon(info, si, mIsUsingFallbackOrNonDefaultIconCheck);
}
/**
@@ -232,11 +225,6 @@
*/
public <T extends ItemInfoWithIcon> void getShortcutIcon(T info, ShortcutInfo si,
@NonNull Predicate<T> fallbackIconCheck) {
- getShortcutIcon(info, si, true /* use badged */, fallbackIconCheck);
- }
-
- private synchronized <T extends ItemInfoWithIcon> void getShortcutIcon(T info, ShortcutInfo si,
- boolean useBadged, @NonNull Predicate<T> fallbackIconCheck) {
BitmapInfo bitmapInfo;
if (FeatureFlags.ENABLE_DEEP_SHORTCUT_ICON_CACHE.get()) {
bitmapInfo = cacheLocked(ShortcutKey.fromInfo(si).componentName, si.getUserHandle(),
@@ -252,13 +240,7 @@
if (isDefaultIcon(bitmapInfo, si.getUserHandle()) && fallbackIconCheck.test(info)) {
return;
}
- info.bitmap = bitmapInfo;
- if (useBadged) {
- BitmapInfo badgeInfo = getShortcutInfoBadge(si);
- try (LauncherIcons li = LauncherIcons.obtain(mContext)) {
- info.bitmap = li.badgeBitmap(info.bitmap.icon, badgeInfo);
- }
- }
+ info.bitmap = bitmapInfo.withBadgeInfo(getShortcutInfoBadge(si));
}
/**
diff --git a/src/com/android/launcher3/icons/LauncherActivityCachingLogic.java b/src/com/android/launcher3/icons/LauncherActivityCachingLogic.java
index e820ac4..4b8c1ad 100644
--- a/src/com/android/launcher3/icons/LauncherActivityCachingLogic.java
+++ b/src/com/android/launcher3/icons/LauncherActivityCachingLogic.java
@@ -22,6 +22,7 @@
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
+import com.android.launcher3.icons.BaseIconFactory.IconOptions;
import com.android.launcher3.icons.cache.CachingLogic;
import com.android.launcher3.util.ResourceBasedOverride;
@@ -59,7 +60,7 @@
try (LauncherIcons li = LauncherIcons.obtain(context)) {
return li.createBadgedIconBitmap(LauncherAppState.getInstance(context)
.getIconProvider().getIcon(object, li.mFillResIconDpi),
- object.getUser(), object.getApplicationInfo().targetSdkVersion);
+ new IconOptions().setUser(object.getUser()));
}
}
}
diff --git a/src/com/android/launcher3/icons/ShortcutCachingLogic.java b/src/com/android/launcher3/icons/ShortcutCachingLogic.java
index d7eed06..6a8f34a 100644
--- a/src/com/android/launcher3/icons/ShortcutCachingLogic.java
+++ b/src/com/android/launcher3/icons/ShortcutCachingLogic.java
@@ -71,8 +71,8 @@
Drawable unbadgedDrawable = ShortcutCachingLogic.getIcon(
context, info, LauncherAppState.getIDP(context).fillResIconDpi);
if (unbadgedDrawable == null) return BitmapInfo.LOW_RES_INFO;
- return new BitmapInfo(li.createScaledBitmapWithoutShadow(
- unbadgedDrawable, 0), Themes.getColorAccent(context));
+ return new BitmapInfo(li.createScaledBitmapWithoutShadow(unbadgedDrawable),
+ Themes.getColorAccent(context));
}
}
diff --git a/src/com/android/launcher3/model/BgDataModel.java b/src/com/android/launcher3/model/BgDataModel.java
index d3351dc..84612de 100644
--- a/src/com/android/launcher3/model/BgDataModel.java
+++ b/src/com/android/launcher3/model/BgDataModel.java
@@ -229,7 +229,6 @@
String.format("Adding item to ID map: %s", item.toString()),
/* stackTrace= */ null);
}
-
itemsIdMap.put(item.id, item);
switch (item.itemType) {
case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
diff --git a/src/com/android/launcher3/model/data/ItemInfoWithIcon.java b/src/com/android/launcher3/model/data/ItemInfoWithIcon.java
index a74c02f..19345d7 100644
--- a/src/com/android/launcher3/model/data/ItemInfoWithIcon.java
+++ b/src/com/android/launcher3/model/data/ItemInfoWithIcon.java
@@ -23,6 +23,7 @@
import androidx.annotation.Nullable;
import com.android.launcher3.icons.BitmapInfo;
+import com.android.launcher3.icons.BitmapInfo.DrawableCreationFlags;
import com.android.launcher3.icons.FastBitmapDrawable;
import com.android.launcher3.logging.FileLog;
import com.android.launcher3.pm.PackageInstallInfo;
@@ -230,15 +231,14 @@
* Returns a FastBitmapDrawable with the icon.
*/
public FastBitmapDrawable newIcon(Context context) {
- return newIcon(context, false);
+ return newIcon(context, 0);
}
/**
* Returns a FastBitmapDrawable with the icon and context theme applied
*/
- public FastBitmapDrawable newIcon(Context context, boolean applyTheme) {
- FastBitmapDrawable drawable = applyTheme
- ? bitmap.newThemedIcon(context) : bitmap.newIcon(context);
+ public FastBitmapDrawable newIcon(Context context, @DrawableCreationFlags int creationFlags) {
+ FastBitmapDrawable drawable = bitmap.newIcon(context, creationFlags);
drawable.setIsDisabled(isDisabled());
return drawable;
}
diff --git a/src/com/android/launcher3/model/data/SearchActionItemInfo.java b/src/com/android/launcher3/model/data/SearchActionItemInfo.java
index c6e5e8a..cc22601 100644
--- a/src/com/android/launcher3/model/data/SearchActionItemInfo.java
+++ b/src/com/android/launcher3/model/data/SearchActionItemInfo.java
@@ -28,7 +28,6 @@
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherModel;
import com.android.launcher3.LauncherSettings;
-import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.logger.LauncherAtom.ItemInfo;
import com.android.launcher3.logger.LauncherAtom.SearchActionItem;
import com.android.launcher3.model.AllAppsList;
@@ -176,9 +175,7 @@
model.updateAndBindWorkspaceItem(() -> {
PackageItemInfo pkgInfo = new PackageItemInfo(getIntentPackageName(), user);
app.getIconCache().getTitleAndIconForApp(pkgInfo, false);
- try (LauncherIcons li = LauncherIcons.obtain(app.getContext())) {
- info.bitmap = li.badgeBitmap(info.bitmap.icon, pkgInfo.bitmap);
- }
+ info.bitmap = info.bitmap.withBadgeInfo(pkgInfo.bitmap);
return info;
});
}
diff --git a/src/com/android/launcher3/popup/LauncherPopupLiveUpdateHandler.java b/src/com/android/launcher3/popup/LauncherPopupLiveUpdateHandler.java
index 731f439..3e3f633 100644
--- a/src/com/android/launcher3/popup/LauncherPopupLiveUpdateHandler.java
+++ b/src/com/android/launcher3/popup/LauncherPopupLiveUpdateHandler.java
@@ -18,6 +18,7 @@
import android.view.View;
import android.view.ViewGroup;
+import com.android.launcher3.BubbleTextView;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.model.data.ItemInfo;
@@ -86,4 +87,9 @@
}
}
}
+
+ @Override
+ protected void showPopupContainerForIcon(BubbleTextView originalIcon) {
+ PopupContainerWithArrow.showForIcon(originalIcon);
+ }
}
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index aa8c70b..0097705 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -152,6 +152,10 @@
};
}
+ public void setPopupItemDragHandler(PopupItemDragHandler popupItemDragHandler) {
+ mPopupItemDragHandler = popupItemDragHandler;
+ }
+
public PopupItemDragHandler getItemDragHandler() {
return mPopupItemDragHandler;
}
diff --git a/src/com/android/launcher3/popup/PopupLiveUpdateHandler.java b/src/com/android/launcher3/popup/PopupLiveUpdateHandler.java
index 194c22f..c5d5452 100644
--- a/src/com/android/launcher3/popup/PopupLiveUpdateHandler.java
+++ b/src/com/android/launcher3/popup/PopupLiveUpdateHandler.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.view.View;
+import com.android.launcher3.BubbleTextView;
import com.android.launcher3.dot.DotInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.notification.NotificationContainer;
@@ -36,7 +37,7 @@
*
* @param <T> The activity on which the popup shows
*/
-public class PopupLiveUpdateHandler<T extends Context & ActivityContext> implements
+public abstract class PopupLiveUpdateHandler<T extends Context & ActivityContext> implements
PopupDataProvider.PopupDataChangeListener, View.OnAttachStateChangeListener {
protected final T mContext;
@@ -103,6 +104,8 @@
@Override
public void onSystemShortcutsUpdated() {
mPopupContainerWithArrow.close(true);
- PopupContainerWithArrow.showForIcon(mPopupContainerWithArrow.getOriginalIcon());
+ showPopupContainerForIcon(mPopupContainerWithArrow.getOriginalIcon());
}
+
+ protected abstract void showPopupContainerForIcon(BubbleTextView originalIcon);
}
diff --git a/src/com/android/launcher3/popup/PopupPopulator.java b/src/com/android/launcher3/popup/PopupPopulator.java
index 1dce1f2..8be4e6c 100644
--- a/src/com/android/launcher3/popup/PopupPopulator.java
+++ b/src/com/android/launcher3/popup/PopupPopulator.java
@@ -162,7 +162,7 @@
for (int i = 0; i < shortcuts.size() && i < shortcutViews.size(); i++) {
final ShortcutInfo shortcut = shortcuts.get(i);
final WorkspaceItemInfo si = new WorkspaceItemInfo(shortcut, context);
- cache.getUnbadgedShortcutIcon(si, shortcut);
+ cache.getShortcutIcon(si, shortcut);
si.rank = i;
si.container = CONTAINER_SHORTCUTS;
diff --git a/src/com/android/launcher3/shortcuts/DeepShortcutView.java b/src/com/android/launcher3/shortcuts/DeepShortcutView.java
index 71d288c..2f17ce0 100644
--- a/src/com/android/launcher3/shortcuts/DeepShortcutView.java
+++ b/src/com/android/launcher3/shortcuts/DeepShortcutView.java
@@ -72,6 +72,7 @@
protected void onFinishInflate() {
super.onFinishInflate();
mBubbleText = findViewById(R.id.bubble_text);
+ mBubbleText.setHideBadge(true);
mIconView = findViewById(R.id.icon);
tryUpdateTextBackground();
}
diff --git a/src/com/android/launcher3/shortcuts/ShortcutDragPreviewProvider.java b/src/com/android/launcher3/shortcuts/ShortcutDragPreviewProvider.java
index cecbb0d..c166bfc 100644
--- a/src/com/android/launcher3/shortcuts/ShortcutDragPreviewProvider.java
+++ b/src/com/android/launcher3/shortcuts/ShortcutDragPreviewProvider.java
@@ -23,12 +23,12 @@
import android.graphics.drawable.Drawable;
import android.view.View;
-import com.android.launcher3.Launcher;
import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.graphics.DragPreviewProvider;
import com.android.launcher3.icons.BitmapRenderer;
import com.android.launcher3.icons.FastBitmapDrawable;
+import com.android.launcher3.views.ActivityContext;
/**
* Extension of {@link DragPreviewProvider} which generates bitmaps scaled to the default icon size.
@@ -45,7 +45,8 @@
@Override
public Drawable createDrawable() {
if (FeatureFlags.ENABLE_DEEP_SHORTCUT_ICON_CACHE.get()) {
- int size = Launcher.getLauncher(mView.getContext()).getDeviceProfile().iconSizePx;
+ int size = ActivityContext.lookupContext(mView.getContext())
+ .getDeviceProfile().iconSizePx;
return new FastBitmapDrawable(
BitmapRenderer.createHardwareBitmap(
size + blurSizeOutline,
@@ -59,7 +60,7 @@
private Bitmap createDragBitmapLegacy() {
Drawable d = mView.getBackground();
Rect bounds = getDrawableBounds(d);
- int size = Launcher.getLauncher(mView.getContext()).getDeviceProfile().iconSizePx;
+ int size = ActivityContext.lookupContext(mView.getContext()).getDeviceProfile().iconSizePx;
final Bitmap b = Bitmap.createBitmap(
size + blurSizeOutline,
size + blurSizeOutline,
@@ -84,9 +85,9 @@
@Override
public float getScaleAndPosition(Drawable preview, int[] outPos) {
- Launcher launcher = Launcher.getLauncher(mView.getContext());
+ ActivityContext context = ActivityContext.lookupContext(mView.getContext());
int iconSize = getDrawableBounds(mView.getBackground()).width();
- float scale = launcher.getDragLayer().getLocationInDragLayer(mView, outPos);
+ float scale = context.getDragLayer().getLocationInDragLayer(mView, outPos);
int iconLeft = mView.getPaddingStart();
if (Utilities.isRtl(mView.getResources())) {
@@ -98,7 +99,7 @@
+ mPositionShift.x);
outPos[1] += Math.round((scale * mView.getHeight() - preview.getIntrinsicHeight()) / 2
+ mPositionShift.y);
- float size = launcher.getDeviceProfile().iconSizePx;
+ float size = context.getDeviceProfile().iconSizePx;
return scale * iconSize / size;
}
}
diff --git a/src/com/android/launcher3/touch/BaseSwipeDetector.java b/src/com/android/launcher3/touch/BaseSwipeDetector.java
index 1276ece..52c3581 100644
--- a/src/com/android/launcher3/touch/BaseSwipeDetector.java
+++ b/src/com/android/launcher3/touch/BaseSwipeDetector.java
@@ -17,6 +17,7 @@
import static android.view.MotionEvent.INVALID_POINTER_ID;
+import android.content.Context;
import android.graphics.PointF;
import android.util.Log;
import android.view.MotionEvent;
@@ -26,6 +27,8 @@
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
+import com.android.launcher3.R;
+
import java.util.LinkedList;
import java.util.Queue;
@@ -44,10 +47,9 @@
private static final boolean DBG = false;
private static final String TAG = "BaseSwipeDetector";
private static final float ANIMATION_DURATION = 1200;
- /** The minimum release velocity in pixels per millisecond that triggers fling.*/
- private static final float RELEASE_VELOCITY_PX_MS = 1.0f;
private static final PointF sTempPoint = new PointF();
+ private final float mReleaseVelocity;
private final PointF mDownPos = new PointF();
private final PointF mLastPos = new PointF();
protected final boolean mIsRtl;
@@ -64,6 +66,7 @@
private boolean mIsSettingState;
protected boolean mIgnoreSlopWhenSettling;
+ protected Context mContext;
private enum ScrollState {
IDLE,
@@ -71,10 +74,14 @@
SETTLING // onDragEnd
}
- protected BaseSwipeDetector(@NonNull ViewConfiguration config, boolean isRtl) {
+ protected BaseSwipeDetector(@NonNull Context context, @NonNull ViewConfiguration config,
+ boolean isRtl) {
mTouchSlop = config.getScaledTouchSlop();
mMaxVelocity = config.getScaledMaximumFlingVelocity();
mIsRtl = isRtl;
+ mContext = context;
+ mReleaseVelocity = mContext.getResources()
+ .getDimensionPixelSize(R.dimen.base_swift_detector_fling_release_velocity);
}
public static long calculateDuration(float velocity, float progressNeeded) {
@@ -120,7 +127,7 @@
}
public boolean isFling(float velocity) {
- return Math.abs(velocity) > RELEASE_VELOCITY_PX_MS;
+ return Math.abs(velocity) > mReleaseVelocity;
}
public boolean onTouchEvent(MotionEvent ev) {
@@ -236,7 +243,7 @@
} else {
mSubtractDisplacement.x = mDisplacement.x > 0 ? mTouchSlop : -mTouchSlop;
mSubtractDisplacement.y = mDisplacement.y > 0 ? mTouchSlop : -mTouchSlop;
- }
+ }
}
protected abstract boolean shouldScrollStart(PointF displacement);
diff --git a/src/com/android/launcher3/touch/BothAxesSwipeDetector.java b/src/com/android/launcher3/touch/BothAxesSwipeDetector.java
index 944391e..6e2f0d8 100644
--- a/src/com/android/launcher3/touch/BothAxesSwipeDetector.java
+++ b/src/com/android/launcher3/touch/BothAxesSwipeDetector.java
@@ -21,7 +21,6 @@
import android.view.ViewConfiguration;
import androidx.annotation.NonNull;
-import androidx.annotation.VisibleForTesting;
import com.android.launcher3.Utilities;
@@ -43,13 +42,7 @@
private int mScrollDirections;
public BothAxesSwipeDetector(@NonNull Context context, @NonNull Listener l) {
- this(ViewConfiguration.get(context), l, Utilities.isRtl(context.getResources()));
- }
-
- @VisibleForTesting
- protected BothAxesSwipeDetector(@NonNull ViewConfiguration config, @NonNull Listener l,
- boolean isRtl) {
- super(config, isRtl);
+ super(context, ViewConfiguration.get(context), Utilities.isRtl(context.getResources()));
mListener = l;
}
diff --git a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
index c255225..0c39067 100644
--- a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
+++ b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
@@ -357,7 +357,7 @@
public List<SplitPositionOption> getSplitPositionOptions(DeviceProfile dp) {
// Add "left" side of phone which is actually the top
return Collections.singletonList(new SplitPositionOption(
- R.drawable.ic_split_screen, R.string.split_screen_position_left,
+ R.drawable.ic_split_left, R.string.split_screen_position_left,
STAGE_POSITION_TOP_OR_LEFT, STAGE_TYPE_MAIN));
}
diff --git a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
index e69944a..b9f1b66 100644
--- a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
+++ b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
@@ -370,28 +370,27 @@
public List<SplitPositionOption> getSplitPositionOptions(DeviceProfile dp) {
List<SplitPositionOption> options = new ArrayList<>(1);
// Add both left and right options if we're in tablet mode
- // TODO: Add in correct icons
if (dp.isTablet && dp.isLandscape) {
options.add(new SplitPositionOption(
- R.drawable.ic_split_screen, R.string.split_screen_position_right,
+ R.drawable.ic_split_right, R.string.split_screen_position_right,
STAGE_POSITION_BOTTOM_OR_RIGHT, STAGE_TYPE_MAIN));
options.add(new SplitPositionOption(
- R.drawable.ic_split_screen, R.string.split_screen_position_left,
+ R.drawable.ic_split_left, R.string.split_screen_position_left,
STAGE_POSITION_TOP_OR_LEFT, STAGE_TYPE_MAIN));
} else {
if (dp.isSeascape()) {
// Add left/right options
options.add(new SplitPositionOption(
- R.drawable.ic_split_screen, R.string.split_screen_position_right,
+ R.drawable.ic_split_right, R.string.split_screen_position_right,
STAGE_POSITION_BOTTOM_OR_RIGHT, STAGE_TYPE_MAIN));
} else if (dp.isLandscape) {
options.add(new SplitPositionOption(
- R.drawable.ic_split_screen, R.string.split_screen_position_left,
+ R.drawable.ic_split_left, R.string.split_screen_position_left,
STAGE_POSITION_TOP_OR_LEFT, STAGE_TYPE_MAIN));
} else {
// Only add top option
options.add(new SplitPositionOption(
- R.drawable.ic_split_screen, R.string.split_screen_position_top,
+ R.drawable.ic_split_top, R.string.split_screen_position_top,
STAGE_POSITION_TOP_OR_LEFT, STAGE_TYPE_MAIN));
}
}
diff --git a/src/com/android/launcher3/touch/SeascapePagedViewHandler.java b/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
index 539e3f8..ce2e136 100644
--- a/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
+++ b/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
@@ -115,7 +115,7 @@
public List<SplitPositionOption> getSplitPositionOptions(DeviceProfile dp) {
// Add "right" option which is actually the top
return Collections.singletonList(new SplitPositionOption(
- R.drawable.ic_split_screen, R.string.split_screen_position_right,
+ R.drawable.ic_split_right, R.string.split_screen_position_right,
STAGE_POSITION_TOP_OR_LEFT, STAGE_TYPE_MAIN));
}
diff --git a/src/com/android/launcher3/touch/SingleAxisSwipeDetector.java b/src/com/android/launcher3/touch/SingleAxisSwipeDetector.java
index f751b7d..5c599c0 100644
--- a/src/com/android/launcher3/touch/SingleAxisSwipeDetector.java
+++ b/src/com/android/launcher3/touch/SingleAxisSwipeDetector.java
@@ -106,13 +106,15 @@
public SingleAxisSwipeDetector(@NonNull Context context, @NonNull Listener l,
@NonNull Direction dir) {
- this(ViewConfiguration.get(context), l, dir, Utilities.isRtl(context.getResources()));
+ super(context, ViewConfiguration.get(context), Utilities.isRtl(context.getResources()));
+ mListener = l;
+ mDir = dir;
}
@VisibleForTesting
- protected SingleAxisSwipeDetector(@NonNull ViewConfiguration config, @NonNull Listener l,
- @NonNull Direction dir, boolean isRtl) {
- super(config, isRtl);
+ protected SingleAxisSwipeDetector(@NonNull Context context, @NonNull ViewConfiguration config,
+ @NonNull Listener l, @NonNull Direction dir, boolean isRtl) {
+ super(context, config, isRtl);
mListener = l;
mDir = dir;
}
diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java
index 8b7ad46..c0ec9d8 100644
--- a/src/com/android/launcher3/views/FloatingIconView.java
+++ b/src/com/android/launcher3/views/FloatingIconView.java
@@ -338,15 +338,13 @@
setLayoutParams(lp);
final LayoutParams clipViewLp = (LayoutParams) mClipIconView.getLayoutParams();
- final int clipViewOgHeight = clipViewLp.height;
- final int clipViewOgWidth = clipViewLp.width;
+ if (mBadge != null) {
+ Rect badgeBounds = new Rect(0, 0, clipViewLp.width, clipViewLp.height);
+ FastBitmapDrawable.setBadgeBounds(mBadge, badgeBounds);
+ }
clipViewLp.width = lp.width;
clipViewLp.height = lp.height;
mClipIconView.setLayoutParams(clipViewLp);
-
- if (mBadge != null) {
- mBadge.setBounds(0, 0, clipViewOgWidth, clipViewOgHeight);
- }
}
if (!mIsOpening && btvIcon != null) {
@@ -460,7 +458,7 @@
if (mIconLoadResult != null && mIconLoadResult.isIconLoaded) {
setVisibility(View.VISIBLE);
}
- if (!mIsOpening) {
+ if (!mIsOpening && mOriginalIcon != null) {
// When closing an app, we want the item on the workspace to be invisible immediately
setIconAndDotVisible(mOriginalIcon, false);
}
diff --git a/src/com/android/launcher3/views/Snackbar.java b/src/com/android/launcher3/views/Snackbar.java
index 49fcd2e..f945819 100644
--- a/src/com/android/launcher3/views/Snackbar.java
+++ b/src/com/android/launcher3/views/Snackbar.java
@@ -28,8 +28,9 @@
import android.view.MotionEvent;
import android.widget.TextView;
+import androidx.annotation.Nullable;
+
import com.android.launcher3.AbstractFloatingView;
-import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.R;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.compat.AccessibilityManagerCompat;
@@ -44,7 +45,7 @@
private static final long HIDE_DURATION_MS = 180;
private static final int TIMEOUT_DURATION_MS = 4000;
- private final BaseDraggingActivity mActivity;
+ private final ActivityContext mActivity;
private Runnable mOnDismissed;
public Snackbar(Context context, AttributeSet attrs) {
@@ -53,12 +54,19 @@
public Snackbar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
- mActivity = BaseDraggingActivity.fromContext(context);
+ mActivity = ActivityContext.lookupContext(context);
inflate(context, R.layout.snackbar, this);
}
- public static void show(BaseDraggingActivity activity, int labelStringResId,
- int actionStringResId, Runnable onDismissed, Runnable onActionClicked) {
+ /** Show a snackbar with just a label. */
+ public static <T extends Context & ActivityContext> void show(T activity, int labelStringRedId,
+ Runnable onDismissed) {
+ show(activity, labelStringRedId, NO_ID, onDismissed, null);
+ }
+
+ /** Show a snackbar with a label and action. */
+ public static <T extends Context & ActivityContext> void show(T activity, int labelStringResId,
+ int actionStringResId, Runnable onDismissed, @Nullable Runnable onActionClicked) {
closeOpenViews(activity, true, TYPE_SNACKBAR);
Snackbar snackbar = new Snackbar(activity, null);
// Set some properties here since inflated xml only contains the children.
@@ -87,13 +95,30 @@
params.setMargins(0, 0, 0, marginBottom + insets.bottom);
TextView labelView = snackbar.findViewById(R.id.label);
- TextView actionView = snackbar.findViewById(R.id.action);
String labelText = res.getString(labelStringResId);
- String actionText = res.getString(actionStringResId);
- int totalContentWidth = (int) (labelView.getPaint().measureText(labelText)
- + actionView.getPaint().measureText(actionText))
+ labelView.setText(labelText);
+
+ TextView actionView = snackbar.findViewById(R.id.action);
+ float actionWidth;
+ if (actionStringResId != NO_ID) {
+ String actionText = res.getString(actionStringResId);
+ actionWidth = actionView.getPaint().measureText(actionText)
+ + actionView.getPaddingRight() + actionView.getPaddingLeft();
+ actionView.setText(actionText);
+ actionView.setOnClickListener(v -> {
+ if (onActionClicked != null) {
+ onActionClicked.run();
+ }
+ snackbar.mOnDismissed = null;
+ snackbar.close(true);
+ });
+ } else {
+ actionWidth = 0;
+ actionView.setVisibility(GONE);
+ }
+
+ int totalContentWidth = (int) (labelView.getPaint().measureText(labelText) + actionWidth)
+ labelView.getPaddingRight() + labelView.getPaddingLeft()
- + actionView.getPaddingRight() + actionView.getPaddingLeft()
+ padding * 2;
if (totalContentWidth > params.width) {
// The text doesn't fit in our standard width so update width to accommodate.
@@ -113,17 +138,8 @@
params.width = maxWidth;
}
}
- labelView.setText(labelText);
- actionView.setText(actionText);
- actionView.setOnClickListener(v -> {
- if (onActionClicked != null) {
- onActionClicked.run();
- }
- snackbar.mOnDismissed = null;
- snackbar.close(true);
- });
- snackbar.mOnDismissed = onDismissed;
+ snackbar.mOnDismissed = onDismissed;
snackbar.setAlpha(0);
snackbar.setScaleX(0.8f);
snackbar.setScaleY(0.8f);
diff --git a/src/com/android/launcher3/widget/DatabaseWidgetPreviewLoader.java b/src/com/android/launcher3/widget/DatabaseWidgetPreviewLoader.java
index 784f4f0..7030f6d 100644
--- a/src/com/android/launcher3/widget/DatabaseWidgetPreviewLoader.java
+++ b/src/com/android/launcher3/widget/DatabaseWidgetPreviewLoader.java
@@ -25,15 +25,10 @@
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
-import android.graphics.Rect;
import android.graphics.RectF;
-import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Handler;
-import android.os.Process;
-import android.os.UserHandle;
-import android.util.ArrayMap;
import android.util.Log;
import android.util.Size;
@@ -44,7 +39,6 @@
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.icons.BitmapRenderer;
-import com.android.launcher3.icons.FastBitmapDrawable;
import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.icons.ShadowGenerator;
import com.android.launcher3.icons.cache.HandlerRunnable;
@@ -65,9 +59,6 @@
private final Context mContext;
private final float mPreviewBoxCornerRadius;
- private final UserHandle mMyUser = Process.myUserHandle();
- private final ArrayMap<UserHandle, Bitmap> mUserBadges = new ArrayMap<>();
-
public DatabaseWidgetPreviewLoader(Context context) {
mContext = context;
float previewCornerRadius = RoundedCornerEnforcement.computeEnforcedRadius(context);
@@ -109,52 +100,6 @@
}
/**
- * Returns a drawable that can be used as a badge for the user or null.
- */
- // @UiThread
- public Drawable getBadgeForUser(UserHandle user, int badgeSize) {
- if (mMyUser.equals(user)) {
- return null;
- }
-
- Bitmap badgeBitmap = getUserBadge(user, badgeSize);
- FastBitmapDrawable d = new FastBitmapDrawable(badgeBitmap);
- d.setFilterBitmap(true);
- d.setBounds(0, 0, badgeBitmap.getWidth(), badgeBitmap.getHeight());
- return d;
- }
-
- private Bitmap getUserBadge(UserHandle user, int badgeSize) {
- synchronized (mUserBadges) {
- Bitmap badgeBitmap = mUserBadges.get(user);
- if (badgeBitmap != null) {
- return badgeBitmap;
- }
-
- final Resources res = mContext.getResources();
- badgeBitmap = Bitmap.createBitmap(badgeSize, badgeSize, Bitmap.Config.ARGB_8888);
-
- Drawable drawable = mContext.getPackageManager().getUserBadgedDrawableForDensity(
- new BitmapDrawable(res, badgeBitmap), user,
- new Rect(0, 0, badgeSize, badgeSize),
- 0);
- if (drawable instanceof BitmapDrawable) {
- badgeBitmap = ((BitmapDrawable) drawable).getBitmap();
- } else {
- badgeBitmap.eraseColor(Color.TRANSPARENT);
- Canvas c = new Canvas(badgeBitmap);
- drawable.setBounds(0, 0, badgeSize, badgeSize);
- drawable.draw(c);
- c.setBitmap(null);
- }
-
- mUserBadges.put(user, badgeBitmap);
- return badgeBitmap;
- }
- }
-
-
- /**
* Generates the widget preview from either the {@link WidgetManagerHelper} or cache
* and add badge at the bottom right corner.
*
@@ -318,8 +263,8 @@
LauncherIcons li = LauncherIcons.obtain(mContext);
Drawable icon = li.createBadgedIconBitmap(
mutateOnMainThread(info.getFullResIcon(
- LauncherAppState.getInstance(mContext).getIconCache())),
- Process.myUserHandle(), 0).newIcon(mContext);
+ LauncherAppState.getInstance(mContext).getIconCache())))
+ .newIcon(mContext);
li.recycle();
icon.setBounds(padding, padding, padding + iconSize, padding + iconSize);
diff --git a/src/com/android/launcher3/widget/PendingAppWidgetHostView.java b/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
index 553ba13..1f6551e 100644
--- a/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
@@ -17,6 +17,7 @@
package com.android.launcher3.widget;
import static com.android.launcher3.graphics.PreloadIconDrawable.newPendingIcon;
+import static com.android.launcher3.icons.FastBitmapDrawable.getDisabledColorFilter;
import static com.android.launcher3.widget.WidgetSections.getWidgetSections;
import android.content.Context;
@@ -159,8 +160,7 @@
disabledIcon.setIsDisabled(true);
mCenterDrawable = disabledIcon;
} else {
- widgetCategoryIcon.setColorFilter(
- FastBitmapDrawable.getDisabledFColorFilter(/* disabledAlpha= */ 1f));
+ widgetCategoryIcon.setColorFilter(getDisabledColorFilter());
mCenterDrawable = widgetCategoryIcon;
}
mSettingIconDrawable = null;
diff --git a/src/com/android/launcher3/widget/PendingItemDragHelper.java b/src/com/android/launcher3/widget/PendingItemDragHelper.java
index 463f4ac..46c0b99 100644
--- a/src/com/android/launcher3/widget/PendingItemDragHelper.java
+++ b/src/com/android/launcher3/widget/PendingItemDragHelper.java
@@ -181,8 +181,7 @@
PendingAddShortcutInfo createShortcutInfo = (PendingAddShortcutInfo) mAddInfo;
Drawable icon = createShortcutInfo.activityInfo.getFullResIcon(app.getIconCache());
LauncherIcons li = LauncherIcons.obtain(launcher);
- preview = new FastBitmapDrawable(
- li.createScaledBitmapWithoutShadow(icon, 0));
+ preview = new FastBitmapDrawable(li.createScaledBitmapWithoutShadow(icon));
previewWidth = preview.getIntrinsicWidth();
previewHeight = preview.getIntrinsicHeight();
li.recycle();
diff --git a/src/com/android/launcher3/widget/WidgetCell.java b/src/com/android/launcher3/widget/WidgetCell.java
index c92fe5a..2796721 100644
--- a/src/com/android/launcher3/widget/WidgetCell.java
+++ b/src/com/android/launcher3/widget/WidgetCell.java
@@ -26,6 +26,7 @@
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
+import android.os.Process;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Size;
@@ -48,7 +49,6 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
-import com.android.launcher3.icons.BaseIconFactory;
import com.android.launcher3.icons.FastBitmapDrawable;
import com.android.launcher3.icons.RoundDrawableWrapper;
import com.android.launcher3.icons.cache.HandlerRunnable;
@@ -372,14 +372,11 @@
/** Used to show the badge when the widget is in the recommended section
*/
public void showBadge() {
- Drawable badge = mWidgetPreviewLoader.getBadgeForUser(mItem.user,
- BaseIconFactory.getBadgeSizeForIconSize(
- mActivity.getDeviceProfile().allAppsIconSizePx));
- if (badge == null) {
+ if (Process.myUserHandle().equals(mItem.user)) {
mWidgetBadge.setVisibility(View.GONE);
} else {
mWidgetBadge.setVisibility(View.VISIBLE);
- mWidgetBadge.setImageDrawable(badge);
+ mWidgetBadge.setImageResource(R.drawable.ic_work_app_badge);
}
}
diff --git a/tests/src/com/android/launcher3/touch/SingleAxisSwipeDetectorTest.java b/tests/src/com/android/launcher3/touch/SingleAxisSwipeDetectorTest.java
index 472e1a1..260f556 100644
--- a/tests/src/com/android/launcher3/touch/SingleAxisSwipeDetectorTest.java
+++ b/tests/src/com/android/launcher3/touch/SingleAxisSwipeDetectorTest.java
@@ -30,6 +30,7 @@
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
+import android.content.Context;
import android.util.Log;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
@@ -58,6 +59,7 @@
private TouchEventGenerator mGenerator;
private SingleAxisSwipeDetector mDetector;
private int mTouchSlop;
+ Context mContext;
@Mock
private SingleAxisSwipeDetector.Listener mMockListener;
@@ -69,12 +71,13 @@
public void setup() {
MockitoAnnotations.initMocks(this);
mGenerator = new TouchEventGenerator((ev) -> mDetector.onTouchEvent(ev));
- ViewConfiguration orgConfig = ViewConfiguration
- .get(InstrumentationRegistry.getTargetContext());
+ mContext = InstrumentationRegistry.getTargetContext();
+ ViewConfiguration orgConfig = ViewConfiguration.get(mContext);
doReturn(orgConfig.getScaledMaximumFlingVelocity()).when(mMockConfig)
.getScaledMaximumFlingVelocity();
- mDetector = new SingleAxisSwipeDetector(mMockConfig, mMockListener, VERTICAL, false);
+ mDetector = new SingleAxisSwipeDetector(mContext,
+ mMockConfig, mMockListener, VERTICAL, false);
mDetector.setDetectableScrollConditions(DIRECTION_BOTH, false);
mTouchSlop = orgConfig.getScaledTouchSlop();
doReturn(mTouchSlop).when(mMockConfig).getScaledTouchSlop();
@@ -84,7 +87,8 @@
@Test
public void testDragStart_verticalPositive() {
- mDetector = new SingleAxisSwipeDetector(mMockConfig, mMockListener, VERTICAL, false);
+ mDetector = new SingleAxisSwipeDetector(mContext,
+ mMockConfig, mMockListener, VERTICAL, false);
mDetector.setDetectableScrollConditions(DIRECTION_POSITIVE, false);
mGenerator.put(0, 100, 100);
mGenerator.move(0, 100, 100 - mTouchSlop);
@@ -94,7 +98,8 @@
@Test
public void testDragStart_verticalNegative() {
- mDetector = new SingleAxisSwipeDetector(mMockConfig, mMockListener, VERTICAL, false);
+ mDetector = new SingleAxisSwipeDetector(mContext,
+ mMockConfig, mMockListener, VERTICAL, false);
mDetector.setDetectableScrollConditions(DIRECTION_NEGATIVE, false);
mGenerator.put(0, 100, 100);
mGenerator.move(0, 100, 100 + mTouchSlop);
@@ -112,7 +117,8 @@
@Test
public void testDragStart_horizontalPositive() {
- mDetector = new SingleAxisSwipeDetector(mMockConfig, mMockListener, HORIZONTAL, false);
+ mDetector = new SingleAxisSwipeDetector(mContext,
+ mMockConfig, mMockListener, HORIZONTAL, false);
mDetector.setDetectableScrollConditions(DIRECTION_POSITIVE, false);
mGenerator.put(0, 100, 100);
@@ -123,7 +129,8 @@
@Test
public void testDragStart_horizontalNegative() {
- mDetector = new SingleAxisSwipeDetector(mMockConfig, mMockListener, HORIZONTAL, false);
+ mDetector = new SingleAxisSwipeDetector(mContext,
+ mMockConfig, mMockListener, HORIZONTAL, false);
mDetector.setDetectableScrollConditions(DIRECTION_NEGATIVE, false);
mGenerator.put(0, 100, 100);
@@ -134,7 +141,8 @@
@Test
public void testDragStart_horizontalRtlPositive() {
- mDetector = new SingleAxisSwipeDetector(mMockConfig, mMockListener, HORIZONTAL, true);
+ mDetector = new SingleAxisSwipeDetector(mContext,
+ mMockConfig, mMockListener, HORIZONTAL, true);
mDetector.setDetectableScrollConditions(DIRECTION_POSITIVE, false);
mGenerator.put(0, 100, 100);
@@ -145,7 +153,8 @@
@Test
public void testDragStart_horizontalRtlNegative() {
- mDetector = new SingleAxisSwipeDetector(mMockConfig, mMockListener, HORIZONTAL, true);
+ mDetector = new SingleAxisSwipeDetector(mContext,
+ mMockConfig, mMockListener, HORIZONTAL, true);
mDetector.setDetectableScrollConditions(DIRECTION_NEGATIVE, false);
mGenerator.put(0, 100, 100);
diff --git a/tests/tapl/com/android/launcher3/tapl/Widgets.java b/tests/tapl/com/android/launcher3/tapl/Widgets.java
index 6e7264a..0bac2ca 100644
--- a/tests/tapl/com/android/launcher3/tapl/Widgets.java
+++ b/tests/tapl/com/android/launcher3/tapl/Widgets.java
@@ -77,7 +77,8 @@
mLauncher.scroll(
widgetsContainer,
Direction.UP,
- new Rect(0, 0, mLauncher.getVisibleBounds(widgetsContainer).width(), 0),
+ new Rect(0, 0, mLauncher.getRightGestureMarginInContainer(widgetsContainer) + 1,
+ 0),
FLING_STEPS, false);
try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("flung back")) {
verifyActiveContainer();