Merge "Import translations. DO NOT MERGE ANYWHERE" into tm-qpr-dev
diff --git a/quickstep/res/layout/task_desktop.xml b/quickstep/res/layout/task_desktop.xml
index 2a9674f..96aabb4 100644
--- a/quickstep/res/layout/task_desktop.xml
+++ b/quickstep/res/layout/task_desktop.xml
@@ -24,6 +24,11 @@
android:defaultFocusHighlightEnabled="false"
android:focusable="true">
+ <View
+ android:id="@+id/background"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
<!--
TODO(b249371338): DesktopTaskView extends from TaskView. TaskView expects TaskThumbnailView
and IconView with these ids to be present. Need to refactor RecentsView to accept child
@@ -38,10 +43,9 @@
<com.android.quickstep.views.IconView
android:id="@+id/icon"
- android:layout_width="0dp"
- android:layout_height="0dp"
+ android:layout_width="@dimen/task_thumbnail_icon_size"
+ android:layout_height="@dimen/task_thumbnail_icon_size"
android:focusable="false"
- android:importantForAccessibility="no"
- android:visibility="gone" />
+ android:importantForAccessibility="no" />
</com.android.quickstep.views.DesktopTaskView>
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index b880a7e..347c492 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -213,9 +213,9 @@
private static final int WIDGET_CROSSFADE_DURATION_MILLIS = 125;
protected final QuickstepLauncher mLauncher;
- private final DragLayer mDragLayer;
+ protected final DragLayer mDragLayer;
- final Handler mHandler;
+ protected final Handler mHandler;
private final float mClosingWindowTransY;
private final float mMaxShadowRadius;
@@ -1097,32 +1097,38 @@
return;
}
if (hasControlRemoteAppTransitionPermission()) {
- mWallpaperOpenRunner = createWallpaperOpenRunner(false /* fromUnlock */);
-
RemoteAnimationDefinition definition = new RemoteAnimationDefinition();
- definition.addRemoteAnimation(WindowManager.TRANSIT_OLD_WALLPAPER_OPEN,
- WindowConfiguration.ACTIVITY_TYPE_STANDARD,
- new RemoteAnimationAdapter(
- new LauncherAnimationRunner(mHandler, mWallpaperOpenRunner,
- false /* startAtFrontOfQueue */),
- CLOSING_TRANSITION_DURATION_MS, 0 /* statusBarTransitionDelay */));
-
- if (KEYGUARD_ANIMATION.get()) {
- mKeyguardGoingAwayRunner = createWallpaperOpenRunner(true /* fromUnlock */);
- definition.addRemoteAnimation(
- WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER,
- new RemoteAnimationAdapter(
- new LauncherAnimationRunner(
- mHandler, mKeyguardGoingAwayRunner,
- true /* startAtFrontOfQueue */),
- CLOSING_TRANSITION_DURATION_MS, 0 /* statusBarTransitionDelay */));
- }
-
+ addRemoteAnimations(definition);
mLauncher.registerRemoteAnimations(definition);
}
}
/**
+ * Adds remote animations to a {@link RemoteAnimationDefinition}. May be overridden to add
+ * additional animations.
+ */
+ protected void addRemoteAnimations(RemoteAnimationDefinition definition) {
+ mWallpaperOpenRunner = createWallpaperOpenRunner(false /* fromUnlock */);
+ definition.addRemoteAnimation(WindowManager.TRANSIT_OLD_WALLPAPER_OPEN,
+ WindowConfiguration.ACTIVITY_TYPE_STANDARD,
+ new RemoteAnimationAdapter(
+ new LauncherAnimationRunner(mHandler, mWallpaperOpenRunner,
+ false /* startAtFrontOfQueue */),
+ CLOSING_TRANSITION_DURATION_MS, 0 /* statusBarTransitionDelay */));
+
+ if (KEYGUARD_ANIMATION.get()) {
+ mKeyguardGoingAwayRunner = createWallpaperOpenRunner(true /* fromUnlock */);
+ definition.addRemoteAnimation(
+ WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER,
+ new RemoteAnimationAdapter(
+ new LauncherAnimationRunner(
+ mHandler, mKeyguardGoingAwayRunner,
+ true /* startAtFrontOfQueue */),
+ CLOSING_TRANSITION_DURATION_MS, 0 /* statusBarTransitionDelay */));
+ }
+ }
+
+ /**
* Registers remote animations used when closing apps to home screen.
*/
public void registerRemoteTransitions() {
@@ -1163,7 +1169,7 @@
SystemUiProxy.INSTANCE.get(mLauncher).setStartingWindowListener(null);
}
- private void unregisterRemoteAnimations() {
+ protected void unregisterRemoteAnimations() {
if (SEPARATE_RECENTS_ACTIVITY.get()) {
return;
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java b/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
index bf0f8f7..25207d4 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
@@ -124,7 +124,7 @@
int shadowSize = context.getResources().getDimensionPixelSize(
R.dimen.blur_size_thin_outline);
mShadowFilter = new BlurMaskFilter(shadowSize, BlurMaskFilter.Blur.OUTER);
- mShapePath = GraphicsUtils.getShapePath(mNormalizedIconSize);
+ mShapePath = GraphicsUtils.getShapePath(context, mNormalizedIconSize);
}
@Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 124f15e..2cbb899 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -23,6 +23,7 @@
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
+import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_SEARCH_ACTION;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.NORMAL;
@@ -238,7 +239,7 @@
mActionsView.updateDimension(getDeviceProfile(), overviewPanel.getLastComputedTaskSize());
mActionsView.updateVerticalMargin(DisplayController.getNavigationMode(this));
- mAppTransitionManager = new QuickstepTransitionManager(this);
+ mAppTransitionManager = buildAppTransitionManager();
mAppTransitionManager.registerRemoteAnimations();
mAppTransitionManager.registerRemoteTransitions();
@@ -307,6 +308,13 @@
return mHotseatPredictionController;
}
+ /**
+ * Builds the {@link QuickstepTransitionManager} instance to use for managing transitions.
+ */
+ protected QuickstepTransitionManager buildAppTransitionManager() {
+ return new QuickstepTransitionManager(this);
+ }
+
@Override
protected QuickstepOnboardingPrefs createOnboardingPrefs(SharedPreferences sharedPrefs) {
return new QuickstepOnboardingPrefs(this, sharedPrefs);
@@ -997,7 +1005,12 @@
activityOptions.options.setSourceInfo(ActivityOptions.SourceInfo.TYPE_LAUNCHER,
mLastTouchUpTime);
}
- activityOptions.options.setSplashScreenStyle(SplashScreen.SPLASH_SCREEN_STYLE_ICON);
+ if (item != null && item.itemType == ITEM_TYPE_SEARCH_ACTION) {
+ activityOptions.options.setSplashScreenStyle(
+ SplashScreen.SPLASH_SCREEN_STYLE_SOLID_COLOR);
+ } else {
+ activityOptions.options.setSplashScreenStyle(SplashScreen.SPLASH_SCREEN_STYLE_ICON);
+ }
activityOptions.options.setLaunchDisplayId(
(v != null && v.getDisplay() != null) ? v.getDisplay().getDisplayId()
: Display.DEFAULT_DISPLAY);
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 4f10dde..3f6eb94 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -50,6 +50,7 @@
import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.CANCEL_RECENTS_ANIMATION;
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.EXPECTING_TASK_APPEARED;
+import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.LAUNCHER_DESTROYED;
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.ON_SETTLED_ON_END_TARGET;
import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD;
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
@@ -181,6 +182,7 @@
if (mActivity != activity) {
return;
}
+ ActiveGestureLog.INSTANCE.addLog("Launcher destroyed", LAUNCHER_DESTROYED);
mRecentsView = null;
mActivity = null;
}
diff --git a/quickstep/src/com/android/quickstep/util/ActiveGestureErrorDetector.java b/quickstep/src/com/android/quickstep/util/ActiveGestureErrorDetector.java
index 60065fb..2964868 100644
--- a/quickstep/src/com/android/quickstep/util/ActiveGestureErrorDetector.java
+++ b/quickstep/src/com/android/quickstep/util/ActiveGestureErrorDetector.java
@@ -20,7 +20,6 @@
import androidx.annotation.NonNull;
import java.io.PrintWriter;
-import java.util.List;
import java.util.Set;
/**
@@ -37,7 +36,7 @@
ON_SETTLED_ON_END_TARGET, START_RECENTS_ANIMATION, FINISH_RECENTS_ANIMATION,
CANCEL_RECENTS_ANIMATION, SET_ON_PAGE_TRANSITION_END_CALLBACK, CANCEL_CURRENT_ANIMATION,
CLEANUP_SCREENSHOT, SCROLLER_ANIMATION_ABORTED, TASK_APPEARED, EXPECTING_TASK_APPEARED,
- FLAG_USING_OTHER_ACTIVITY_INPUT_CONSUMER,
+ FLAG_USING_OTHER_ACTIVITY_INPUT_CONSUMER, LAUNCHER_DESTROYED,
/**
* These GestureEvents are specifically associated to state flags that get set in
@@ -68,288 +67,288 @@
protected static void analyseAndDump(
@NonNull String prefix,
@NonNull PrintWriter writer,
- List<ActiveGestureLog.EventLog> eventLogs) {
- writer.println(prefix + "ActiveGestureErrorDetector:");
- for (int i = 0; i < eventLogs.size(); i++) {
- ActiveGestureLog.EventLog eventLog = eventLogs.get(i);
- if (eventLog == null) {
+ @NonNull ActiveGestureLog.EventLog eventLog) {
+ writer.println(prefix + "Error messages for gesture ID: " + eventLog.logId);
+
+ boolean errorDetected = false;
+ // Use a Set since the order is inherently checked in the loop.
+ final Set<GestureEvent> encounteredEvents = new ArraySet<>();
+ // Set flags and check order of operations.
+ for (ActiveGestureLog.EventEntry eventEntry : eventLog.eventEntries) {
+ GestureEvent gestureEvent = eventEntry.getGestureEvent();
+ if (gestureEvent == null) {
continue;
}
- int gestureId = eventLog.logId;
- writer.println(prefix + "\tError messages for gesture ID: " + gestureId);
+ encounteredEvents.add(gestureEvent);
- boolean errorDetected = false;
- // Use a Set since the order is inherently checked in the loop.
- final Set<GestureEvent> encounteredEvents = new ArraySet<>();
- // Set flags and check order of operations.
- for (ActiveGestureLog.EventEntry eventEntry : eventLog.eventEntries) {
- GestureEvent gestureEvent = eventEntry.getGestureEvent();
- if (gestureEvent == null) {
- continue;
- }
- encounteredEvents.add(gestureEvent);
- switch (gestureEvent) {
- case MOTION_UP:
- errorDetected |= printErrorIfTrue(
- !encounteredEvents.contains(GestureEvent.MOTION_DOWN),
- prefix,
- /* errorMessage= */ "Motion up detected before/without"
- + " motion down.",
- writer);
- break;
- case ON_SETTLED_ON_END_TARGET:
- errorDetected |= printErrorIfTrue(
- !encounteredEvents.contains(GestureEvent.SET_END_TARGET),
- prefix,
- /* errorMessage= */ "onSettledOnEndTarget called "
- + "before/without setEndTarget.",
- writer);
- break;
- case FINISH_RECENTS_ANIMATION:
- errorDetected |= printErrorIfTrue(
- !encounteredEvents.contains(GestureEvent.START_RECENTS_ANIMATION),
- prefix,
- /* errorMessage= */ "finishRecentsAnimation called "
- + "before/without startRecentsAnimation.",
- writer);
- break;
- case CANCEL_RECENTS_ANIMATION:
- errorDetected |= printErrorIfTrue(
- !encounteredEvents.contains(GestureEvent.START_RECENTS_ANIMATION),
- prefix,
- /* errorMessage= */ "cancelRecentsAnimation called "
- + "before/without startRecentsAnimation.",
- writer);
- break;
- case CLEANUP_SCREENSHOT:
- errorDetected |= printErrorIfTrue(
- !encounteredEvents.contains(GestureEvent.STATE_SCREENSHOT_CAPTURED),
- prefix,
- /* errorMessage= */ "recents activity screenshot was "
- + "cleaned up before/without STATE_SCREENSHOT_CAPTURED "
- + "being set.",
- writer);
- break;
- case SCROLLER_ANIMATION_ABORTED:
- errorDetected |= printErrorIfTrue(
- encounteredEvents.contains(GestureEvent.SET_END_TARGET_HOME)
- && !encounteredEvents.contains(
- GestureEvent.ON_SETTLED_ON_END_TARGET),
- prefix,
- /* errorMessage= */ "recents view scroller animation "
- + "aborted after setting end target HOME, but before"
- + " settling on end target.",
- writer);
- break;
- case TASK_APPEARED:
- errorDetected |= printErrorIfTrue(
- !encounteredEvents.contains(GestureEvent.SET_END_TARGET_NEW_TASK),
- prefix,
- /* errorMessage= */ "onTasksAppeared called "
- + "before/without setting end target to new task",
- writer);
- errorDetected |= printErrorIfTrue(
- !encounteredEvents.contains(GestureEvent.EXPECTING_TASK_APPEARED),
- prefix,
- /* errorMessage= */ "onTasksAppeared was not expected to be called",
- writer);
- break;
- case EXPECTING_TASK_APPEARED:
- errorDetected |= printErrorIfTrue(
- !encounteredEvents.contains(GestureEvent.SET_END_TARGET_NEW_TASK),
- prefix,
- /* errorMessage= */ "expecting onTasksAppeared to be called "
- + "before/without setting end target to new task",
- writer);
- break;
- case STATE_GESTURE_COMPLETED:
- errorDetected |= printErrorIfTrue(
- !encounteredEvents.contains(GestureEvent.MOTION_UP),
- prefix,
- /* errorMessage= */ "STATE_GESTURE_COMPLETED set "
- + "before/without motion up.",
- writer);
- errorDetected |= printErrorIfTrue(
- !encounteredEvents.contains(GestureEvent.STATE_GESTURE_STARTED),
- prefix,
- /* errorMessage= */ "STATE_GESTURE_COMPLETED set "
- + "before/without STATE_GESTURE_STARTED.",
- writer);
- break;
- case STATE_GESTURE_CANCELLED:
- errorDetected |= printErrorIfTrue(
- !encounteredEvents.contains(GestureEvent.MOTION_UP),
- prefix,
- /* errorMessage= */ "STATE_GESTURE_CANCELLED set "
- + "before/without motion up.",
- writer);
- errorDetected |= printErrorIfTrue(
- !encounteredEvents.contains(GestureEvent.STATE_GESTURE_STARTED),
- prefix,
- /* errorMessage= */ "STATE_GESTURE_CANCELLED set "
- + "before/without STATE_GESTURE_STARTED.",
- writer);
- break;
- case STATE_SCREENSHOT_CAPTURED:
- errorDetected |= printErrorIfTrue(
- !encounteredEvents.contains(GestureEvent.STATE_CAPTURE_SCREENSHOT),
- prefix,
- /* errorMessage= */ "STATE_SCREENSHOT_CAPTURED set "
- + "before/without STATE_CAPTURE_SCREENSHOT.",
- writer);
- break;
- case STATE_RECENTS_SCROLLING_FINISHED:
- errorDetected |= printErrorIfTrue(
- !encounteredEvents.contains(
- GestureEvent.SET_ON_PAGE_TRANSITION_END_CALLBACK),
- prefix,
- /* errorMessage= */ "STATE_RECENTS_SCROLLING_FINISHED "
- + "set before/without calling "
- + "setOnPageTransitionEndCallback.",
- writer);
- break;
- case STATE_RECENTS_ANIMATION_CANCELED:
- errorDetected |= printErrorIfTrue(
- !encounteredEvents.contains(
- GestureEvent.START_RECENTS_ANIMATION),
- prefix,
- /* errorMessage= */ "STATE_RECENTS_ANIMATION_CANCELED "
- + "set before/without startRecentsAnimation.",
- writer);
- break;
- case MOTION_DOWN:
- case SET_END_TARGET:
- case SET_END_TARGET_HOME:
- case SET_END_TARGET_NEW_TASK:
- case START_RECENTS_ANIMATION:
- case SET_ON_PAGE_TRANSITION_END_CALLBACK:
- case CANCEL_CURRENT_ANIMATION:
- case FLAG_USING_OTHER_ACTIVITY_INPUT_CONSUMER:
- case STATE_GESTURE_STARTED:
- case STATE_END_TARGET_ANIMATION_FINISHED:
- case STATE_CAPTURE_SCREENSHOT:
- case STATE_HANDLER_INVALIDATED:
- case STATE_LAUNCHER_DRAWN:
- default:
- // No-Op
- }
+ switch (gestureEvent) {
+ case MOTION_UP:
+ errorDetected |= printErrorIfTrue(
+ !encounteredEvents.contains(GestureEvent.MOTION_DOWN),
+ prefix,
+ /* errorMessage= */ "Motion up detected before/without"
+ + " motion down.",
+ writer);
+ break;
+ case ON_SETTLED_ON_END_TARGET:
+ errorDetected |= printErrorIfTrue(
+ !encounteredEvents.contains(GestureEvent.SET_END_TARGET),
+ prefix,
+ /* errorMessage= */ "onSettledOnEndTarget called "
+ + "before/without setEndTarget.",
+ writer);
+ break;
+ case FINISH_RECENTS_ANIMATION:
+ errorDetected |= printErrorIfTrue(
+ !encounteredEvents.contains(GestureEvent.START_RECENTS_ANIMATION),
+ prefix,
+ /* errorMessage= */ "finishRecentsAnimation called "
+ + "before/without startRecentsAnimation.",
+ writer);
+ break;
+ case CANCEL_RECENTS_ANIMATION:
+ errorDetected |= printErrorIfTrue(
+ !encounteredEvents.contains(GestureEvent.START_RECENTS_ANIMATION),
+ prefix,
+ /* errorMessage= */ "cancelRecentsAnimation called "
+ + "before/without startRecentsAnimation.",
+ writer);
+ break;
+ case CLEANUP_SCREENSHOT:
+ errorDetected |= printErrorIfTrue(
+ !encounteredEvents.contains(GestureEvent.STATE_SCREENSHOT_CAPTURED),
+ prefix,
+ /* errorMessage= */ "recents activity screenshot was "
+ + "cleaned up before/without STATE_SCREENSHOT_CAPTURED "
+ + "being set.",
+ writer);
+ break;
+ case SCROLLER_ANIMATION_ABORTED:
+ errorDetected |= printErrorIfTrue(
+ encounteredEvents.contains(GestureEvent.SET_END_TARGET_HOME)
+ && !encounteredEvents.contains(
+ GestureEvent.ON_SETTLED_ON_END_TARGET),
+ prefix,
+ /* errorMessage= */ "recents view scroller animation "
+ + "aborted after setting end target HOME, but before"
+ + " settling on end target.",
+ writer);
+ break;
+ case TASK_APPEARED:
+ errorDetected |= printErrorIfTrue(
+ !encounteredEvents.contains(GestureEvent.SET_END_TARGET_NEW_TASK),
+ prefix,
+ /* errorMessage= */ "onTasksAppeared called "
+ + "before/without setting end target to new task",
+ writer);
+ errorDetected |= printErrorIfTrue(
+ !encounteredEvents.contains(GestureEvent.EXPECTING_TASK_APPEARED),
+ prefix,
+ /* errorMessage= */ "onTasksAppeared was not expected to be called",
+ writer);
+ break;
+ case EXPECTING_TASK_APPEARED:
+ errorDetected |= printErrorIfTrue(
+ !encounteredEvents.contains(GestureEvent.SET_END_TARGET_NEW_TASK),
+ prefix,
+ /* errorMessage= */ "expecting onTasksAppeared to be called "
+ + "before/without setting end target to new task",
+ writer);
+ break;
+ case LAUNCHER_DESTROYED:
+ errorDetected |= printErrorIfTrue(
+ true,
+ prefix,
+ /* errorMessage= */ "Launcher destroyed mid-gesture",
+ writer);
+ break;
+ case STATE_GESTURE_COMPLETED:
+ errorDetected |= printErrorIfTrue(
+ !encounteredEvents.contains(GestureEvent.MOTION_UP),
+ prefix,
+ /* errorMessage= */ "STATE_GESTURE_COMPLETED set "
+ + "before/without motion up.",
+ writer);
+ errorDetected |= printErrorIfTrue(
+ !encounteredEvents.contains(GestureEvent.STATE_GESTURE_STARTED),
+ prefix,
+ /* errorMessage= */ "STATE_GESTURE_COMPLETED set "
+ + "before/without STATE_GESTURE_STARTED.",
+ writer);
+ break;
+ case STATE_GESTURE_CANCELLED:
+ errorDetected |= printErrorIfTrue(
+ !encounteredEvents.contains(GestureEvent.MOTION_UP),
+ prefix,
+ /* errorMessage= */ "STATE_GESTURE_CANCELLED set "
+ + "before/without motion up.",
+ writer);
+ errorDetected |= printErrorIfTrue(
+ !encounteredEvents.contains(GestureEvent.STATE_GESTURE_STARTED),
+ prefix,
+ /* errorMessage= */ "STATE_GESTURE_CANCELLED set "
+ + "before/without STATE_GESTURE_STARTED.",
+ writer);
+ break;
+ case STATE_SCREENSHOT_CAPTURED:
+ errorDetected |= printErrorIfTrue(
+ !encounteredEvents.contains(GestureEvent.STATE_CAPTURE_SCREENSHOT),
+ prefix,
+ /* errorMessage= */ "STATE_SCREENSHOT_CAPTURED set "
+ + "before/without STATE_CAPTURE_SCREENSHOT.",
+ writer);
+ break;
+ case STATE_RECENTS_SCROLLING_FINISHED:
+ errorDetected |= printErrorIfTrue(
+ !encounteredEvents.contains(
+ GestureEvent.SET_ON_PAGE_TRANSITION_END_CALLBACK),
+ prefix,
+ /* errorMessage= */ "STATE_RECENTS_SCROLLING_FINISHED "
+ + "set before/without calling "
+ + "setOnPageTransitionEndCallback.",
+ writer);
+ break;
+ case STATE_RECENTS_ANIMATION_CANCELED:
+ errorDetected |= printErrorIfTrue(
+ !encounteredEvents.contains(
+ GestureEvent.START_RECENTS_ANIMATION),
+ prefix,
+ /* errorMessage= */ "STATE_RECENTS_ANIMATION_CANCELED "
+ + "set before/without startRecentsAnimation.",
+ writer);
+ break;
+ case MOTION_DOWN:
+ case SET_END_TARGET:
+ case SET_END_TARGET_HOME:
+ case SET_END_TARGET_NEW_TASK:
+ case START_RECENTS_ANIMATION:
+ case SET_ON_PAGE_TRANSITION_END_CALLBACK:
+ case CANCEL_CURRENT_ANIMATION:
+ case FLAG_USING_OTHER_ACTIVITY_INPUT_CONSUMER:
+ case STATE_GESTURE_STARTED:
+ case STATE_END_TARGET_ANIMATION_FINISHED:
+ case STATE_CAPTURE_SCREENSHOT:
+ case STATE_HANDLER_INVALIDATED:
+ case STATE_LAUNCHER_DRAWN:
+ default:
+ // No-Op
}
+ }
- // Check that all required events were found.
- errorDetected |= printErrorIfTrue(
- !encounteredEvents.contains(GestureEvent.MOTION_DOWN),
- prefix,
- /* errorMessage= */ "Motion down never detected.",
- writer);
- errorDetected |= printErrorIfTrue(
- !encounteredEvents.contains(GestureEvent.MOTION_UP),
- prefix,
- /* errorMessage= */ "Motion up never detected.",
- writer);
+ // Check that all required events were found.
+ errorDetected |= printErrorIfTrue(
+ !encounteredEvents.contains(GestureEvent.MOTION_DOWN),
+ prefix,
+ /* errorMessage= */ "Motion down never detected.",
+ writer);
+ errorDetected |= printErrorIfTrue(
+ !encounteredEvents.contains(GestureEvent.MOTION_UP),
+ prefix,
+ /* errorMessage= */ "Motion up never detected.",
+ writer);
- errorDetected |= printErrorIfTrue(
- /* condition= */ encounteredEvents.contains(GestureEvent.SET_END_TARGET)
- && !encounteredEvents.contains(GestureEvent.ON_SETTLED_ON_END_TARGET),
- prefix,
- /* errorMessage= */ "setEndTarget was called, but "
- + "onSettledOnEndTarget wasn't.",
- writer);
- errorDetected |= printErrorIfTrue(
- /* condition= */ encounteredEvents.contains(GestureEvent.SET_END_TARGET)
- && !encounteredEvents.contains(
- GestureEvent.STATE_END_TARGET_ANIMATION_FINISHED),
- prefix,
- /* errorMessage= */ "setEndTarget was called, but "
- + "STATE_END_TARGET_ANIMATION_FINISHED was never set.",
- writer);
- errorDetected |= printErrorIfTrue(
- /* condition= */ encounteredEvents.contains(GestureEvent.SET_END_TARGET)
- && !encounteredEvents.contains(
- GestureEvent.STATE_RECENTS_SCROLLING_FINISHED),
- prefix,
- /* errorMessage= */ "setEndTarget was called, but "
- + "STATE_RECENTS_SCROLLING_FINISHED was never set.",
- writer);
- errorDetected |= printErrorIfTrue(
- /* condition= */ encounteredEvents.contains(
- GestureEvent.STATE_END_TARGET_ANIMATION_FINISHED)
- && encounteredEvents.contains(
- GestureEvent.STATE_RECENTS_SCROLLING_FINISHED)
- && !encounteredEvents.contains(GestureEvent.ON_SETTLED_ON_END_TARGET),
- prefix,
- /* errorMessage= */ "STATE_END_TARGET_ANIMATION_FINISHED and "
- + "STATE_RECENTS_SCROLLING_FINISHED were set, but onSettledOnEndTarget "
- + "wasn't called.",
- writer);
+ errorDetected |= printErrorIfTrue(
+ /* condition= */ encounteredEvents.contains(GestureEvent.SET_END_TARGET)
+ && !encounteredEvents.contains(GestureEvent.ON_SETTLED_ON_END_TARGET),
+ prefix,
+ /* errorMessage= */ "setEndTarget was called, but "
+ + "onSettledOnEndTarget wasn't.",
+ writer);
+ errorDetected |= printErrorIfTrue(
+ /* condition= */ encounteredEvents.contains(GestureEvent.SET_END_TARGET)
+ && !encounteredEvents.contains(
+ GestureEvent.STATE_END_TARGET_ANIMATION_FINISHED),
+ prefix,
+ /* errorMessage= */ "setEndTarget was called, but "
+ + "STATE_END_TARGET_ANIMATION_FINISHED was never set.",
+ writer);
+ errorDetected |= printErrorIfTrue(
+ /* condition= */ encounteredEvents.contains(GestureEvent.SET_END_TARGET)
+ && !encounteredEvents.contains(
+ GestureEvent.STATE_RECENTS_SCROLLING_FINISHED),
+ prefix,
+ /* errorMessage= */ "setEndTarget was called, but "
+ + "STATE_RECENTS_SCROLLING_FINISHED was never set.",
+ writer);
+ errorDetected |= printErrorIfTrue(
+ /* condition= */ encounteredEvents.contains(
+ GestureEvent.STATE_END_TARGET_ANIMATION_FINISHED)
+ && encounteredEvents.contains(
+ GestureEvent.STATE_RECENTS_SCROLLING_FINISHED)
+ && !encounteredEvents.contains(GestureEvent.ON_SETTLED_ON_END_TARGET),
+ prefix,
+ /* errorMessage= */ "STATE_END_TARGET_ANIMATION_FINISHED and "
+ + "STATE_RECENTS_SCROLLING_FINISHED were set, but onSettledOnEndTarget "
+ + "wasn't called.",
+ writer);
- errorDetected |= printErrorIfTrue(
- /* condition= */ encounteredEvents.contains(
- GestureEvent.START_RECENTS_ANIMATION)
- && !encounteredEvents.contains(GestureEvent.FINISH_RECENTS_ANIMATION)
- && !encounteredEvents.contains(GestureEvent.CANCEL_RECENTS_ANIMATION),
- prefix,
- /* errorMessage= */ "startRecentsAnimation was called, but "
- + "finishRecentsAnimation and cancelRecentsAnimation weren't.",
- writer);
+ errorDetected |= printErrorIfTrue(
+ /* condition= */ encounteredEvents.contains(
+ GestureEvent.START_RECENTS_ANIMATION)
+ && !encounteredEvents.contains(GestureEvent.FINISH_RECENTS_ANIMATION)
+ && !encounteredEvents.contains(GestureEvent.CANCEL_RECENTS_ANIMATION),
+ prefix,
+ /* errorMessage= */ "startRecentsAnimation was called, but "
+ + "finishRecentsAnimation and cancelRecentsAnimation weren't.",
+ writer);
- errorDetected |= printErrorIfTrue(
- /* condition= */ encounteredEvents.contains(GestureEvent.STATE_GESTURE_STARTED)
- && !encounteredEvents.contains(GestureEvent.STATE_GESTURE_COMPLETED)
- && !encounteredEvents.contains(GestureEvent.STATE_GESTURE_CANCELLED),
- prefix,
- /* errorMessage= */ "STATE_GESTURE_STARTED was set, but "
- + "STATE_GESTURE_COMPLETED and STATE_GESTURE_CANCELLED weren't.",
- writer);
+ errorDetected |= printErrorIfTrue(
+ /* condition= */ encounteredEvents.contains(GestureEvent.STATE_GESTURE_STARTED)
+ && !encounteredEvents.contains(GestureEvent.STATE_GESTURE_COMPLETED)
+ && !encounteredEvents.contains(GestureEvent.STATE_GESTURE_CANCELLED),
+ prefix,
+ /* errorMessage= */ "STATE_GESTURE_STARTED was set, but "
+ + "STATE_GESTURE_COMPLETED and STATE_GESTURE_CANCELLED weren't.",
+ writer);
- errorDetected |= printErrorIfTrue(
- /* condition= */ encounteredEvents.contains(
- GestureEvent.STATE_CAPTURE_SCREENSHOT)
- && !encounteredEvents.contains(GestureEvent.STATE_SCREENSHOT_CAPTURED),
- prefix,
- /* errorMessage= */ "STATE_CAPTURE_SCREENSHOT was set, but "
- + "STATE_SCREENSHOT_CAPTURED wasn't.",
- writer);
+ errorDetected |= printErrorIfTrue(
+ /* condition= */ encounteredEvents.contains(
+ GestureEvent.STATE_CAPTURE_SCREENSHOT)
+ && !encounteredEvents.contains(GestureEvent.STATE_SCREENSHOT_CAPTURED),
+ prefix,
+ /* errorMessage= */ "STATE_CAPTURE_SCREENSHOT was set, but "
+ + "STATE_SCREENSHOT_CAPTURED wasn't.",
+ writer);
- errorDetected |= printErrorIfTrue(
- /* condition= */ encounteredEvents.contains(
- GestureEvent.SET_ON_PAGE_TRANSITION_END_CALLBACK)
- && !encounteredEvents.contains(
- GestureEvent.STATE_RECENTS_SCROLLING_FINISHED),
- prefix,
- /* errorMessage= */ "setOnPageTransitionEndCallback called, but "
- + "STATE_RECENTS_SCROLLING_FINISHED wasn't set.",
- writer);
+ errorDetected |= printErrorIfTrue(
+ /* condition= */ encounteredEvents.contains(
+ GestureEvent.SET_ON_PAGE_TRANSITION_END_CALLBACK)
+ && !encounteredEvents.contains(
+ GestureEvent.STATE_RECENTS_SCROLLING_FINISHED),
+ prefix,
+ /* errorMessage= */ "setOnPageTransitionEndCallback called, but "
+ + "STATE_RECENTS_SCROLLING_FINISHED wasn't set.",
+ writer);
- errorDetected |= printErrorIfTrue(
- /* condition= */ encounteredEvents.contains(
- GestureEvent.FLAG_USING_OTHER_ACTIVITY_INPUT_CONSUMER)
- && !encounteredEvents.contains(GestureEvent.CANCEL_CURRENT_ANIMATION)
- && !encounteredEvents.contains(GestureEvent.STATE_HANDLER_INVALIDATED),
- prefix,
- /* errorMessage= */ "AbsSwipeUpHandler.cancelCurrentAnimation "
- + "wasn't called and STATE_HANDLER_INVALIDATED wasn't set.",
- writer);
+ errorDetected |= printErrorIfTrue(
+ /* condition= */ encounteredEvents.contains(
+ GestureEvent.FLAG_USING_OTHER_ACTIVITY_INPUT_CONSUMER)
+ && !encounteredEvents.contains(GestureEvent.CANCEL_CURRENT_ANIMATION)
+ && !encounteredEvents.contains(GestureEvent.STATE_HANDLER_INVALIDATED),
+ prefix,
+ /* errorMessage= */ "AbsSwipeUpHandler.cancelCurrentAnimation "
+ + "wasn't called and STATE_HANDLER_INVALIDATED wasn't set.",
+ writer);
- errorDetected |= printErrorIfTrue(
- /* condition= */ encounteredEvents.contains(
- GestureEvent.STATE_RECENTS_ANIMATION_CANCELED)
- && !encounteredEvents.contains(GestureEvent.CLEANUP_SCREENSHOT),
- prefix,
- /* errorMessage= */ "STATE_RECENTS_ANIMATION_CANCELED was set but "
- + "the task screenshot wasn't cleaned up.",
- writer);
+ errorDetected |= printErrorIfTrue(
+ /* condition= */ encounteredEvents.contains(
+ GestureEvent.STATE_RECENTS_ANIMATION_CANCELED)
+ && !encounteredEvents.contains(GestureEvent.CLEANUP_SCREENSHOT),
+ prefix,
+ /* errorMessage= */ "STATE_RECENTS_ANIMATION_CANCELED was set but "
+ + "the task screenshot wasn't cleaned up.",
+ writer);
- errorDetected |= printErrorIfTrue(
- /* condition= */ encounteredEvents.contains(
- GestureEvent.EXPECTING_TASK_APPEARED)
- && !encounteredEvents.contains(GestureEvent.TASK_APPEARED),
- prefix,
- /* errorMessage= */ "onTaskAppeared was expected to be called but wasn't.",
- writer);
+ errorDetected |= printErrorIfTrue(
+ /* condition= */ encounteredEvents.contains(
+ GestureEvent.EXPECTING_TASK_APPEARED)
+ && !encounteredEvents.contains(GestureEvent.TASK_APPEARED),
+ prefix,
+ /* errorMessage= */ "onTaskAppeared was expected to be called but wasn't.",
+ writer);
- if (!errorDetected) {
- writer.println(prefix + "\t\tNo errors detected.");
- }
+ if (!errorDetected) {
+ writer.println(prefix + "\tNo errors detected.");
}
}
@@ -358,7 +357,8 @@
if (!condition) {
return false;
}
- writer.println(prefix + "\t\t- " + errorMessage);
+ writer.println(prefix + "\t- " + errorMessage);
+
return true;
}
}
diff --git a/quickstep/src/com/android/quickstep/util/ActiveGestureLog.java b/quickstep/src/com/android/quickstep/util/ActiveGestureLog.java
index 23fdd58..e05d85c 100644
--- a/quickstep/src/com/android/quickstep/util/ActiveGestureLog.java
+++ b/quickstep/src/com/android/quickstep/util/ActiveGestureLog.java
@@ -155,19 +155,27 @@
}
public void dump(String prefix, PrintWriter writer) {
+ if (FeatureFlags.ENABLE_GESTURE_ERROR_DETECTION.get()) {
+ writer.println(prefix + "ActiveGestureErrorDetector:");
+ for (int i = 0; i < logs.length; i++) {
+ EventLog eventLog = logs[(nextIndex + i) % logs.length];
+ if (eventLog == null) {
+ continue;
+ }
+ ActiveGestureErrorDetector.analyseAndDump(prefix + '\t', writer, eventLog);
+ }
+ }
+
writer.println(prefix + "ActiveGestureLog history:");
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSSZ ", Locale.US);
Date date = new Date();
- ArrayList<EventLog> eventLogs = new ArrayList<>();
-
for (int i = 0; i < logs.length; i++) {
EventLog eventLog = logs[(nextIndex + i) % logs.length];
if (eventLog == null) {
continue;
}
- eventLogs.add(eventLog);
- writer.println(prefix + "\tLogs for logId: " + eventLog.logId);
+ writer.println(prefix + "\tLogs for logId: " + eventLog.logId);
for (EventEntry eventEntry : eventLog.eventEntries) {
date.setTime(eventEntry.time);
@@ -199,10 +207,6 @@
writer.println(msg);
}
}
-
- if (FeatureFlags.ENABLE_GESTURE_ERROR_DETECTION.get()) {
- ActiveGestureErrorDetector.analyseAndDump(prefix + '\t', writer, eventLogs);
- }
}
/**
diff --git a/quickstep/src/com/android/quickstep/views/DesktopTaskView.java b/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
index dc265e4..0ac682f 100644
--- a/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
@@ -24,6 +24,8 @@
import android.content.Context;
import android.graphics.Point;
import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.LayerDrawable;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.RoundRectShape;
import android.os.SystemProperties;
@@ -31,14 +33,16 @@
import android.util.Log;
import android.util.SparseArray;
import android.view.MotionEvent;
+import android.view.View;
+import android.widget.FrameLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
+import com.android.launcher3.R;
import com.android.launcher3.Utilities;
-import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.util.RunnableList;
import com.android.quickstep.RecentsModel;
import com.android.quickstep.SystemUiProxy;
@@ -87,7 +91,7 @@
private final ArrayList<CancellableTask<?>> mPendingThumbnailRequests = new ArrayList<>();
- private ShapeDrawable mBackground;
+ private View mBackgroundView;
public DesktopTaskView(Context context) {
this(context, null);
@@ -104,14 +108,28 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
+
+ mBackgroundView = findViewById(R.id.background);
+
+ int topMarginPx =
+ mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx;
+ FrameLayout.LayoutParams params = (LayoutParams) mBackgroundView.getLayoutParams();
+ params.topMargin = topMarginPx;
+ mBackgroundView.setLayoutParams(params);
+
float[] outerRadii = new float[8];
Arrays.fill(outerRadii, getTaskCornerRadius());
RoundRectShape shape = new RoundRectShape(outerRadii, null, null);
- mBackground = new ShapeDrawable(shape);
- mBackground.setTint(getResources().getColor(android.R.color.system_neutral2_300,
+ ShapeDrawable background = new ShapeDrawable(shape);
+ background.setTint(getResources().getColor(android.R.color.system_neutral2_300,
getContext().getTheme()));
// TODO(b/244348395): this should be wallpaper
- setBackground(mBackground);
+ mBackgroundView.setBackground(background);
+
+ Drawable icon = getResources().getDrawable(R.drawable.ic_desktop, getContext().getTheme());
+ Drawable iconBackground = getResources().getDrawable(R.drawable.bg_circle,
+ getContext().getTheme());
+ mIconView.setDrawable(new LayerDrawable(new Drawable[]{iconBackground, icon}));
}
@Override
@@ -252,20 +270,9 @@
}
@Override
- public void setOrientationState(RecentsOrientedState orientationState) {
- // TODO(b/249371338): this copies logic from TaskView
- PagedOrientationHandler orientationHandler = orientationState.getOrientationHandler();
- boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
+ protected void setThumbnailOrientation(RecentsOrientedState orientationState) {
DeviceProfile deviceProfile = mActivity.getDeviceProfile();
-
- LayoutParams iconParams = (LayoutParams) mIconView.getLayoutParams();
-
int thumbnailTopMargin = deviceProfile.overviewTaskThumbnailTopMarginPx;
- int taskIconHeight = deviceProfile.overviewTaskIconSizePx;
- int taskMargin = deviceProfile.overviewTaskMarginPx;
-
- orientationHandler.setTaskIconParams(iconParams, taskMargin, taskIconHeight,
- thumbnailTopMargin, isRtl);
LayoutParams snapshotParams = (LayoutParams) mSnapshotView.getLayoutParams();
snapshotParams.topMargin = thumbnailTopMargin;
@@ -374,6 +381,9 @@
setMeasuredDimension(containerWidth, containerHeight);
+ int thumbnailTopMarginPx = mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx;
+ containerHeight -= thumbnailTopMarginPx;
+
int thumbnails = mSnapshotViewMap.size();
if (thumbnails == 0) {
return;
@@ -416,6 +426,8 @@
}
int taskX = (int) (positionInParent.x * scaleWidth);
int taskY = (int) (positionInParent.y * scaleHeight);
+ // move task down by margin size
+ taskY += thumbnailTopMarginPx;
thumbnailView.setX(taskX);
thumbnailView.setY(taskY);
@@ -439,9 +451,9 @@
mFullscreenProgress = progress;
if (mFullscreenProgress > 0) {
// Don't show background while we are transitioning to/from fullscreen
- setBackground(null);
+ mBackgroundView.setVisibility(INVISIBLE);
} else {
- setBackground(mBackground);
+ mBackgroundView.setVisibility(VISIBLE);
}
for (int i = 0; i < mSnapshotViewMap.size(); i++) {
TaskThumbnailView thumbnailView = mSnapshotViewMap.valueAt(i);
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index 829e72c..d3c7778 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -996,6 +996,11 @@
}
public void setOrientationState(RecentsOrientedState orientationState) {
+ setIconOrientation(orientationState);
+ setThumbnailOrientation(orientationState);
+ }
+
+ protected void setIconOrientation(RecentsOrientedState orientationState) {
PagedOrientationHandler orientationHandler = orientationState.getOrientationHandler();
boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
DeviceProfile deviceProfile = mActivity.getDeviceProfile();
@@ -1016,6 +1021,11 @@
int iconDrawableSize = isGridTask ? deviceProfile.overviewTaskIconDrawableSizeGridPx
: deviceProfile.overviewTaskIconDrawableSizePx;
mIconView.setDrawableSize(iconDrawableSize, iconDrawableSize);
+ }
+
+ protected void setThumbnailOrientation(RecentsOrientedState orientationState) {
+ DeviceProfile deviceProfile = mActivity.getDeviceProfile();
+ int thumbnailTopMargin = deviceProfile.overviewTaskThumbnailTopMarginPx;
LayoutParams snapshotParams = (LayoutParams) mSnapshotView.getLayoutParams();
snapshotParams.topMargin = thumbnailTopMargin;
diff --git a/res/drawable/ic_desktop.xml b/res/drawable/ic_desktop.xml
new file mode 100644
index 0000000..dfaf8b8
--- /dev/null
+++ b/res/drawable/ic_desktop.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 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.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="32.0dp"
+ android:height="32.0dp"
+ android:viewportWidth="32.0"
+ android:viewportHeight="32.0"
+ >
+ <group android:scaleX="0.5"
+ android:scaleY="0.5"
+ android:translateX="6.0"
+ android:translateY="6.0">
+ <path
+ android:fillColor="?android:attr/textColorPrimary"
+ android:pathData="M5.958,37.708Q4.458,37.708 3.354,36.604Q2.25,35.5 2.25,34V18.292Q2.25,16.792 3.354,15.688Q4.458,14.583 5.958,14.583H9.5V5.958Q9.5,4.458 10.625,3.354Q11.75,2.25 13.208,2.25H34Q35.542,2.25 36.646,3.354Q37.75,4.458 37.75,5.958V21.667Q37.75,23.167 36.646,24.271Q35.542,25.375 34,25.375H30.5V34Q30.5,35.5 29.396,36.604Q28.292,37.708 26.792,37.708ZM5.958,34H26.792Q26.792,34 26.792,34Q26.792,34 26.792,34V21.542H5.958V34Q5.958,34 5.958,34Q5.958,34 5.958,34ZM30.5,21.667H34Q34,21.667 34,21.667Q34,21.667 34,21.667V9.208H13.208V14.583H26.833Q28.375,14.583 29.438,15.667Q30.5,16.75 30.5,18.25Z"/>
+ </group>
+</vector>
diff --git a/res/drawable/widget_suggestions.xml b/res/drawable/widget_suggestions.xml
new file mode 100644
index 0000000..b090a68
--- /dev/null
+++ b/res/drawable/widget_suggestions.xml
@@ -0,0 +1,27 @@
+<!--
+Copyright (C) 2023 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="@color/widget_picker_background_selected"
+ android:gravity="center"
+ >
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M16.65,13 L11,7.35 16.65,1.7 22.3,7.35ZM3,11V3H11V11ZM13,21V13H21V21ZM3,21V13H11V21ZM5,9H9V5H5ZM16.675,10.2 L19.5,7.375 16.675,4.55 13.85,7.375ZM15,19H19V15H15ZM5,19H9V15H5ZM9,9ZM13.85,7.375ZM9,15ZM15,15Z"/>
+</vector>
diff --git a/res/drawable/widget_suggestions_icon.xml b/res/drawable/widget_suggestions_icon.xml
new file mode 100644
index 0000000..919b5e4
--- /dev/null
+++ b/res/drawable/widget_suggestions_icon.xml
@@ -0,0 +1,30 @@
+<!--
+Copyright (C) 2023 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.
+-->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item>
+ <shape android:shape="oval">
+ <size
+ android:width="48dp"
+ android:height="48dp" />
+ <solid android:color="@color/surface"/>
+ </shape>
+ </item>
+ <item
+ android:width="24dp"
+ android:height="24dp"
+ android:drawable="@drawable/widget_suggestions"
+ android:gravity="center" />
+</layer-list>
diff --git a/res/layout/widgets_full_sheet_large_screen.xml b/res/layout/widgets_full_sheet_large_screen.xml
new file mode 100644
index 0000000..3dbe6f5
--- /dev/null
+++ b/res/layout/widgets_full_sheet_large_screen.xml
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<com.android.launcher3.widget.picker.WidgetsFullSheet xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:theme="?attr/widgetsTheme">
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:id="@+id/container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@drawable/bg_widgets_full_sheet"
+ android:focusable="true"
+ android:importantForAccessibility="no">
+
+ <FrameLayout
+ android:id="@+id/recycler_view_container"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ app:layout_constraintEnd_toStartOf="@id/right_pane"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/title"
+ app:layout_constraintWidth_percent="0.33">
+
+ <TextView
+ android:id="@+id/no_widgets_text"
+ style="@style/PrimaryHeadline"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:textSize="18sp"
+ android:visibility="gone"
+ tools:text="No widgets available" />
+
+ <TextView
+ android:id="@+id/fast_scroller_popup"
+ style="@style/FastScrollerPopup"
+ android:layout_marginEnd="@dimen/fastscroll_popup_margin" />
+
+ <!-- Fast scroller popup -->
+ <com.android.launcher3.views.RecyclerViewFastScroller
+ android:id="@+id/fast_scroller"
+ android:layout_width="@dimen/fastscroll_width"
+ android:layout_height="match_parent"
+ android:layout_marginEnd="@dimen/fastscroll_end_margin" />
+
+ <com.android.launcher3.widget.picker.WidgetsRecyclerView
+ android:id="@+id/search_widgets_list_view"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:clipToPadding="false"
+ android:paddingHorizontal="@dimen/widget_list_horizontal_margin_large_screen"
+ android:visibility="gone" />
+ </FrameLayout>
+
+ <ScrollView
+ android:id="@+id/right_pane"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toEndOf="@id/recycler_view_container"
+ app:layout_constraintTop_toBottomOf="@id/title"
+ app:layout_constraintBottom_toBottomOf="parent"
+ android:paddingEnd="16dp"
+ android:paddingStart="8dp"
+ android:layout_marginTop="26dp"
+ app:layout_constraintWidth_percent="0.67">
+
+ <com.android.launcher3.widget.picker.WidgetsRecommendationTableLayout
+ android:id="@+id/recommended_widget_table"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@drawable/widgets_surface_background"
+ android:paddingHorizontal="@dimen/widget_list_horizontal_margin_large_screen"
+ android:paddingVertical="@dimen/recommended_widgets_table_vertical_padding"
+ android:visibility="gone" />
+ </ScrollView>
+
+ <View
+ android:id="@+id/collapse_handle"
+ android:layout_width="@dimen/bottom_sheet_handle_width"
+ android:layout_height="@dimen/bottom_sheet_handle_height"
+ android:layout_marginTop="@dimen/bottom_sheet_handle_margin"
+ android:background="@drawable/bg_rounded_corner_bottom_sheet_handle"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <TextView
+ android:id="@+id/title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/collapse_handle"
+ android:layout_marginTop="24dp"
+ android:gravity="center_horizontal"
+ android:paddingHorizontal="@dimen/widget_list_horizontal_margin_large_screen"
+ android:text="@string/widget_button_text"
+ android:textColor="?android:attr/textColorSecondary"
+ android:textSize="24sp" />
+
+ </androidx.constraintlayout.widget.ConstraintLayout>
+</com.android.launcher3.widget.picker.WidgetsFullSheet>
diff --git a/res/layout/widgets_full_sheet_paged_view_large_screen.xml b/res/layout/widgets_full_sheet_paged_view_large_screen.xml
new file mode 100644
index 0000000..6634345
--- /dev/null
+++ b/res/layout/widgets_full_sheet_paged_view_large_screen.xml
@@ -0,0 +1,122 @@
+<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2023 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.
+-->
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:launcher="http://schemas.android.com/apk/res-auto"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
+
+ <FrameLayout
+ android:id="@+id/widgets_full_sheet_paged_view_large_screen"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ app:layout_constraintEnd_toStartOf="@id/scrollView"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/title"
+ app:layout_constraintWidth_percent="0.33">
+ <com.android.launcher3.widget.picker.WidgetPagedView
+ android:id="@+id/widgets_view_pager"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:clipToPadding="false"
+ android:descendantFocusability="afterDescendants"
+ android:paddingHorizontal="@dimen/widget_list_horizontal_margin_large_screen"
+ launcher:pageIndicator="@+id/tabs" >
+
+ <com.android.launcher3.widget.picker.WidgetsRecyclerView
+ android:id="@+id/primary_widgets_list_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:clipToPadding="false" />
+
+ <com.android.launcher3.widget.picker.WidgetsRecyclerView
+ android:id="@+id/work_widgets_list_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:clipToPadding="false" />
+
+ </com.android.launcher3.widget.picker.WidgetPagedView>
+
+ <!-- SearchAndRecommendationsView without the tab layout as well -->
+ <com.android.launcher3.views.StickyHeaderLayout
+ android:id="@+id/search_and_recommendations_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <FrameLayout
+ android:id="@+id/search_bar_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="?android:attr/colorBackground"
+ android:clipToPadding="false"
+ android:elevation="0.1dp"
+ android:paddingBottom="8dp"
+ android:paddingHorizontal="@dimen/widget_list_horizontal_margin_large_screen"
+ launcher:layout_sticky="true">
+
+ <include layout="@layout/widgets_search_bar" />
+ </FrameLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:id="@+id/suggestions_header"
+ android:layout_marginTop="8dp"
+ android:layout_marginHorizontal="@dimen/widget_list_horizontal_margin_large_screen"
+ android:orientation="horizontal">
+ </LinearLayout>
+
+ <com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip
+ android:id="@+id/tabs"
+ android:layout_width="match_parent"
+ android:layout_height="64dp"
+ android:gravity="center_horizontal"
+ android:orientation="horizontal"
+ android:paddingVertical="8dp"
+ android:layout_marginHorizontal="@dimen/widget_list_horizontal_margin_large_screen"
+ android:background="?android:attr/colorBackground"
+ style="@style/TextHeadline"
+ launcher:layout_sticky="true">
+
+ <Button
+ android:id="@+id/tab_personal"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_marginEnd="@dimen/widget_tabs_button_horizontal_padding"
+ android:layout_marginVertical="@dimen/widget_apps_tabs_vertical_padding"
+ android:layout_weight="1"
+ android:background="@drawable/all_apps_tabs_background"
+ android:text="@string/widgets_full_sheet_personal_tab"
+ android:textColor="@color/all_apps_tab_text"
+ android:textSize="14sp"
+ style="?android:attr/borderlessButtonStyle" />
+
+ <Button
+ android:id="@+id/tab_work"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_marginEnd="@dimen/widget_tabs_button_horizontal_padding"
+ android:layout_marginVertical="@dimen/widget_apps_tabs_vertical_padding"
+ android:layout_weight="1"
+ android:background="@drawable/all_apps_tabs_background"
+ android:text="@string/widgets_full_sheet_work_tab"
+ android:textColor="@color/all_apps_tab_text"
+ android:textSize="14sp"
+ style="?android:attr/borderlessButtonStyle" />
+
+ </com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip>
+ </com.android.launcher3.views.StickyHeaderLayout>
+ </FrameLayout>
+</merge>
diff --git a/res/layout/widgets_full_sheet_recyclerview_large_screen.xml b/res/layout/widgets_full_sheet_recyclerview_large_screen.xml
new file mode 100644
index 0000000..212cd55
--- /dev/null
+++ b/res/layout/widgets_full_sheet_recyclerview_large_screen.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="utf-8"?><!-- 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.
+-->
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:launcher="http://schemas.android.com/apk/res-auto"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
+
+ <FrameLayout
+ android:id="@+id/widgets_full_sheet_recyclerview_large_screen"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ app:layout_constraintEnd_toStartOf="@id/scrollView"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/title"
+ app:layout_constraintWidth_percent="0.33">
+
+ <com.android.launcher3.widget.picker.WidgetsRecyclerView
+ android:id="@+id/primary_widgets_list_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginHorizontal="@dimen/widget_list_horizontal_margin_large_screen"
+ android:clipToPadding="false" />
+
+ <!-- SearchAndRecommendationsView without the tab layout as well -->
+ <com.android.launcher3.views.StickyHeaderLayout
+ android:id="@+id/search_and_recommendations_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <FrameLayout
+ android:id="@+id/search_bar_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="?android:attr/colorBackground"
+ android:clipToPadding="false"
+ android:elevation="0.1dp"
+ android:paddingBottom="8dp"
+ android:paddingHorizontal="@dimen/widget_list_horizontal_margin_large_screen"
+ launcher:layout_sticky="true">
+
+ <include layout="@layout/widgets_search_bar" />
+ </FrameLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:id="@+id/suggestions_header"
+ android:layout_marginTop="8dp"
+ android:layout_marginHorizontal="@dimen/widget_list_horizontal_margin_large_screen"
+ android:orientation="horizontal">
+ </LinearLayout>
+ </com.android.launcher3.views.StickyHeaderLayout>
+ </FrameLayout>
+</merge>
diff --git a/res/values-sw720dp-land/dimens.xml b/res/values-sw720dp-land/dimens.xml
index 6362960..b89910d 100644
--- a/res/values-sw720dp-land/dimens.xml
+++ b/res/values-sw720dp-land/dimens.xml
@@ -31,6 +31,7 @@
<!-- Widget picker-->
<dimen name="widget_list_horizontal_margin">49dp</dimen>
+ <dimen name="widget_list_horizontal_margin_large_screen">24dp</dimen>
<!-- Bottom sheet-->
<dimen name="bottom_sheet_extra_top_padding">0dp</dimen>
diff --git a/res/values-v31/colors.xml b/res/values-v31/colors.xml
index 63a5454..f87d9fc 100644
--- a/res/values-v31/colors.xml
+++ b/res/values-v31/colors.xml
@@ -64,4 +64,6 @@
<color name="all_apps_button_color_light">@android:color/system_neutral2_700</color>
<color name="all_apps_button_color_dark">@android:color/system_neutral2_200</color>
+
+ <color name="widget_picker_background_selected">@android:color/system_accent2_100</color>
</resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index a9638f9..9d2aa06 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -192,6 +192,7 @@
<dimen name="widget_list_header_view_vertical_padding">20dp</dimen>
<dimen name="widget_list_entry_spacing">2dp</dimen>
<dimen name="widget_list_horizontal_margin">16dp</dimen>
+ <dimen name="widget_list_horizontal_margin_large_screen">24dp</dimen>
<dimen name="widget_preview_shadow_blur">0.5dp</dimen>
<dimen name="widget_preview_key_shadow_distance">1dp</dimen>
diff --git a/res/values/id.xml b/res/values/id.xml
index 52a7e98..375750f 100644
--- a/res/values/id.xml
+++ b/res/values/id.xml
@@ -19,7 +19,6 @@
<item type="id" name="view_type_widgets_space" />
<item type="id" name="view_type_widgets_list" />
<item type="id" name="view_type_widgets_header" />
- <item type="id" name="view_type_widgets_search_header" />
<!-- Used for A11y actions in staged split to identify each task uniquely -->
<item type="id" name="split_topLeft_appInfo" />
<item type="id" name="split_bottomRight_appInfo" />
diff --git a/res/values/strings.xml b/res/values/strings.xml
index a2ebf16..190a3a5 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -63,6 +63,9 @@
<!-- Accessibility spoken message announced when a widget gets added to the home screen using a
button in a dialog. [CHAR_LIMIT=none] -->
<string name="added_to_home_screen_accessibility_text"><xliff:g id="widget_name" example="Calendar month view">%1$s</xliff:g> widget added to home screen</string>
+ <!-- Widget suggestions header title in the full widgets picker for large screen devices
+ in landscape mode. [CHAR_LIMIT=50] -->
+ <string name="suggested_widgets_header_title">Suggestions</string>
<!-- Label for showing the number of widgets an app has in the full widgets picker.
[CHAR_LIMIT=25][ICU SYNTAX] -->
<string name="widgets_count">
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 086cf05..2c34b3f 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -578,15 +578,16 @@
dimensionOverrideProvider.accept(this);
// This is done last, after iconSizePx is calculated above.
- mDotRendererWorkSpace = createDotRenderer(iconSizePx, dotRendererCache);
- mDotRendererAllApps = createDotRenderer(allAppsIconSizePx, dotRendererCache);
+ mDotRendererWorkSpace = createDotRenderer(context, iconSizePx, dotRendererCache);
+ mDotRendererAllApps = createDotRenderer(context, allAppsIconSizePx, dotRendererCache);
}
private static DotRenderer createDotRenderer(
- int size, @NonNull SparseArray<DotRenderer> cache) {
+ @NonNull Context context, int size, @NonNull SparseArray<DotRenderer> cache) {
DotRenderer renderer = cache.get(size);
if (renderer == null) {
- renderer = new DotRenderer(size, getShapePath(DEFAULT_DOT_SIZE), DEFAULT_DOT_SIZE);
+ renderer = new DotRenderer(size, getShapePath(context, DEFAULT_DOT_SIZE),
+ DEFAULT_DOT_SIZE);
cache.put(size, renderer);
}
return renderer;
diff --git a/src/com/android/launcher3/FastScrollRecyclerView.java b/src/com/android/launcher3/FastScrollRecyclerView.java
index 3504b24..e1a216e 100644
--- a/src/com/android/launcher3/FastScrollRecyclerView.java
+++ b/src/com/android/launcher3/FastScrollRecyclerView.java
@@ -63,6 +63,9 @@
public void bindFastScrollbar() {
ViewGroup parent = (ViewGroup) getParent().getParent();
+ if (parent.findViewById(R.id.fast_scroller) == null) {
+ parent = (ViewGroup) parent.getParent();
+ }
mScrollbar = parent.findViewById(R.id.fast_scroller);
mScrollbar.setRecyclerView(this, parent.findViewById(R.id.fast_scroller_popup));
onUpdateScrollbar(0);
diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
index c3d24f9..dd37bab 100644
--- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
@@ -1101,15 +1101,26 @@
@Override
public void drawOnScrimWithScale(Canvas canvas, float scale) {
- boolean isTablet = mActivityContext.getDeviceProfile().isTablet;
+ final boolean isTablet = mActivityContext.getDeviceProfile().isTablet;
+ final View panel = mBottomSheetBackground;
+ final float translationY = ((View) panel.getParent()).getTranslationY();
+ final float horizontalScaleOffset = (1 - scale) * panel.getWidth() / 2;
+ final float verticalScaleOffset = (1 - scale) * (panel.getHeight() - getHeight() / 2);
+
+ final float topNoScale = panel.getTop() + translationY;
+ final float topWithScale = topNoScale + verticalScaleOffset;
+ final float leftWithScale = panel.getLeft() + horizontalScaleOffset;
+ final float rightWithScale = panel.getRight() - horizontalScaleOffset;
// Draw full background panel for tablets.
if (isTablet) {
mHeaderPaint.setColor(mBottomSheetBackgroundColor);
- View panel = (View) mBottomSheetBackground;
- float translationY = ((View) panel.getParent()).getTranslationY();
- mTmpRectF.set(panel.getLeft(), panel.getTop() + translationY,
- panel.getRight(), panel.getBottom());
+
+ mTmpRectF.set(
+ leftWithScale,
+ topWithScale,
+ rightWithScale,
+ panel.getBottom());
mTmpPath.reset();
mTmpPath.addRoundRect(mTmpRectF, mBottomSheetCornerRadii, Direction.CW);
canvas.drawPath(mTmpPath, mHeaderPaint);
@@ -1125,25 +1136,33 @@
if (mHeaderPaint.getColor() == mScrimColor || mHeaderPaint.getColor() == 0) {
return;
}
- final float offset = (getVisibleContainerView().getHeight() * (1 - scale) / 2);
- final float bottom =
- scale * (getHeaderBottom() + getVisibleContainerView().getPaddingTop()) + offset;
- FloatingHeaderView headerView = getFloatingHeaderView();
+
+ // Draw header on background panel
+ final float headerBottomNoScale =
+ getHeaderBottom() + getVisibleContainerView().getPaddingTop();
+ final float headerHeightNoScale = headerBottomNoScale - topNoScale;
+ final float headerBottomWithScaleOnTablet = topWithScale + headerHeightNoScale * scale;
+ final float headerBottomOffset = (getVisibleContainerView().getHeight() * (1 - scale) / 2);
+ final float headerBottomWithScaleOnPhone = headerBottomNoScale * scale + headerBottomOffset;
+ final FloatingHeaderView headerView = getFloatingHeaderView();
if (isTablet) {
// Start adding header protection if search bar or tabs will attach to the top.
- if (!isSearchBarOnBottom() || mUsingTabs) {
- View panel = (View) mBottomSheetBackground;
- float translationY = ((View) panel.getParent()).getTranslationY();
- mTmpRectF.set(panel.getLeft(), panel.getTop() + translationY, panel.getRight(),
- bottom);
+ if (!FeatureFlags.ENABLE_FLOATING_SEARCH_BAR.get() || mUsingTabs) {
+ mTmpRectF.set(
+ leftWithScale,
+ topWithScale,
+ rightWithScale,
+ headerBottomWithScaleOnTablet);
mTmpPath.reset();
mTmpPath.addRoundRect(mTmpRectF, mBottomSheetCornerRadii, Direction.CW);
canvas.drawPath(mTmpPath, mHeaderPaint);
}
} else {
- canvas.drawRect(0, 0, canvas.getWidth(), bottom, mHeaderPaint);
+ canvas.drawRect(0, 0, canvas.getWidth(), headerBottomWithScaleOnPhone, mHeaderPaint);
}
- int tabsHeight = headerView.getPeripheralProtectionHeight();
+
+ // If tab exist (such as work profile), extend header with tab height
+ final int tabsHeight = headerView.getPeripheralProtectionHeight();
if (mTabsProtectionAlpha > 0 && tabsHeight != 0) {
if (DEBUG_HEADER_PROTECTION) {
mHeaderPaint.setColor(Color.BLUE);
@@ -1151,13 +1170,24 @@
} else {
mHeaderPaint.setAlpha((int) (getAlpha() * mTabsProtectionAlpha));
}
- int left = 0;
- int right = canvas.getWidth();
+ float left = 0f;
+ float right = canvas.getWidth();
if (isTablet) {
- left = mBottomSheetBackground.getLeft();
- right = mBottomSheetBackground.getRight();
+ left = mBottomSheetBackground.getLeft() + horizontalScaleOffset;
+ right = mBottomSheetBackground.getRight() - horizontalScaleOffset;
}
- canvas.drawRect(left, bottom, right, bottom + tabsHeight, mHeaderPaint);
+
+ final float tabTopWithScale = isTablet
+ ? headerBottomWithScaleOnTablet
+ : headerBottomWithScaleOnPhone;
+ final float tabBottomWithScale = tabTopWithScale + tabsHeight * scale;
+
+ canvas.drawRect(
+ left,
+ tabTopWithScale,
+ right,
+ tabBottomWithScale,
+ mHeaderPaint);
}
}
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 2dc3e70..68b33bc 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -96,6 +96,9 @@
"ENABLE_EXPANDING_PAUSE_WORK_BUTTON", false,
"Expand and collapse pause work button while scrolling");
+ public static final BooleanFlag ENABLE_RECENT_BLOCK = getDebugFlag("ENABLE_RECENT_BLOCK",
+ false, "Show recently tapped search target block in zero state");
+
public static final BooleanFlag COLLECT_SEARCH_HISTORY = new DeviceFlag(
"COLLECT_SEARCH_HISTORY", false, "Allow launcher to collect search history for log");
@@ -379,6 +382,10 @@
"Enable the ability to generate monochromatic icons, if it is not provided by the app"
);
+ public static final BooleanFlag ENABLE_DREAM_TRANSITION = getDebugFlag(
+ "ENABLE_DREAM_TRANSITION", true,
+ "Enable the launcher transition when the device enters a dream");
+
public static final BooleanFlag ENABLE_TASKBAR_EDU_TOOLTIP = getDebugFlag(
"ENABLE_TASKBAR_EDU_TOOLTIP", true,
"Enable the tooltip version of the Taskbar education flow.");
diff --git a/src/com/android/launcher3/graphics/PreloadIconDrawable.java b/src/com/android/launcher3/graphics/PreloadIconDrawable.java
index f2fde0e..8efd12a 100644
--- a/src/com/android/launcher3/graphics/PreloadIconDrawable.java
+++ b/src/com/android/launcher3/graphics/PreloadIconDrawable.java
@@ -138,7 +138,8 @@
IconPalette.getPreloadProgressColor(context, info.bitmap.color),
getPreloadColors(context),
Utilities.isDarkTheme(context),
- getRefreshRateMillis(context));
+ getRefreshRateMillis(context),
+ GraphicsUtils.getShapePath(context, DEFAULT_PATH_SIZE));
}
public PreloadIconDrawable(
@@ -146,10 +147,11 @@
int indicatorColor,
int[] preloadColors,
boolean isDarkMode,
- int refreshRateMillis) {
+ int refreshRateMillis,
+ Path shapePath) {
super(info.bitmap);
mItem = info;
- mShapePath = GraphicsUtils.getShapePath(DEFAULT_PATH_SIZE);
+ mShapePath = shapePath;
mScaledTrackPath = new Path();
mScaledProgressPath = new Path();
@@ -386,7 +388,8 @@
mIndicatorColor,
new int[] {mSystemAccentColor, mSystemBackgroundColor},
mIsDarkMode,
- mRefreshRateMillis);
+ mRefreshRateMillis,
+ mShapePath);
}
@Override
@@ -442,6 +445,7 @@
protected final boolean mIsDarkMode;
protected final int mLevel;
protected final int mRefreshRateMillis;
+ private final Path mShapePath;
public PreloadIconConstantState(
Bitmap bitmap,
@@ -450,7 +454,8 @@
int indicatorColor,
int[] preloadColors,
boolean isDarkMode,
- int refreshRateMillis) {
+ int refreshRateMillis,
+ Path shapePath) {
super(bitmap, iconColor);
mInfo = info;
mIndicatorColor = indicatorColor;
@@ -458,6 +463,7 @@
mIsDarkMode = isDarkMode;
mLevel = info.getProgressLevel();
mRefreshRateMillis = refreshRateMillis;
+ mShapePath = shapePath;
}
@Override
@@ -467,7 +473,8 @@
mIndicatorColor,
mPreloadColors,
mIsDarkMode,
- mRefreshRateMillis);
+ mRefreshRateMillis,
+ mShapePath);
}
}
}
diff --git a/src/com/android/launcher3/popup/PopupDataProvider.java b/src/com/android/launcher3/popup/PopupDataProvider.java
index 80ffecc..69c96ff 100644
--- a/src/com/android/launcher3/popup/PopupDataProvider.java
+++ b/src/com/android/launcher3/popup/PopupDataProvider.java
@@ -238,6 +238,15 @@
.collect(Collectors.toList());
}
+ /** Gets the WidgetsListContentEntry for the currently selected header. */
+ public WidgetsListContentEntry getSelectedAppWidgets(PackageUserKey packageUserKey) {
+ return (WidgetsListContentEntry) mAllWidgets.stream()
+ .filter(row -> row instanceof WidgetsListContentEntry
+ && row.mPkgItem.packageName.equals(packageUserKey.mPackageName))
+ .findAny()
+ .orElse(null);
+ }
+
/**
* Returns a list of notifications that are relevant to given ItemInfo.
*/
diff --git a/src/com/android/launcher3/widget/model/WidgetsListBaseEntry.java b/src/com/android/launcher3/widget/model/WidgetsListBaseEntry.java
index 1d1c9dc..f09f4c6 100644
--- a/src/com/android/launcher3/widget/model/WidgetsListBaseEntry.java
+++ b/src/com/android/launcher3/widget/model/WidgetsListBaseEntry.java
@@ -59,27 +59,12 @@
@Rank
public abstract int getRank();
- /**
- * Marker interface for subclasses that are headers for widget list items.
- *
- * @param <T> The type of this class.
- */
- public interface Header<T extends WidgetsListBaseEntry & Header<T>> {
- /** Returns whether the widget list is currently expanded. */
- boolean isWidgetListShown();
-
- /** Returns a copy of the item with the widget list shown. */
- T withWidgetListShown();
- }
-
@Retention(SOURCE)
- @IntDef({RANK_WIDGETS_TOP_SPACE, RANK_WIDGETS_LIST_HEADER, RANK_WIDGETS_LIST_SEARCH_HEADER,
- RANK_WIDGETS_LIST_CONTENT})
+ @IntDef({RANK_WIDGETS_TOP_SPACE, RANK_WIDGETS_LIST_HEADER, RANK_WIDGETS_LIST_CONTENT})
public @interface Rank {
}
public static final int RANK_WIDGETS_TOP_SPACE = 1;
public static final int RANK_WIDGETS_LIST_HEADER = 2;
- public static final int RANK_WIDGETS_LIST_SEARCH_HEADER = 3;
- public static final int RANK_WIDGETS_LIST_CONTENT = 4;
+ public static final int RANK_WIDGETS_LIST_CONTENT = 3;
}
diff --git a/src/com/android/launcher3/widget/model/WidgetsListHeaderEntry.java b/src/com/android/launcher3/widget/model/WidgetsListHeaderEntry.java
index 5b3ea94..bb0cf92 100644
--- a/src/com/android/launcher3/widget/model/WidgetsListHeaderEntry.java
+++ b/src/com/android/launcher3/widget/model/WidgetsListHeaderEntry.java
@@ -15,35 +15,67 @@
*/
package com.android.launcher3.widget.model;
+import android.content.Context;
+import android.content.res.Resources;
+
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.R;
import com.android.launcher3.model.WidgetItem;
import com.android.launcher3.model.data.PackageItemInfo;
+import com.android.launcher3.util.PluralMessageFormat;
import java.util.List;
+import java.util.function.BiFunction;
+import java.util.stream.Collectors;
/** An information holder for an app which has widgets or/and shortcuts. */
-public final class WidgetsListHeaderEntry extends WidgetsListBaseEntry
- implements WidgetsListBaseEntry.Header<WidgetsListHeaderEntry> {
+public final class WidgetsListHeaderEntry extends WidgetsListBaseEntry {
- public final int widgetsCount;
- public final int shortcutsCount;
+ private static final BiFunction<Context, WidgetsListHeaderEntry, String> SUBTITLE_SEARCH =
+ (context, entry) -> entry.mWidgets.stream()
+ .map(item -> item.label).sorted().collect(Collectors.joining(", "));
+
+ private static final BiFunction<Context, WidgetsListHeaderEntry, String> SUBTITLE_DEFAULT =
+ (context, entry) -> {
+ List<WidgetItem> items = entry.mWidgets;
+ int wc = (int) items.stream().filter(item -> item.widgetInfo != null).count();
+ int sc = Math.max(0, items.size() - wc);
+
+ Resources resources = context.getResources();
+ if (wc == 0 && sc == 0) {
+ return null;
+ }
+
+ String subtitle;
+ if (wc > 0 && sc > 0) {
+ String widgetsCount = PluralMessageFormat.getIcuPluralString(context,
+ R.string.widgets_count, wc);
+ String shortcutsCount = PluralMessageFormat.getIcuPluralString(context,
+ R.string.shortcuts_count, sc);
+ subtitle = resources.getString(R.string.widgets_and_shortcuts_count,
+ widgetsCount, shortcutsCount);
+ } else if (wc > 0) {
+ subtitle = PluralMessageFormat.getIcuPluralString(context,
+ R.string.widgets_count, wc);
+ } else {
+ subtitle = PluralMessageFormat.getIcuPluralString(context,
+ R.string.shortcuts_count, sc);
+ }
+ return subtitle;
+ };
private final boolean mIsWidgetListShown;
-
- public WidgetsListHeaderEntry(PackageItemInfo pkgItem, String titleSectionName,
- List<WidgetItem> items) {
- this(pkgItem, titleSectionName, items, /* isWidgetListShown= */ false);
- }
+ private final boolean mIsSearchEntry;
private WidgetsListHeaderEntry(PackageItemInfo pkgItem, String titleSectionName,
- List<WidgetItem> items, boolean isWidgetListShown) {
+ List<WidgetItem> items, boolean isSearchEntry, boolean isWidgetListShown) {
super(pkgItem, titleSectionName, items);
- widgetsCount = (int) items.stream().filter(item -> item.widgetInfo != null).count();
- shortcutsCount = Math.max(0, items.size() - widgetsCount);
+ mIsSearchEntry = isSearchEntry;
mIsWidgetListShown = isWidgetListShown;
}
/** Returns {@code true} if the widgets list associated with this header is shown. */
- @Override
public boolean isWidgetListShown() {
return mIsWidgetListShown;
}
@@ -59,23 +91,54 @@
return RANK_WIDGETS_LIST_HEADER;
}
+ public boolean isSearchEntry() {
+ return mIsSearchEntry;
+ }
+
+ @Nullable
+ public String getSubtitle(Context context) {
+ return mIsSearchEntry
+ ? SUBTITLE_SEARCH.apply(context, this) : SUBTITLE_DEFAULT.apply(context, this);
+ }
+
@Override
public boolean equals(Object obj) {
if (!(obj instanceof WidgetsListHeaderEntry)) return false;
WidgetsListHeaderEntry otherEntry = (WidgetsListHeaderEntry) obj;
return mWidgets.equals(otherEntry.mWidgets) && mPkgItem.equals(otherEntry.mPkgItem)
&& mTitleSectionName.equals(otherEntry.mTitleSectionName)
- && mIsWidgetListShown == otherEntry.mIsWidgetListShown;
+ && mIsWidgetListShown == otherEntry.mIsWidgetListShown
+ && mIsSearchEntry == otherEntry.mIsSearchEntry;
}
/** Returns a copy of this {@link WidgetsListHeaderEntry} with the widget list shown. */
- @Override
public WidgetsListHeaderEntry withWidgetListShown() {
if (mIsWidgetListShown) return this;
return new WidgetsListHeaderEntry(
mPkgItem,
mTitleSectionName,
mWidgets,
+ mIsSearchEntry,
/* isWidgetListShown= */ true);
}
+
+ public static WidgetsListHeaderEntry create(PackageItemInfo pkgItem, String titleSectionName,
+ List<WidgetItem> items) {
+ return new WidgetsListHeaderEntry(
+ pkgItem,
+ titleSectionName,
+ items,
+ /* forSearch */ false,
+ /* isWidgetListShown= */ false);
+ }
+
+ public static WidgetsListHeaderEntry createForSearch(PackageItemInfo pkgItem,
+ String titleSectionName, List<WidgetItem> items) {
+ return new WidgetsListHeaderEntry(
+ pkgItem,
+ titleSectionName,
+ items,
+ /* forSearch */ true,
+ /* isWidgetListShown= */ false);
+ }
}
diff --git a/src/com/android/launcher3/widget/model/WidgetsListSearchHeaderEntry.java b/src/com/android/launcher3/widget/model/WidgetsListSearchHeaderEntry.java
deleted file mode 100644
index 055e4ec..0000000
--- a/src/com/android/launcher3/widget/model/WidgetsListSearchHeaderEntry.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * 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.widget.model;
-
-import com.android.launcher3.model.WidgetItem;
-import com.android.launcher3.model.data.PackageItemInfo;
-
-import java.util.List;
-
-/** An information holder for an app which has widgets or/and shortcuts, to be shown in search. */
-public final class WidgetsListSearchHeaderEntry extends WidgetsListBaseEntry
- implements WidgetsListBaseEntry.Header<WidgetsListSearchHeaderEntry> {
-
- private final boolean mIsWidgetListShown;
-
- public WidgetsListSearchHeaderEntry(PackageItemInfo pkgItem, String titleSectionName,
- List<WidgetItem> items) {
- this(pkgItem, titleSectionName, items, /* isWidgetListShown= */ false);
- }
-
- private WidgetsListSearchHeaderEntry(PackageItemInfo pkgItem, String titleSectionName,
- List<WidgetItem> items, boolean isWidgetListShown) {
- super(pkgItem, titleSectionName, items);
- mIsWidgetListShown = isWidgetListShown;
- }
-
- /** Returns {@code true} if the widgets list associated with this header is shown. */
- @Override
- public boolean isWidgetListShown() {
- return mIsWidgetListShown;
- }
-
- @Override
- public String toString() {
- return "SearchHeader:" + mPkgItem.packageName + ":" + mWidgets.size();
- }
-
- @Override
- @Rank
- public int getRank() {
- return RANK_WIDGETS_LIST_SEARCH_HEADER;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (!(obj instanceof WidgetsListSearchHeaderEntry)) return false;
- WidgetsListSearchHeaderEntry otherEntry = (WidgetsListSearchHeaderEntry) obj;
- return mWidgets.equals(otherEntry.mWidgets) && mPkgItem.equals(otherEntry.mPkgItem)
- && mTitleSectionName.equals(otherEntry.mTitleSectionName)
- && mIsWidgetListShown == otherEntry.mIsWidgetListShown;
- }
-
- /** Returns a copy of this {@link WidgetsListSearchHeaderEntry} with the widget list shown. */
- @Override
- public WidgetsListSearchHeaderEntry withWidgetListShown() {
- if (mIsWidgetListShown) return this;
- return new WidgetsListSearchHeaderEntry(
- mPkgItem,
- mTitleSectionName,
- mWidgets,
- /* isWidgetListShown= */ true);
- }
-}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsDiffReporter.java b/src/com/android/launcher3/widget/picker/WidgetsDiffReporter.java
index 99374f5..d09fe84 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsDiffReporter.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsDiffReporter.java
@@ -25,7 +25,6 @@
import com.android.launcher3.widget.model.WidgetsListBaseEntry;
import com.android.launcher3.widget.model.WidgetsListContentEntry;
import com.android.launcher3.widget.model.WidgetsListHeaderEntry;
-import com.android.launcher3.widget.model.WidgetsListSearchHeaderEntry;
import com.android.launcher3.widget.picker.WidgetsListAdapter.WidgetListBaseRowEntryComparator;
import java.util.ArrayList;
@@ -175,12 +174,8 @@
*/
private boolean hasHeaderUpdated(WidgetsListBaseEntry curRow, WidgetsListBaseEntry newRow) {
if (newRow instanceof WidgetsListHeaderEntry && curRow instanceof WidgetsListHeaderEntry) {
- return !curRow.equals(newRow);
- }
- if (newRow instanceof WidgetsListSearchHeaderEntry
- && curRow instanceof WidgetsListSearchHeaderEntry) {
// Always refresh search header entries to reset rounded corners in their view holder.
- return true;
+ return !curRow.equals(newRow) || ((WidgetsListHeaderEntry) curRow).isSearchEntry();
}
return false;
}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index c78ecf5..7c7cdf4 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -20,6 +20,7 @@
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
import static com.android.launcher3.allapps.AllAppsTransitionController.SWIPE_ALL_APPS_TO_HOME_MIN_SCALE;
+import static com.android.launcher3.config.FeatureFlags.LARGE_SCREEN_WIDGET_PICKER;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WIDGETSTRAY_SEARCHED;
import static com.android.launcher3.testing.shared.TestProtocol.NORMAL_STATE_ORDINAL;
@@ -45,14 +46,18 @@
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
import android.widget.TextView;
import androidx.annotation.FloatRange;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.RecyclerView;
+import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
@@ -62,7 +67,9 @@
import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.model.UserManagerState;
import com.android.launcher3.model.WidgetItem;
+import com.android.launcher3.model.data.PackageItemInfo;
import com.android.launcher3.pm.UserCache;
+import com.android.launcher3.util.PackageUserKey;
import com.android.launcher3.views.ArrowTipView;
import com.android.launcher3.views.RecyclerViewFastScroller;
import com.android.launcher3.views.SpringRelativeLayout;
@@ -71,6 +78,8 @@
import com.android.launcher3.widget.BaseWidgetSheet;
import com.android.launcher3.widget.LauncherWidgetHolder.ProviderChangedListener;
import com.android.launcher3.widget.model.WidgetsListBaseEntry;
+import com.android.launcher3.widget.model.WidgetsListContentEntry;
+import com.android.launcher3.widget.model.WidgetsListHeaderEntry;
import com.android.launcher3.widget.picker.search.SearchModeListener;
import com.android.launcher3.widget.picker.search.WidgetsSearchBar;
import com.android.launcher3.widget.util.WidgetsTableUtils;
@@ -78,6 +87,7 @@
import com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip.OnActivePageChangedListener;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.IntStream;
@@ -93,6 +103,9 @@
private static final long EDUCATION_TIP_DELAY_MS = 200;
private static final long EDUCATION_DIALOG_DELAY_MS = 500;
private static final float VERTICAL_START_POSITION = 0.3f;
+ private static final int PERSONAL_TAB = 0;
+ private static final int WORK_TAB = 1;
+ private static final String SUGGESTIONS_PACKAGE_NAME = "widgets_list_suggestions_entry";
// The widget recommendation table can easily take over the entire screen on devices with small
// resolution or landscape on phone. This ratio defines the max percentage of content area that
// the table can display.
@@ -169,14 +182,23 @@
private StickyHeaderLayout mSearchScrollView;
private WidgetsRecommendationTableLayout mRecommendedWidgetsTable;
+ private LinearLayout mSuggestedWidgetsContainer;
+ private WidgetsListHeader mSuggestedWidgetsHeader;
private View mTabBar;
private View mSearchBarContainer;
private WidgetsSearchBar mSearchBar;
private TextView mHeaderTitle;
+ private ScrollView mRightPane;
+ private WidgetsListTableViewHolderBinder mWidgetsListTableViewHolderBinder;
+ private final boolean mIsTwoPane;
+
+ private int mOrientation;
private @Nullable WidgetsRecyclerView mCurrentTouchEventRecyclerView;
public WidgetsFullSheet(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
+ DeviceProfile dp = Launcher.getLauncher(context).getDeviceProfile();
+ mIsTwoPane = dp.isTablet && dp.isLandscape && LARGE_SCREEN_WIDGET_PICKER.get();
mHasWorkProfile = context.getSystemService(LauncherApps.class).getProfiles().size() > 1;
mAdapters.put(AdapterHolder.PRIMARY, new AdapterHolder(AdapterHolder.PRIMARY));
mAdapters.put(AdapterHolder.WORK, new AdapterHolder(AdapterHolder.WORK));
@@ -205,9 +227,16 @@
LayoutInflater layoutInflater = LayoutInflater.from(getContext());
int contentLayoutRes = mHasWorkProfile ? R.layout.widgets_full_sheet_paged_view
: R.layout.widgets_full_sheet_recyclerview;
+ if (mIsTwoPane) {
+ contentLayoutRes = mHasWorkProfile ? R.layout.widgets_full_sheet_paged_view_large_screen
+ : R.layout.widgets_full_sheet_recyclerview_large_screen;
+ }
layoutInflater.inflate(contentLayoutRes, mContent, true);
RecyclerViewFastScroller fastScroller = findViewById(R.id.fast_scroller);
+ if (mIsTwoPane) {
+ fastScroller.setVisibility(GONE);
+ }
mAdapters.get(AdapterHolder.PRIMARY).setup(findViewById(R.id.primary_widgets_list_view));
mAdapters.get(AdapterHolder.SEARCH).setup(findViewById(R.id.search_widgets_list_view));
if (mHasWorkProfile) {
@@ -230,15 +259,61 @@
mSearchScrollView = findViewById(R.id.search_and_recommendations_container);
mSearchScrollView.setCurrentRecyclerView(findViewById(R.id.primary_widgets_list_view));
- mRecommendedWidgetsTable = mSearchScrollView.findViewById(R.id.recommended_widget_table);
+ mRecommendedWidgetsTable = mIsTwoPane
+ ? mContent.findViewById(R.id.recommended_widget_table)
+ : mSearchScrollView.findViewById(R.id.recommended_widget_table);
+
mRecommendedWidgetsTable.setWidgetCellLongClickListener(this);
mRecommendedWidgetsTable.setWidgetCellOnClickListener(this);
+ // Add suggested widgets.
+ if (mIsTwoPane) {
+ mSuggestedWidgetsContainer = mSearchScrollView.findViewById(R.id.suggestions_header);
+
+ // Inflate the suggestions header.
+ mSuggestedWidgetsHeader = (WidgetsListHeader) layoutInflater.inflate(
+ R.layout.widgets_list_row_header, mSuggestedWidgetsContainer, false);
+ mSuggestedWidgetsHeader.setExpanded(true);
+ mSuggestedWidgetsHeader.setBackground(
+ new WidgetsListDrawableFactory(getContext()).createHeaderBackgroundDrawable());
+
+ PackageItemInfo packageItemInfo = new PackageItemInfo(
+ /* packageName= */ SUGGESTIONS_PACKAGE_NAME,
+ Process.myUserHandle()) {
+ @Override
+ public boolean usingLowResIcon() {
+ return false;
+ }
+ };
+ packageItemInfo.title = getContext().getString(R.string.suggested_widgets_header_title);
+ WidgetsListHeaderEntry widgetsListHeaderEntry = WidgetsListHeaderEntry.create(
+ packageItemInfo,
+ getContext().getString(R.string.suggested_widgets_header_title),
+ mActivityContext.getPopupDataProvider().getRecommendedWidgets())
+ .withWidgetListShown();
+
+ mSuggestedWidgetsHeader.applyFromItemInfoWithIcon(widgetsListHeaderEntry);
+ mSuggestedWidgetsHeader.setIcon(
+ getContext().getDrawable(R.drawable.widget_suggestions_icon));
+ mSuggestedWidgetsHeader.setOnExpandChangeListener(isExpanded -> {
+ mSuggestedWidgetsHeader.setExpanded(isExpanded);
+ resetExpandedHeaders();
+ mRightPane.removeAllViews();
+ mRightPane.addView(mRecommendedWidgetsTable);
+ });
+ mSuggestedWidgetsContainer.addView(mSuggestedWidgetsHeader);
+ }
+
mTabBar = mSearchScrollView.findViewById(R.id.tabs);
mSearchBarContainer = mSearchScrollView.findViewById(R.id.search_bar_container);
mSearchBar = mSearchScrollView.findViewById(R.id.widgets_search_bar);
- mHeaderTitle = mSearchScrollView.findViewById(R.id.title);
-
+ mHeaderTitle = mIsTwoPane
+ ? mContent.findViewById(R.id.title)
+ : mSearchScrollView.findViewById(R.id.title);
+ mRightPane = mIsTwoPane ? mContent.findViewById(R.id.right_pane) : null;
+ mWidgetsListTableViewHolderBinder = new WidgetsListTableViewHolderBinder(
+ layoutInflater, this, this,
+ new WidgetsListDrawableFactory(getContext()));
onRecommendedWidgetsBound();
onWidgetsBound();
@@ -260,6 +335,13 @@
@Override
public void onActivePageChanged(int currentActivePage) {
+
+ // if the current active page changes to personal or work we set suggestions
+ // to be the selected widget
+ if (mIsTwoPane && (currentActivePage == PERSONAL_TAB || currentActivePage == WORK_TAB)) {
+ mSuggestedWidgetsHeader.callOnClick();
+ }
+
AdapterHolder currentAdapterHolder = mAdapters.get(currentActivePage);
WidgetsRecyclerView currentRecyclerView =
mAdapters.get(currentActivePage).mWidgetsRecyclerView;
@@ -428,6 +510,11 @@
View content = mHasWorkProfile
? mViewPager
: mAdapters.get(AdapterHolder.PRIMARY).mWidgetsRecyclerView;
+
+ if (mIsTwoPane && mRightPane != null) {
+ content = mRightPane;
+ }
+
int maxHorizontalSpans = computeMaxHorizontalSpans(content,
mWidgetSheetContentHorizontalPadding);
if (mMaxSpansPerRow != maxHorizontalSpans) {
@@ -520,6 +607,9 @@
public void onSearchResults(List<WidgetsListBaseEntry> entries) {
mAdapters.get(AdapterHolder.SEARCH).mWidgetsListAdapter.setWidgetsOnSearch(entries);
updateRecyclerViewVisibility(mAdapters.get(AdapterHolder.SEARCH));
+ if (mIsTwoPane) {
+ mAdapters.get(AdapterHolder.SEARCH).mWidgetsListAdapter.selectFirstHeaderEntry();
+ }
mAdapters.get(AdapterHolder.SEARCH).mWidgetsRecyclerView.scrollToTop();
}
@@ -527,6 +617,9 @@
mIsInSearchMode = isInSearchMode;
if (isInSearchMode) {
mRecommendedWidgetsTable.setVisibility(GONE);
+ if (mIsTwoPane) {
+ mSuggestedWidgetsContainer.setVisibility(GONE);
+ }
if (mHasWorkProfile) {
mViewPager.setVisibility(GONE);
mTabBar.setVisibility(GONE);
@@ -538,6 +631,10 @@
mNoWidgetsView.setVisibility(GONE);
} else {
mAdapters.get(AdapterHolder.SEARCH).mWidgetsRecyclerView.setVisibility(GONE);
+ if (mIsTwoPane) {
+ mSuggestedWidgetsContainer.setVisibility(VISIBLE);
+ mSuggestedWidgetsHeader.callOnClick();
+ }
// Visibility of recommended widgets, recycler views and headers are handled in methods
// below.
onRecommendedWidgetsBound();
@@ -572,7 +669,7 @@
MeasureSpec.EXACTLY),
makeMeasureSpec(mActivityContext.getDeviceProfile().availableHeightPx,
MeasureSpec.EXACTLY));
- float maxTableHeight = (mContent.getMeasuredHeight()
+ float maxTableHeight = mIsTwoPane ? Float.MAX_VALUE : (mContent.getMeasuredHeight()
- mTabsHeight - getHeaderViewHeight()
- noWidgetsViewHeight) * RECOMMENDATION_TABLE_HEIGHT_RATIO;
@@ -626,7 +723,7 @@
@Override
public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
- // Disable swipe down when recycler view is scrolling
+ // Disable swipe down when recycler view is scrolling or scroll view is scrolling
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
mNoIntercept = false;
WidgetsRecyclerView recyclerView = getRecyclerView();
@@ -636,6 +733,8 @@
mNoIntercept = true;
} else if (getPopupContainer().isEventOverView(recyclerView, ev)) {
mNoIntercept = !recyclerView.shouldContainerScroll(ev, getPopupContainer());
+ } else if (mIsTwoPane && getPopupContainer().isEventOverView(mRightPane, ev)) {
+ mNoIntercept = mRightPane.getScrollY() > 0;
}
if (mSearchBar.isSearchBarFocused()
@@ -649,7 +748,11 @@
/** Shows the {@link WidgetsFullSheet} on the launcher. */
public static WidgetsFullSheet show(Launcher launcher, boolean animate) {
WidgetsFullSheet sheet = (WidgetsFullSheet) launcher.getLayoutInflater()
- .inflate(R.layout.widgets_full_sheet, launcher.getDragLayer(), false);
+ .inflate(LARGE_SCREEN_WIDGET_PICKER.get()
+ && launcher.getDeviceProfile().isTablet
+ && launcher.getDeviceProfile().isLandscape
+ ? R.layout.widgets_full_sheet_large_screen
+ : R.layout.widgets_full_sheet, launcher.getDragLayer(), false);
sheet.attachToContainer();
sheet.mIsOpen = true;
sheet.open(animate);
@@ -746,6 +849,13 @@
if (mIsInSearchMode) {
mSearchBar.reset();
}
+
+ // Checks the orientation of the screen
+ if (LARGE_SCREEN_WIDGET_PICKER.get() && mOrientation != newConfig.orientation) {
+ mOrientation = newConfig.orientation;
+ handleClose(false);
+ show(Launcher.getLauncher(getContext()), false);
+ }
}
@Override
@@ -835,16 +945,44 @@
AdapterHolder(int adapterType) {
mAdapterType = adapterType;
-
Context context = getContext();
LauncherAppState apps = LauncherAppState.getInstance(context);
+
+ HeaderChangeListener headerChangeListener = new HeaderChangeListener() {
+ @Override
+ public void onHeaderChanged(@NonNull PackageUserKey selectedHeader) {
+ WidgetsListContentEntry contentEntry = mActivityContext.getPopupDataProvider()
+ .getSelectedAppWidgets(selectedHeader);
+
+ if (contentEntry == null || mRightPane == null) {
+ return;
+ }
+
+ if (mSuggestedWidgetsHeader != null) {
+ mSuggestedWidgetsHeader.setExpanded(false);
+ }
+ WidgetsRowViewHolder widgetsRowViewHolder =
+ mWidgetsListTableViewHolderBinder.newViewHolder(mRightPane);
+ mWidgetsListTableViewHolderBinder.bindViewHolder(widgetsRowViewHolder,
+ contentEntry,
+ 0, Collections.EMPTY_LIST);
+ widgetsRowViewHolder.mDataCallback = data -> {
+ mWidgetsListTableViewHolderBinder.bindViewHolder(widgetsRowViewHolder,
+ contentEntry,
+ 0, Collections.singletonList(data));
+ };
+ mRightPane.removeAllViews();
+ mRightPane.addView(widgetsRowViewHolder.itemView);
+ }
+ };
mWidgetsListAdapter = new WidgetsListAdapter(
context,
LayoutInflater.from(context),
apps.getIconCache(),
this::getEmptySpaceHeight,
/* iconClickListener= */ WidgetsFullSheet.this,
- /* iconLongClickListener= */ WidgetsFullSheet.this);
+ /* iconLongClickListener= */ WidgetsFullSheet.this,
+ mIsTwoPane ? headerChangeListener : null);
mWidgetsListAdapter.setHasStableIds(true);
switch (mAdapterType) {
case PRIMARY:
@@ -871,8 +1009,10 @@
mWidgetsRecyclerView.setAdapter(mWidgetsListAdapter);
mWidgetsRecyclerView.setItemAnimator(mWidgetsListItemAnimator);
mWidgetsRecyclerView.setHeaderViewDimensionsProvider(WidgetsFullSheet.this);
- mWidgetsRecyclerView.setEdgeEffectFactory(
- ((SpringRelativeLayout) mContent).createEdgeEffectFactory());
+ if (!mIsTwoPane) {
+ mWidgetsRecyclerView.setEdgeEffectFactory(
+ ((SpringRelativeLayout) mContent).createEdgeEffectFactory());
+ }
// Recycler view binds to fast scroller when it is attached to screen. Make sure
// search recycler view is bound to fast scroller if user is in search mode at the time
// of attachment.
@@ -882,4 +1022,15 @@
mWidgetsListAdapter.setMaxHorizontalSpansPerRow(mMaxSpansPerRow);
}
}
+
+ /**
+ * This is a listener for when the selected header gets changed in the left pane.
+ */
+ public interface HeaderChangeListener {
+ /**
+ * Sets the right pane to have the widgets for the currently selected header from
+ * the left pane.
+ */
+ void onHeaderChanged(@NonNull PackageUserKey selectedHeader);
+ }
}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java b/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java
index e6b9dca..549ac42 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java
@@ -48,7 +48,6 @@
import com.android.launcher3.widget.model.WidgetsListBaseEntry;
import com.android.launcher3.widget.model.WidgetsListContentEntry;
import com.android.launcher3.widget.model.WidgetsListHeaderEntry;
-import com.android.launcher3.widget.model.WidgetsListSearchHeaderEntry;
import java.util.ArrayList;
import java.util.Arrays;
@@ -81,13 +80,13 @@
public static final int VIEW_TYPE_WIDGETS_SPACE = R.id.view_type_widgets_space;
public static final int VIEW_TYPE_WIDGETS_LIST = R.id.view_type_widgets_list;
public static final int VIEW_TYPE_WIDGETS_HEADER = R.id.view_type_widgets_header;
- public static final int VIEW_TYPE_WIDGETS_SEARCH_HEADER = R.id.view_type_widgets_search_header;
private final Context mContext;
private final WidgetsDiffReporter mDiffReporter;
private final SparseArray<ViewHolderBinder> mViewHolderBinders = new SparseArray<>();
private final WidgetListBaseRowEntryComparator mRowComparator =
new WidgetListBaseRowEntryComparator();
+ @Nullable private final WidgetsFullSheet.HeaderChangeListener mHeaderChangeListener;
private final List<WidgetsListBaseEntry> mAllEntries = new ArrayList<>();
private ArrayList<WidgetsListBaseEntry> mVisibleEntries = new ArrayList<>();
@@ -95,7 +94,6 @@
private Predicate<WidgetsListBaseEntry> mHeaderAndSelectedContentFilter = entry ->
entry instanceof WidgetsListHeaderEntry
- || entry instanceof WidgetsListSearchHeaderEntry
|| PackageUserKey.fromPackageItemInfo(entry.mPkgItem)
.equals(mWidgetsContentVisiblePackageUserKey);
@Nullable private Predicate<WidgetsListBaseEntry> mFilter = null;
@@ -105,7 +103,9 @@
public WidgetsListAdapter(Context context, LayoutInflater layoutInflater,
IconCache iconCache, IntSupplier emptySpaceHeightProvider,
- OnClickListener iconClickListener, OnLongClickListener iconLongClickListener) {
+ OnClickListener iconClickListener, OnLongClickListener iconLongClickListener,
+ WidgetsFullSheet.HeaderChangeListener headerChangeListener) {
+ mHeaderChangeListener = headerChangeListener;
mContext = context;
mDiffReporter = new WidgetsDiffReporter(iconCache, this);
WidgetsListDrawableFactory listDrawableFactory = new WidgetsListDrawableFactory(context);
@@ -122,12 +122,6 @@
/* onHeaderClickListener= */ this,
listDrawableFactory));
mViewHolderBinders.put(
- VIEW_TYPE_WIDGETS_SEARCH_HEADER,
- new WidgetsListSearchHeaderViewHolderBinder(
- layoutInflater,
- /* onHeaderClickListener= */ this,
- listDrawableFactory));
- mViewHolderBinders.put(
VIEW_TYPE_WIDGETS_SPACE,
new WidgetsSpaceViewHolderBinder(emptySpaceHeightProvider));
}
@@ -196,14 +190,16 @@
getOffsetForPosition(previousPositionForPackageUserKey);
List<WidgetsListBaseEntry> newVisibleEntries = mAllEntries.stream()
- .filter(entry -> ((mFilter == null || mFilter.test(entry))
+ .filter(entry -> (((mFilter == null || mFilter.test(entry))
&& mHeaderAndSelectedContentFilter.test(entry))
|| entry instanceof WidgetListSpaceEntry)
+ && (mHeaderChangeListener == null
+ || !(entry instanceof WidgetsListContentEntry)))
.map(entry -> {
- if (entry instanceof WidgetsListBaseEntry.Header<?>
+ if (entry instanceof WidgetsListHeaderEntry
&& matchesKey(entry, mWidgetsContentVisiblePackageUserKey)) {
// Adjust the original entries to expand headers for the selected content.
- return ((WidgetsListBaseEntry.Header<?>) entry).withWidgetListShown();
+ return ((WidgetsListHeaderEntry) entry).withWidgetListShown();
} else if (entry instanceof WidgetsListContentEntry) {
// Adjust the original content entries to accommodate for the current
// maxSpanSize.
@@ -225,11 +221,10 @@
}
}
-
/** Returns whether {@code entry} matches {@code key}. */
private static boolean isHeaderForPackageUserKey(
@NonNull WidgetsListBaseEntry entry, @Nullable PackageUserKey key) {
- return entry instanceof WidgetsListBaseEntry.Header && matchesKey(entry, key);
+ return entry instanceof WidgetsListHeaderEntry && matchesKey(entry, key);
}
private static boolean matchesKey(@NonNull WidgetsListBaseEntry entry,
@@ -258,7 +253,6 @@
@Override
public void onBindViewHolder(ViewHolder holder, int pos, List<Object> payloads) {
ViewHolderBinder viewHolderBinder = mViewHolderBinders.get(getItemViewType(pos));
- WidgetsListBaseEntry entry = mVisibleEntries.get(pos);
// The first entry has an empty space, count from second entries.
int listPos = (pos > 1) ? POSITION_DEFAULT : POSITION_FIRST;
@@ -268,6 +262,18 @@
viewHolderBinder.bindViewHolder(holder, mVisibleEntries.get(pos), listPos, payloads);
}
+ /**
+ * Selects the first visible header. This is used in search as we want to always select the
+ * first header in the new list that gets generated as we search.
+ */
+ void selectFirstHeaderEntry() {
+ mVisibleEntries.stream()
+ .filter(entry -> entry instanceof WidgetsListHeaderEntry)
+ .findFirst()
+ .ifPresent(entry ->
+ onHeaderClicked(true, PackageUserKey.fromPackageItemInfo(entry.mPkgItem)));
+ }
+
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (DEBUG) {
@@ -305,8 +311,6 @@
return VIEW_TYPE_WIDGETS_LIST;
} else if (entry instanceof WidgetsListHeaderEntry) {
return VIEW_TYPE_WIDGETS_HEADER;
- } else if (entry instanceof WidgetsListSearchHeaderEntry) {
- return VIEW_TYPE_WIDGETS_SEARCH_HEADER;
} else if (entry instanceof WidgetListSpaceEntry) {
return VIEW_TYPE_WIDGETS_SPACE;
}
@@ -318,6 +322,9 @@
// Ignore invalid clicks, such as collapsing a package that isn't currently expanded.
if (!showWidgets && !packageUserKey.equals(mWidgetsContentVisiblePackageUserKey)) return;
+ if (mHeaderChangeListener != null
+ && packageUserKey.equals(mWidgetsContentVisiblePackageUserKey)) return;
+
if (showWidgets) {
mWidgetsContentVisiblePackageUserKey = packageUserKey;
ActivityContext.lookupContext(mContext)
@@ -331,6 +338,10 @@
mPendingClickHeader = packageUserKey;
updateVisibleEntries();
+
+ if (mHeaderChangeListener != null && mWidgetsContentVisiblePackageUserKey != null) {
+ mHeaderChangeListener.onHeaderChanged(mWidgetsContentVisiblePackageUserKey);
+ }
}
/**
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListHeader.java b/src/com/android/launcher3/widget/picker/WidgetsListHeader.java
index 48df04f..a6ef89f 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListHeader.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListHeader.java
@@ -15,13 +15,17 @@
*/
package com.android.launcher3.widget.picker;
+import static com.android.launcher3.config.FeatureFlags.LARGE_SCREEN_WIDGET_PICKER;
import android.content.Context;
-import android.content.res.Resources;
import android.content.res.TypedArray;
+import android.graphics.Color;
import android.graphics.drawable.Drawable;
+import android.graphics.drawable.GradientDrawable;
import android.os.Bundle;
+import android.text.TextUtils;
import android.util.AttributeSet;
+import android.util.TypedValue;
import android.view.View;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.CheckBox;
@@ -35,17 +39,15 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
import com.android.launcher3.icons.IconCache.ItemInfoUpdateReceiver;
import com.android.launcher3.icons.PlaceHolderIconDrawable;
import com.android.launcher3.icons.cache.HandlerRunnable;
import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.model.data.PackageItemInfo;
-import com.android.launcher3.util.PluralMessageFormat;
+import com.android.launcher3.util.Themes;
import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.widget.model.WidgetsListHeaderEntry;
-import com.android.launcher3.widget.model.WidgetsListSearchHeaderEntry;
-
-import java.util.stream.Collectors;
/**
* A UI represents a header of an app shown in the full widgets tray.
@@ -55,19 +57,19 @@
*/
public final class WidgetsListHeader extends LinearLayout implements ItemInfoUpdateReceiver {
- private boolean mEnableIconUpdateAnimation = false;
+ private final int mIconSize;
+ private final boolean mIsTwoPane;
@Nullable private HandlerRunnable mIconLoadRequest;
@Nullable private Drawable mIconDrawable;
- private final int mIconSize;
-
+ @Nullable private WidgetsListDrawableState mListDrawableState;
private ImageView mAppIcon;
private TextView mTitle;
private TextView mSubtitle;
-
+ private GradientDrawable mBackground;
private CheckBox mExpandToggle;
+ private boolean mEnableIconUpdateAnimation = false;
private boolean mIsExpanded = false;
- @Nullable private WidgetsListDrawableState mListDrawableState;
public WidgetsListHeader(Context context) {
this(context, /* attrs= */ null);
@@ -86,6 +88,11 @@
R.styleable.WidgetsListRowHeader, defStyleAttr, /* defStyleRes= */ 0);
mIconSize = a.getDimensionPixelSize(R.styleable.WidgetsListRowHeader_appIconSize,
grid.iconSizePx);
+
+ mIsTwoPane = grid.isLandscape && grid.isTablet && LARGE_SCREEN_WIDGET_PICKER.get();
+ if (mIsTwoPane) {
+ setLargeScreenTheme();
+ }
}
@Override
@@ -95,6 +102,9 @@
mTitle = findViewById(R.id.app_title);
mSubtitle = findViewById(R.id.app_subtitle);
mExpandToggle = findViewById(R.id.toggle);
+ if (mIsTwoPane) {
+ mExpandToggle.setVisibility(GONE);
+ }
setAccessibilityDelegate(new AccessibilityDelegate() {
@Override
@@ -132,7 +142,7 @@
@Nullable OnExpansionChangeListener onExpandChangeListener) {
// Use the entire touch area of this view to expand / collapse an app widgets section.
setOnClickListener(view -> {
- setExpanded(!mIsExpanded);
+ setExpanded(mIsTwoPane || !mIsExpanded);
if (onExpandChangeListener != null) {
onExpandChangeListener.onExpansionChange(mIsExpanded);
}
@@ -144,8 +154,38 @@
public void setExpanded(boolean isExpanded) {
this.mIsExpanded = isExpanded;
mExpandToggle.setChecked(isExpanded);
+ if (mIsTwoPane) {
+ if (Utilities.isDarkTheme(getContext())) {
+ if (mIsExpanded) {
+ mTitle.setTextColor(Color.BLACK);
+ mSubtitle.setTextColor(Color.BLACK);
+ } else {
+ mTitle.setTextColor(Color.WHITE);
+ mSubtitle.setTextColor(Themes.getAttrColor(getContext(),
+ android.R.attr.textColorSecondary));
+ }
+ }
+ setLargeScreenTheme();
+ }
}
+ /**
+ * Sets the style for the header when we are using large screens in landscape.
+ */
+ private void setLargeScreenTheme() {
+ if (mBackground == null) {
+ mBackground = new GradientDrawable();
+ mBackground.setCornerRadius((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+ 28,
+ getContext().getResources().getDisplayMetrics()));
+ }
+ mBackground.setColor(mIsExpanded
+ ? getResources().getColor(R.color.widget_picker_background_selected)
+ : Color.TRANSPARENT);
+ this.setBackground(mBackground);
+ }
+
+
/** Sets the {@link WidgetsListDrawableState} and refreshes the background drawable. */
@UiThread
public void setListDrawableState(WidgetsListDrawableState state) {
@@ -157,13 +197,8 @@
/** Apply app icon, labels and tag using a generic {@link WidgetsListHeaderEntry}. */
@UiThread
public void applyFromItemInfoWithIcon(WidgetsListHeaderEntry entry) {
- applyIconAndLabel(entry);
- }
-
- @UiThread
- private void applyIconAndLabel(WidgetsListHeaderEntry entry) {
PackageItemInfo info = entry.mPkgItem;
- setIcon(info);
+ setIcon(info.newIcon(getContext()));
setTitles(entry);
setExpanded(entry.isWidgetListShown());
@@ -172,9 +207,7 @@
verifyHighRes();
}
- private void setIcon(PackageItemInfo info) {
- Drawable icon;
- icon = info.newIcon(getContext());
+ void setIcon(Drawable icon) {
applyDrawables(icon);
mIconDrawable = icon;
if (mIconDrawable != null) {
@@ -205,55 +238,13 @@
private void setTitles(WidgetsListHeaderEntry entry) {
mTitle.setText(entry.mPkgItem.title);
- Resources resources = getContext().getResources();
- if (entry.widgetsCount == 0 && entry.shortcutsCount == 0) {
+ String subtitle = entry.getSubtitle(getContext());
+ if (TextUtils.isEmpty(subtitle)) {
mSubtitle.setVisibility(GONE);
- return;
- }
-
- String subtitle;
- if (entry.widgetsCount > 0 && entry.shortcutsCount > 0) {
- String widgetsCount = PluralMessageFormat.getIcuPluralString(getContext(),
- R.string.widgets_count, entry.widgetsCount);
- String shortcutsCount = PluralMessageFormat.getIcuPluralString(getContext(),
- R.string.shortcuts_count, entry.shortcutsCount);
- subtitle = resources.getString(R.string.widgets_and_shortcuts_count, widgetsCount,
- shortcutsCount);
- } else if (entry.widgetsCount > 0) {
- subtitle = PluralMessageFormat.getIcuPluralString(getContext(),
- R.string.widgets_count, entry.widgetsCount);
} else {
- subtitle = PluralMessageFormat.getIcuPluralString(getContext(),
- R.string.shortcuts_count, entry.shortcutsCount);
+ mSubtitle.setText(subtitle);
+ mSubtitle.setVisibility(VISIBLE);
}
- mSubtitle.setText(subtitle);
- mSubtitle.setVisibility(VISIBLE);
- }
-
- /** Apply app icon, labels and tag using a generic {@link WidgetsListSearchHeaderEntry}. */
- @UiThread
- public void applyFromItemInfoWithIcon(WidgetsListSearchHeaderEntry entry) {
- applyIconAndLabel(entry);
- }
-
- @UiThread
- private void applyIconAndLabel(WidgetsListSearchHeaderEntry entry) {
- PackageItemInfo info = entry.mPkgItem;
- setIcon(info);
- setTitles(entry);
- setExpanded(entry.isWidgetListShown());
-
- super.setTag(info);
-
- verifyHighRes();
- }
-
- private void setTitles(WidgetsListSearchHeaderEntry entry) {
- mTitle.setText(entry.mPkgItem.title);
-
- mSubtitle.setText(entry.mWidgets.stream()
- .map(item -> item.label).sorted().collect(Collectors.joining(", ")));
- mSubtitle.setVisibility(VISIBLE);
}
@Override
@@ -265,7 +256,7 @@
// Optimization: Starting in N, pre-uploads the bitmap to RenderThread.
info.bitmap.icon.prepareToDraw();
- setIcon((PackageItemInfo) info);
+ setIcon(info.newIcon(getContext()));
mEnableIconUpdateAnimation = false;
}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderViewHolderBinder.java b/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderViewHolderBinder.java
deleted file mode 100644
index 2b27fc2..0000000
--- a/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderViewHolderBinder.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * 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.widget.picker;
-
-import android.view.LayoutInflater;
-import android.view.ViewGroup;
-
-import com.android.launcher3.R;
-import com.android.launcher3.recyclerview.ViewHolderBinder;
-import com.android.launcher3.util.PackageUserKey;
-import com.android.launcher3.widget.model.WidgetsListHeaderEntry;
-import com.android.launcher3.widget.model.WidgetsListSearchHeaderEntry;
-
-import java.util.List;
-
-/**
- * Binds data from {@link WidgetsListHeaderEntry} to UI elements in {@link WidgetsListHeaderHolder}.
- */
-public final class WidgetsListSearchHeaderViewHolderBinder implements
- ViewHolderBinder<WidgetsListSearchHeaderEntry, WidgetsListSearchHeaderHolder> {
- private final LayoutInflater mLayoutInflater;
- private final OnHeaderClickListener mOnHeaderClickListener;
- private final WidgetsListDrawableFactory mListDrawableFactory;
-
- public WidgetsListSearchHeaderViewHolderBinder(LayoutInflater layoutInflater,
- OnHeaderClickListener onHeaderClickListener,
- WidgetsListDrawableFactory listDrawableFactory) {
- mLayoutInflater = layoutInflater;
- mOnHeaderClickListener = onHeaderClickListener;
- mListDrawableFactory = listDrawableFactory;
- }
-
- @Override
- public WidgetsListSearchHeaderHolder newViewHolder(ViewGroup parent) {
- WidgetsListHeader header = (WidgetsListHeader) mLayoutInflater.inflate(
- R.layout.widgets_list_row_header, parent, false);
- header.setBackground(mListDrawableFactory.createHeaderBackgroundDrawable());
- return new WidgetsListSearchHeaderHolder(header);
- }
-
- @Override
- public void bindViewHolder(WidgetsListSearchHeaderHolder viewHolder,
- WidgetsListSearchHeaderEntry data, @ListPosition int position, List<Object> payloads) {
- WidgetsListHeader widgetsListHeader = viewHolder.mWidgetsListHeader;
- widgetsListHeader.applyFromItemInfoWithIcon(data);
- widgetsListHeader.setExpanded(data.isWidgetListShown());
- widgetsListHeader.setListDrawableState(
- WidgetsListDrawableState.obtain(
- (position & POSITION_FIRST) != 0,
- (position & POSITION_LAST) != 0,
- /* isExpanded= */ data.isWidgetListShown()));
- widgetsListHeader.setOnExpandChangeListener(isExpanded ->
- mOnHeaderClickListener.onHeaderClicked(isExpanded,
- PackageUserKey.fromPackageItemInfo(data.mPkgItem)));
- }
-}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java b/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
index 05e26ad..8500b9a 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
@@ -110,13 +110,8 @@
// When preview loads, notify adapter to rebind the item and possibly animate
widget.applyFromCellItem(widgetItem, 1f,
- bitmap -> {
- if (holder.getBindingAdapter() != null) {
- holder.getBindingAdapter().notifyItemChanged(
- holder.getBindingAdapterPosition(),
- Pair.create(widgetItem, bitmap));
- }
- }, holder.previewCache.get(widgetItem));
+ bitmap -> holder.onPreviewLoaded(Pair.create(widgetItem, bitmap)),
+ holder.previewCache.get(widgetItem));
}
}
}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsRowViewHolder.java b/src/com/android/launcher3/widget/picker/WidgetsRowViewHolder.java
index fe2d84b..7411459 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsRowViewHolder.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsRowViewHolder.java
@@ -16,6 +16,7 @@
package com.android.launcher3.widget.picker;
import android.graphics.Bitmap;
+import android.util.Pair;
import android.view.View;
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
@@ -25,16 +26,33 @@
import java.util.HashMap;
import java.util.Map;
+import java.util.function.Consumer;
/** A {@link ViewHolder} for showing widgets of an app in the full widget picker. */
public final class WidgetsRowViewHolder extends ViewHolder {
public final WidgetsListTableView tableContainer;
public final Map<WidgetItem, Bitmap> previewCache = new HashMap<>();
+ Consumer<Pair<WidgetItem, Bitmap>> mDataCallback;
public WidgetsRowViewHolder(View v) {
super(v);
tableContainer = v.findViewById(R.id.widgets_table);
}
+
+ /**
+ * When the preview is loaded we callback to notify that the preview loaded and we rebind the
+ * view.
+ *
+ * @param data is the payload which is needed when binding the view.
+ */
+ public void onPreviewLoaded(Pair<WidgetItem, Bitmap> data) {
+ if (mDataCallback != null) {
+ mDataCallback.accept(data);
+ }
+ if (getBindingAdapter() != null) {
+ getBindingAdapter().notifyItemChanged(getBindingAdapterPosition(), data);
+ }
+ }
}
diff --git a/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchAlgorithm.java b/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchAlgorithm.java
index 9be3b5f..613066a 100644
--- a/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchAlgorithm.java
+++ b/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchAlgorithm.java
@@ -28,7 +28,6 @@
import com.android.launcher3.widget.model.WidgetsListBaseEntry;
import com.android.launcher3.widget.model.WidgetsListContentEntry;
import com.android.launcher3.widget.model.WidgetsListHeaderEntry;
-import com.android.launcher3.widget.model.WidgetsListSearchHeaderEntry;
import java.util.ArrayList;
import java.util.List;
@@ -72,7 +71,7 @@
List<WidgetItem> matchedWidgetItems = filterWidgetItems(
input, headerEntry.mPkgItem.title.toString(), headerEntry.mWidgets);
if (matchedWidgetItems.size() > 0) {
- results.add(new WidgetsListSearchHeaderEntry(headerEntry.mPkgItem,
+ results.add(WidgetsListHeaderEntry.createForSearch(headerEntry.mPkgItem,
headerEntry.mTitleSectionName, matchedWidgetItems));
results.add(new WidgetsListContentEntry(headerEntry.mPkgItem,
headerEntry.mTitleSectionName, matchedWidgetItems));
diff --git a/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java b/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java
index 702f343..f490333 100644
--- a/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java
+++ b/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java
@@ -87,7 +87,7 @@
List<WidgetItem> widgetItems = entry.getValue();
String sectionName = (pkgItem.title == null) ? "" :
indexer.computeSectionName(pkgItem.title);
- result.add(new WidgetsListHeaderEntry(pkgItem, sectionName, widgetItems));
+ result.add(WidgetsListHeaderEntry.create(pkgItem, sectionName, widgetItems));
result.add(new WidgetsListContentEntry(pkgItem, sectionName, widgetItems));
}
return result;
diff --git a/tests/src/com/android/launcher3/widget/picker/WidgetsDiffReporterTest.java b/tests/src/com/android/launcher3/widget/picker/WidgetsDiffReporterTest.java
index b480a4c..8c87957 100644
--- a/tests/src/com/android/launcher3/widget/picker/WidgetsDiffReporterTest.java
+++ b/tests/src/com/android/launcher3/widget/picker/WidgetsDiffReporterTest.java
@@ -229,7 +229,7 @@
List.of(mHeaderA, mHeaderB, mContentE));
// GIVEN the new list has one of the headers widgets list modified.
List<WidgetsListBaseEntry> newList = List.of(
- new WidgetsListHeaderEntry(
+ WidgetsListHeaderEntry.create(
mHeaderA.mPkgItem, mHeaderA.mTitleSectionName,
mHeaderA.mWidgets.subList(0, 1)),
mHeaderB, mContentE);
@@ -274,7 +274,7 @@
PackageItemInfo pInfo = createPackageItemInfo(packageName, appName,
widgetItems.get(0).user);
- return new WidgetsListHeaderEntry(pInfo, /* titleSectionName= */ "", widgetItems);
+ return WidgetsListHeaderEntry.create(pInfo, /* titleSectionName= */ "", widgetItems);
}
private WidgetsListContentEntry createWidgetsContentEntry(String packageName, String appName,
diff --git a/tests/src/com/android/launcher3/widget/picker/WidgetsListAdapterTest.java b/tests/src/com/android/launcher3/widget/picker/WidgetsListAdapterTest.java
index 4e0bdda..0044d04 100644
--- a/tests/src/com/android/launcher3/widget/picker/WidgetsListAdapterTest.java
+++ b/tests/src/com/android/launcher3/widget/picker/WidgetsListAdapterTest.java
@@ -86,7 +86,7 @@
mTestProfile.numColumns = 5;
mUserHandle = Process.myUserHandle();
mAdapter = new WidgetsListAdapter(mContext, mMockLayoutInflater,
- mIconCache, () -> 0, null, null);
+ mIconCache, () -> 0, null, null, null);
mAdapter.registerAdapterDataObserver(mListener);
doAnswer(invocation -> ((ComponentWithLabel) invocation.getArgument(0))
@@ -270,7 +270,8 @@
pInfo.title = pInfo.packageName;
pInfo.bitmap = BitmapInfo.of(Bitmap.createBitmap(10, 10, Bitmap.Config.ALPHA_8), 0);
- result.add(new WidgetsListHeaderEntry(pInfo, /* titleSectionName= */ "", widgetItems));
+ result.add(WidgetsListHeaderEntry.create(
+ pInfo, /* titleSectionName= */ "", widgetItems));
result.add(new WidgetsListContentEntry(pInfo, /* titleSectionName= */ "", widgetItems));
}
diff --git a/tests/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinderTest.java b/tests/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinderTest.java
index 211318c..f53d15b 100644
--- a/tests/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinderTest.java
+++ b/tests/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinderTest.java
@@ -134,7 +134,7 @@
appInfo.title = appName;
appInfo.bitmap = BitmapInfo.of(Bitmap.createBitmap(10, 10, Bitmap.Config.ALPHA_8), 0);
- return new WidgetsListHeaderEntry(appInfo,
+ return WidgetsListHeaderEntry.create(appInfo,
/* titleSectionName= */ "",
generateWidgetItems(packageName, numOfWidgets));
}
diff --git a/tests/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderViewHolderBinderTest.java b/tests/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderViewHolderBinderTest.java
deleted file mode 100644
index 66c2f36..0000000
--- a/tests/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderViewHolderBinderTest.java
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * 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.widget.picker;
-
-import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.verify;
-
-import static java.util.Collections.EMPTY_LIST;
-
-import android.appwidget.AppWidgetProviderInfo;
-import android.content.ComponentName;
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.os.UserHandle;
-import android.view.LayoutInflater;
-import android.widget.FrameLayout;
-import android.widget.TextView;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import com.android.launcher3.InvariantDeviceProfile;
-import com.android.launcher3.R;
-import com.android.launcher3.icons.BitmapInfo;
-import com.android.launcher3.icons.ComponentWithLabel;
-import com.android.launcher3.icons.IconCache;
-import com.android.launcher3.model.WidgetItem;
-import com.android.launcher3.model.data.PackageItemInfo;
-import com.android.launcher3.util.ActivityContextWrapper;
-import com.android.launcher3.util.PackageUserKey;
-import com.android.launcher3.util.WidgetUtils;
-import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
-import com.android.launcher3.widget.model.WidgetsListSearchHeaderEntry;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.util.ArrayList;
-import java.util.List;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public final class WidgetsListSearchHeaderViewHolderBinderTest {
- private static final String TEST_PACKAGE = "com.google.test";
- private static final String APP_NAME = "Test app";
-
- private Context mContext;
- private WidgetsListSearchHeaderViewHolderBinder mViewHolderBinder;
- private InvariantDeviceProfile mTestProfile;
-
- @Mock
- private IconCache mIconCache;
- @Mock
- private OnHeaderClickListener mOnHeaderClickListener;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- mContext = new ActivityContextWrapper(getApplicationContext());
- mTestProfile = new InvariantDeviceProfile();
- mTestProfile.numRows = 5;
- mTestProfile.numColumns = 5;
-
- doAnswer(invocation -> {
- ComponentWithLabel componentWithLabel = (ComponentWithLabel) invocation.getArgument(0);
- return componentWithLabel.getComponent().getShortClassName();
- }).when(mIconCache).getTitleNoCache(any());
- mViewHolderBinder = new WidgetsListSearchHeaderViewHolderBinder(
- LayoutInflater.from(mContext),
- mOnHeaderClickListener,
- new WidgetsListDrawableFactory(mContext));
- }
-
- @Test
- public void bindViewHolder_appWith3Widgets_shouldShowTheCorrectAppNameAndSubtitle() {
- WidgetsListSearchHeaderHolder viewHolder = mViewHolderBinder.newViewHolder(
- new FrameLayout(mContext));
- WidgetsListHeader widgetsListHeader = viewHolder.mWidgetsListHeader;
- WidgetsListSearchHeaderEntry entry = generateSampleSearchHeader(
- APP_NAME,
- TEST_PACKAGE,
- /* numOfWidgets= */ 3);
- mViewHolderBinder.bindViewHolder(viewHolder, entry, /* position= */ 0, EMPTY_LIST);
-
- TextView appTitle = widgetsListHeader.findViewById(R.id.app_title);
- TextView appSubtitle = widgetsListHeader.findViewById(R.id.app_subtitle);
- assertThat(appTitle.getText()).isEqualTo(APP_NAME);
- assertThat(appSubtitle.getText())
- .isEqualTo(".SampleWidget0, .SampleWidget1, .SampleWidget2");
- }
-
- @Test
- public void bindViewHolder_shouldAttachOnHeaderClickListener() {
- WidgetsListSearchHeaderHolder viewHolder = mViewHolderBinder.newViewHolder(
- new FrameLayout(mContext));
- WidgetsListHeader widgetsListHeader = viewHolder.mWidgetsListHeader;
- WidgetsListSearchHeaderEntry entry = generateSampleSearchHeader(
- APP_NAME,
- TEST_PACKAGE,
- /* numOfWidgets= */ 3);
-
- mViewHolderBinder.bindViewHolder(viewHolder, entry, /* position= */ 0, EMPTY_LIST);
- widgetsListHeader.callOnClick();
-
- verify(mOnHeaderClickListener).onHeaderClicked(eq(true),
- eq(PackageUserKey.fromPackageItemInfo(entry.mPkgItem)));
- }
-
- private WidgetsListSearchHeaderEntry generateSampleSearchHeader(String appName,
- String packageName, int numOfWidgets) {
- PackageItemInfo appInfo = new PackageItemInfo(packageName, UserHandle.CURRENT);
- appInfo.title = appName;
- appInfo.bitmap = BitmapInfo.of(Bitmap.createBitmap(10, 10, Bitmap.Config.ALPHA_8), 0);
-
- return new WidgetsListSearchHeaderEntry(appInfo,
- /* titleSectionName= */ "",
- generateWidgetItems(packageName, numOfWidgets));
- }
-
- private List<WidgetItem> generateWidgetItems(String packageName, int numOfWidgets) {
- ArrayList<WidgetItem> widgetItems = new ArrayList<>();
- for (int i = 0; i < numOfWidgets; i++) {
- ComponentName cn = ComponentName.createRelative(packageName, ".SampleWidget" + i);
- AppWidgetProviderInfo widgetInfo = WidgetUtils.createAppWidgetProviderInfo(cn);
-
- widgetItems.add(new WidgetItem(
- LauncherAppWidgetProviderInfo.fromProviderInfo(mContext, widgetInfo),
- mTestProfile, mIconCache));
- }
- return widgetItems;
- }
-}
diff --git a/tests/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchAlgorithmTest.java b/tests/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchAlgorithmTest.java
index d812ab0..0124f73 100644
--- a/tests/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchAlgorithmTest.java
+++ b/tests/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchAlgorithmTest.java
@@ -50,7 +50,6 @@
import com.android.launcher3.widget.model.WidgetsListBaseEntry;
import com.android.launcher3.widget.model.WidgetsListContentEntry;
import com.android.launcher3.widget.model.WidgetsListHeaderEntry;
-import com.android.launcher3.widget.model.WidgetsListSearchHeaderEntry;
import org.junit.Before;
import org.junit.Test;
@@ -117,12 +116,12 @@
.getAllWidgets();
assertEquals(List.of(
- new WidgetsListSearchHeaderEntry(
+ WidgetsListHeaderEntry.createForSearch(
mCalendarHeaderEntry.mPkgItem,
mCalendarHeaderEntry.mTitleSectionName,
mCalendarHeaderEntry.mWidgets),
mCalendarContentEntry,
- new WidgetsListSearchHeaderEntry(
+ WidgetsListHeaderEntry.createForSearch(
mCameraHeaderEntry.mPkgItem,
mCameraHeaderEntry.mTitleSectionName,
mCameraHeaderEntry.mWidgets),
@@ -138,7 +137,7 @@
.getAllWidgets();
assertEquals(List.of(
- new WidgetsListSearchHeaderEntry(
+ WidgetsListHeaderEntry.createForSearch(
mCalendarHeaderEntry.mPkgItem,
mCalendarHeaderEntry.mTitleSectionName,
mCalendarHeaderEntry.mWidgets.subList(1, 2)),
@@ -146,7 +145,7 @@
mCalendarHeaderEntry.mPkgItem,
mCalendarHeaderEntry.mTitleSectionName,
mCalendarHeaderEntry.mWidgets.subList(1, 2)),
- new WidgetsListSearchHeaderEntry(
+ WidgetsListHeaderEntry.createForSearch(
mCameraHeaderEntry.mPkgItem,
mCameraHeaderEntry.mTitleSectionName,
mCameraHeaderEntry.mWidgets.subList(1, 3)),
@@ -175,7 +174,7 @@
PackageItemInfo pInfo = createPackageItemInfo(packageName, appName,
widgetItems.get(0).user);
- return new WidgetsListHeaderEntry(pInfo, /* titleSectionName= */ "", widgetItems);
+ return WidgetsListHeaderEntry.create(pInfo, /* titleSectionName= */ "", widgetItems);
}
private WidgetsListContentEntry createWidgetsContentEntry(String packageName, String appName,