Merge "Restore drag&drop from WidgetsBottomSheet" into sc-dev
diff --git a/Android.bp b/Android.bp
index e30d22f..df0a96f 100644
--- a/Android.bp
+++ b/Android.bp
@@ -211,3 +211,30 @@
name: "launcher-proguard-rules",
srcs: ["proguard.flags"],
}
+
+
+// Library with all the dependencies for building Launcher Go
+android_library {
+ name: "LauncherGoResLib",
+ srcs: [
+ "src/**/*.java",
+ "quickstep/src/**/*.java",
+ "go/src/**/*.java",
+ "go/quickstep/src/**/*.java",
+ ],
+ resource_dirs: [
+ "go/res",
+ "go/quickstep/res",
+ ],
+ static_libs: [
+ "Launcher3CommonDepsLib",
+ "QuickstepResLib",
+ ],
+ manifest: "quickstep/AndroidManifest-launcher.xml",
+ additional_manifests: [
+ "go/AndroidManifest.xml",
+ "AndroidManifest-common.xml",
+ ],
+ min_sdk_version: "29",
+}
+
diff --git a/quickstep/robolectric_tests/src/com/android/quickstep/OrientationTouchTransformerTest.java b/quickstep/robolectric_tests/src/com/android/quickstep/OrientationTouchTransformerTest.java
index eca27b5..e771962 100644
--- a/quickstep/robolectric_tests/src/com/android/quickstep/OrientationTouchTransformerTest.java
+++ b/quickstep/robolectric_tests/src/com/android/quickstep/OrientationTouchTransformerTest.java
@@ -247,10 +247,7 @@
}
@Test
- @Ignore("There's too much that goes into needing to mock a real motion event so the "
- + "transforms in native code get applied correctly. Once that happens then maybe we can"
- + " write slightly more complex unit tests")
- public void applyTransform_taskNotFrozen_90Rotate_inTwoRegions() {
+ public void applyTransform_taskNotFrozen_90Rotate_withTwoRegions() {
mTouchTransformer.createOrAddTouchRegion(mInfo);
mTouchTransformer.enableMultipleRegions(true, mInfo);
mTouchTransformer
@@ -262,6 +259,7 @@
// Portrait point in landscape orientation axis
MotionEvent inRegion2 = generateMotionEvent(MotionEvent.ACTION_DOWN, 10, 10);
mTouchTransformer.transform(inRegion1_down);
+ // no-op
mTouchTransformer.transform(inRegion2);
assertTrue(mTouchTransformer.touchInValidSwipeRegions(
inRegion1_down.getX(), inRegion1_down.getY()));
@@ -269,9 +267,19 @@
assertFalse(mTouchTransformer.touchInValidSwipeRegions(inRegion2.getX(), inRegion2.getY()));
mTouchTransformer.transform(inRegion1_up);
+ }
- // Set the new region with this MotionEvent.ACTION_DOWN
- inRegion2 = generateAndTransformMotionEvent(MotionEvent.ACTION_DOWN, 10, 370);
+ @Test
+ public void applyTransform_90Rotate_inRotatedRegion() {
+ // Create regions for both 0 Rotation and 90 Rotation
+ mTouchTransformer.createOrAddTouchRegion(mInfo);
+ mTouchTransformer.enableMultipleRegions(true, mInfo);
+ mTouchTransformer
+ .createOrAddTouchRegion(createDisplayInfo(NORMAL_SCREEN_SIZE, Surface.ROTATION_90));
+ // Portrait point in landscape orientation axis
+ float x1 = generateTouchRegionHeight(NORMAL_SCREEN_SIZE, Surface.ROTATION_0);
+ // bottom of screen, from landscape perspective right side of screen
+ MotionEvent inRegion2 = generateAndTransformMotionEvent(MotionEvent.ACTION_DOWN, x1, 370);
assertTrue(mTouchTransformer.touchInValidSwipeRegions(inRegion2.getX(), inRegion2.getY()));
}
diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
index e9ded8a..4415b51 100644
--- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
@@ -219,7 +219,7 @@
mSplitPlaceholderView = findViewById(R.id.split_placeholder);
RecentsView overviewPanel = (RecentsView) getOverviewPanel();
mSplitPlaceholderView.init(
- new SplitSelectStateController(SystemUiProxy.INSTANCE.get(this))
+ new SplitSelectStateController(mHandler, SystemUiProxy.INSTANCE.get(this))
);
overviewPanel.init(mActionsView, mSplitPlaceholderView);
mActionsView.updateVerticalMargin(SysUINavigationMode.getMode(this));
diff --git a/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java b/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
index a749f9a..2a6e478 100644
--- a/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
+++ b/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
@@ -53,7 +53,7 @@
*/
class OrientationTouchTransformer {
- class CurrentDisplay {
+ private static class CurrentDisplay {
public Point size;
public int rotation;
@@ -68,6 +68,13 @@
}
@Override
+ public String toString() {
+ return "CurrentDisplay:"
+ + " rotation: " + rotation
+ + " size: " + size;
+ }
+
+ @Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
@@ -86,21 +93,20 @@
private static final String TAG = "OrientationTouchTransformer";
private static final boolean DEBUG = false;
- private static final int MAX_ORIENTATIONS = 4;
private static final int QUICKSTEP_ROTATION_UNINITIALIZED = -1;
private final Matrix mTmpMatrix = new Matrix();
private final float[] mTmpPoint = new float[2];
- private Map<CurrentDisplay, OrientationRectF> mSwipeTouchRegions =
+ private final Map<CurrentDisplay, OrientationRectF> mSwipeTouchRegions =
new HashMap<CurrentDisplay, OrientationRectF>();
private final RectF mAssistantLeftRegion = new RectF();
private final RectF mAssistantRightRegion = new RectF();
private final RectF mOneHandedModeRegion = new RectF();
private CurrentDisplay mCurrentDisplay = new CurrentDisplay();
private int mNavBarGesturalHeight;
- private int mNavBarLargerGesturalHeight;
+ private final int mNavBarLargerGesturalHeight;
private boolean mEnableMultipleRegions;
private Resources mResources;
private OrientationRectF mLastRectTouched;
@@ -374,10 +380,7 @@
return;
}
- for (int i = 0; i < MAX_ORIENTATIONS; i++) {
- CurrentDisplay display = new CurrentDisplay(mCurrentDisplay.size, i);
- OrientationRectF rect = mSwipeTouchRegions.get(display);
-
+ for (OrientationRectF rect : mSwipeTouchRegions.values()) {
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.NO_SWIPE_TO_HOME, "transform:DOWN, rect=" + rect);
}
diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
index 06137f2..7c453e7 100644
--- a/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -108,8 +108,7 @@
SplitPlaceholderView splitPlaceholderView = findViewById(R.id.split_placeholder);
splitPlaceholderView.init(
- new SplitSelectStateController(
- SystemUiProxy.INSTANCE.get(this))
+ new SplitSelectStateController(mUiHandler, SystemUiProxy.INSTANCE.get(this))
);
mDragLayer.recreateControllers();
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index 1f332c4..0ee28bc 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -35,6 +35,7 @@
import android.view.MotionEvent;
import com.android.launcher3.util.MainThreadInitializedObject;
+import com.android.launcher3.util.SplitConfigurationOptions;
import com.android.systemui.shared.recents.ISystemUiProxy;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.RemoteTransitionCompat;
@@ -491,6 +492,20 @@
}
}
+ /** Start multiple tasks in split-screen simultaneously. */
+ public void startTasks(int mainTaskId, Bundle mainOptions, int sideTaskId, Bundle sideOptions,
+ @SplitConfigurationOptions.StagePosition int sidePosition,
+ RemoteTransitionCompat remoteTransition) {
+ if (mSystemUiProxy != null) {
+ try {
+ mSplitScreen.startTasks(mainTaskId, mainOptions, sideTaskId, sideOptions,
+ sidePosition, remoteTransition.getTransition());
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed call startTask");
+ }
+ }
+ }
+
public void startShortcut(String packageName, String shortcutId, int stage, int position,
Bundle options, UserHandle user) {
if (mSplitScreen != null) {
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index bea1250..cbb2a66 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -15,6 +15,9 @@
*/
package com.android.quickstep;
+import static android.view.WindowManager.TRANSIT_OPEN;
+import static android.view.WindowManager.TRANSIT_TO_FRONT;
+
import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
import static com.android.launcher3.LauncherState.NORMAL;
@@ -47,7 +50,9 @@
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Build;
+import android.view.SurfaceControl;
import android.view.View;
+import android.window.TransitionInfo;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -352,7 +357,47 @@
* device is considered in multiWindowMode and things like insets and stuff change
* and calculations have to be adjusted in the animations for that
*/
- public static void composeRecentsSplitLaunchAnimator(@NonNull AnimatorSet anim,
+ public static void composeRecentsSplitLaunchAnimator(@NonNull TaskView initialView,
+ @NonNull TaskView v, @NonNull TransitionInfo transitionInfo,
+ SurfaceControl.Transaction t, @NonNull Runnable finishCallback) {
+
+ final TransitionInfo.Change[] splitRoots = new TransitionInfo.Change[2];
+ for (int i = 0; i < transitionInfo.getChanges().size(); ++i) {
+ final TransitionInfo.Change change = transitionInfo.getChanges().get(i);
+ final int taskId = change.getTaskInfo() != null ? change.getTaskInfo().taskId : -1;
+ final int mode = change.getMode();
+ // Find the target tasks' root tasks since those are the split stages that need to
+ // be animated (the tasks themselves are children and thus inherit animation).
+ if (taskId == initialView.getTask().key.id || taskId == v.getTask().key.id) {
+ if (!(mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT)) {
+ throw new IllegalStateException(
+ "Expected task to be showing, but it is " + mode);
+ }
+ if (change.getParent() == null) {
+ throw new IllegalStateException("Initiating multi-split launch but the split"
+ + "root of " + taskId + " is already visible or has broken hierarchy.");
+ }
+ splitRoots[taskId == initialView.getTask().key.id ? 0 : 1] =
+ transitionInfo.getChange(change.getParent());
+ }
+ }
+
+ // This is where we should animate the split roots. For now, though, just make them visible.
+ for (int i = 0; i < 2; ++i) {
+ t.show(splitRoots[i].getLeash());
+ t.setAlpha(splitRoots[i].getLeash(), 1.f);
+ }
+
+ // This contains the initial state (before animation), so apply this at the beginning of
+ // the animation.
+ t.apply();
+
+ // Once there is an animation, this should be called AFTER the animation completes.
+ finishCallback.run();
+ }
+
+ /** Legacy version (until shell transitions are enabled) */
+ public static void composeRecentsSplitLaunchAnimatorLegacy(@NonNull AnimatorSet anim,
@NonNull TaskView v, @NonNull RemoteAnimationTargetCompat[] appTargets,
@NonNull RemoteAnimationTargetCompat[] wallpaperTargets,
@NonNull RemoteAnimationTargetCompat[] nonAppTargets, boolean launcherClosing,
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index e3f2925..9576eac 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -16,11 +16,17 @@
package com.android.quickstep.util;
+import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
+import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
+import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
+
import android.animation.AnimatorSet;
import android.app.ActivityOptions;
import android.os.Handler;
import android.os.Looper;
import android.util.Pair;
+import android.view.SurfaceControl;
+import android.window.TransitionInfo;
import androidx.annotation.Nullable;
@@ -31,12 +37,15 @@
import com.android.launcher3.WrappedLauncherAnimationRunner;
import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
import com.android.quickstep.SystemUiProxy;
+import com.android.quickstep.TaskAnimationManager;
import com.android.quickstep.TaskViewUtils;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.system.ActivityOptionsCompat;
import com.android.systemui.shared.system.RemoteAnimationAdapterCompat;
import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
+import com.android.systemui.shared.system.RemoteTransitionCompat;
+import com.android.systemui.shared.system.RemoteTransitionRunner;
/**
* Represent data needed for the transient state when user has selected one app for split screen
@@ -47,9 +56,11 @@
private final SystemUiProxy mSystemUiProxy;
private TaskView mInitialTaskView;
private SplitPositionOption mInitialPosition;
+ private final Handler mHandler;
- public SplitSelectStateController(SystemUiProxy systemUiProxy) {
+ public SplitSelectStateController(Handler handler, SystemUiProxy systemUiProxy) {
mSystemUiProxy = systemUiProxy;
+ mHandler = handler;
}
/**
@@ -64,6 +75,19 @@
* To be called after second task selected
*/
public void setSecondTaskId(TaskView taskView) {
+ if (TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
+ // Assume initial task is for top/left part of screen
+ final int[] taskIds = mInitialPosition.mStagePosition == STAGE_POSITION_TOP_OR_LEFT
+ ? new int[]{mInitialTaskView.getTask().key.id, taskView.getTask().key.id}
+ : new int[]{taskView.getTask().key.id, mInitialTaskView.getTask().key.id};
+
+ RemoteSplitLaunchAnimationRunner animationRunner =
+ new RemoteSplitLaunchAnimationRunner(mInitialTaskView, taskView);
+ mSystemUiProxy.startTasks(taskIds[0], null /* mainOptions */, taskIds[1],
+ null /* sideOptions */, STAGE_POSITION_BOTTOM_OR_RIGHT,
+ new RemoteTransitionCompat(animationRunner, MAIN_EXECUTOR));
+ return;
+ }
// Assume initial mInitialTaskId is for top/left part of screen
WrappedAnimationRunnerImpl initialSplitRunnerWrapped = new SplitLaunchAnimationRunner(
mInitialTaskView, 0);
@@ -96,6 +120,30 @@
}
/**
+ * Requires Shell Transitions
+ */
+ private class RemoteSplitLaunchAnimationRunner implements RemoteTransitionRunner {
+
+ private final TaskView mInitialTaskView;
+ private final TaskView mTaskView;
+
+ RemoteSplitLaunchAnimationRunner(TaskView initialTaskView, TaskView taskView) {
+ mInitialTaskView = initialTaskView;
+ mTaskView = taskView;
+ }
+
+ @Override
+ public void startAnimation(TransitionInfo info, SurfaceControl.Transaction t,
+ Runnable finishCallback) {
+ TaskViewUtils.composeRecentsSplitLaunchAnimator(mInitialTaskView, mTaskView,
+ info, t, finishCallback);
+ // After successful launch, call resetState
+ resetState();
+ }
+ }
+
+ /**
+ * LEGACY
* @return the opposite stage and position from the {@param position} provided as first and
* second object, respectively
* Ex. If position is has stage = Main and position = Top/Left, this will return
@@ -109,6 +157,7 @@
}
/**
+ * LEGACY
* Remote animation runner for animation to launch an app.
*/
private class SplitLaunchAnimationRunner implements WrappedAnimationRunnerImpl {
@@ -129,7 +178,7 @@
LauncherAnimationRunner.AnimationResult result) {
AnimatorSet anim = new AnimatorSet();
BaseQuickstepLauncher activity = BaseActivity.fromContext(mV.getContext());
- TaskViewUtils.composeRecentsSplitLaunchAnimator(anim, mV,
+ TaskViewUtils.composeRecentsSplitLaunchAnimatorLegacy(anim, mV,
appTargets, wallpaperTargets, nonAppTargets, true, activity.getStateManager(),
activity.getDepthController(), mTargetState);
result.setAnimation(anim, activity);
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index 5ffe315..0fe5432 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -120,7 +120,6 @@
getCurrentOverviewPage(launcher) < currentTaskAfterFlingForward));
// Test opening a task.
- startTestActivity(2);
OverviewTask task = mLauncher.pressHome().switchToOverview().getCurrentTask();
assertNotNull("overview.getCurrentTask() returned null (1)", task);
assertNotNull("OverviewTask.open returned null", task.open());
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 986180c..9072907 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -95,6 +95,9 @@
<!-- Tab label. A user can tap this tab to access their work widgets. [CHAR_LIMIT=25] -->
<string name="widgets_full_sheet_work_tab">Work</string>
+ <!-- A widget category label for grouping widgets related to conversations. [CHAR_LIMIT=30] -->
+ <string name="widget_category_conversations">Conversations</string>
+
<!-- All Apps -->
<!-- Search bar text in the apps view. [CHAR_LIMIT=50] -->
<string name="all_apps_search_bar_hint">Search apps</string>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index a27cdac..fd77b80 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -150,7 +150,7 @@
</style>
<style name="HomeSettingsTheme" parent="@android:style/Theme.DeviceDefault.Settings">
- <item name="android:navigationBarColor">@android:color/transparent</item>
+ <item name="android:navigationBarColor">?android:colorPrimaryDark</item>
<item name="preferenceTheme">@style/HomeSettingsPreferenceTheme</item>
</style>
diff --git a/robolectric_tests/src/com/android/launcher3/model/BackupRestoreTest.java b/robolectric_tests/src/com/android/launcher3/model/BackupRestoreTest.java
index 8baf5a3..adf720f 100644
--- a/robolectric_tests/src/com/android/launcher3/model/BackupRestoreTest.java
+++ b/robolectric_tests/src/com/android/launcher3/model/BackupRestoreTest.java
@@ -35,6 +35,7 @@
import android.content.pm.PackageInstaller;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
+import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
@@ -64,17 +65,11 @@
private static final long OLD_WORK_PROFILE_ID = 11;
private static final int WORK_PROFILE_ID = 10;
- private static final int SYSTEM_USER = 0;
- private static final int FLAG_SYSTEM = 0x00000800;
- private static final int FLAG_PROFILE = 0x00001000;
-
private ShadowUserManager mUserManager;
private BackupManager mBackupManager;
private LauncherModelHelper mModelHelper;
private SQLiteDatabase mDb;
private InvariantDeviceProfile mIdp;
- private UserHandle mMainProfileUser;
- private UserHandle mWorkProfileUser;
@Before
public void setUp() {
@@ -90,17 +85,15 @@
final UserManager userManager = RuntimeEnvironment.application.getSystemService(
UserManager.class);
mUserManager = Shadow.extract(userManager);
- // sign in to primary user
- mMainProfileUser = mUserManager.addUser(SYSTEM_USER, "me", FLAG_SYSTEM);
// sign in to work profile
- mWorkProfileUser = mUserManager.addUser(WORK_PROFILE_ID, "work", FLAG_PROFILE);
+ mUserManager.addUser(WORK_PROFILE_ID, "work", ShadowUserManager.FLAG_MANAGED_PROFILE);
}
private void setupBackupManager() {
mBackupManager = new BackupManager(RuntimeEnvironment.application);
final LShadowBackupManager bm = Shadow.extract(mBackupManager);
- bm.addProfile(MY_OLD_PROFILE_ID, mMainProfileUser);
- bm.addProfile(OLD_WORK_PROFILE_ID, mWorkProfileUser);
+ bm.addProfile(MY_OLD_PROFILE_ID, Process.myUserHandle());
+ bm.addProfile(OLD_WORK_PROFILE_ID, UserHandle.of(WORK_PROFILE_ID));
}
@Test
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 01f7c71..7496703 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -926,8 +926,7 @@
if (disallowIntercept) {
// We need to make sure to cancel our long press if
// a scrollable widget takes over touch events
- final View currentPage = getPageAt(mCurrentPage);
- currentPage.cancelLongPress();
+ cancelCurrentPageLongPress();
}
super.requestDisallowInterceptTouchEvent(disallowIntercept);
}
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index a1b7997..cf1cb45 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -78,7 +78,6 @@
import com.android.launcher3.R;
import com.android.launcher3.ShortcutAndWidgetContainer;
import com.android.launcher3.Utilities;
-import com.android.launcher3.Workspace;
import com.android.launcher3.Workspace.ItemOperator;
import com.android.launcher3.accessibility.AccessibleDragListenerAdapter;
import com.android.launcher3.accessibility.FolderAccessibilityHelper;
@@ -534,9 +533,25 @@
}
private void startAnimation(final AnimatorSet a) {
- final Workspace workspace = mLauncher.getWorkspace();
- final CellLayout currentCellLayout =
- (CellLayout) workspace.getChildAt(workspace.getCurrentPage());
+ mLauncher.getWorkspace().getVisiblePages()
+ .forEach(visiblePage -> addAnimatorListenerForPage(a, (CellLayout) visiblePage));
+
+ a.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mState = STATE_ANIMATING;
+ mCurrentAnimator = a;
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mCurrentAnimator = null;
+ }
+ });
+ a.start();
+ }
+
+ private void addAnimatorListenerForPage(AnimatorSet a, CellLayout currentCellLayout) {
final boolean useHardware = shouldUseHardwareLayerForAnimation(currentCellLayout);
final boolean wasHardwareAccelerated = currentCellLayout.isHardwareLayerEnabled();
@@ -546,8 +561,6 @@
if (useHardware) {
currentCellLayout.enableHardwareLayer(true);
}
- mState = STATE_ANIMATING;
- mCurrentAnimator = a;
}
@Override
@@ -555,10 +568,8 @@
if (useHardware) {
currentCellLayout.enableHardwareLayer(wasHardwareAccelerated);
}
- mCurrentAnimator = null;
}
});
- a.start();
}
private boolean shouldUseHardwareLayerForAnimation(CellLayout currentCellLayout) {
diff --git a/src/com/android/launcher3/icons/IconCache.java b/src/com/android/launcher3/icons/IconCache.java
index 988794c..a2c0f5c 100644
--- a/src/com/android/launcher3/icons/IconCache.java
+++ b/src/com/android/launcher3/icons/IconCache.java
@@ -39,6 +39,7 @@
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherFiles;
+import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.icons.ComponentWithLabel.ComponentCachingLogic;
@@ -304,6 +305,11 @@
CacheEntry entry = getEntryForPackageLocked(
infoInOut.packageName, infoInOut.user, useLowResIcon);
applyCacheEntry(entry, infoInOut);
+ if (infoInOut.category == PackageItemInfo.CONVERSATIONS) {
+ infoInOut.title = mContext.getString(R.string.widget_category_conversations);
+ infoInOut.contentDescription = mPackageManager.getUserBadgedLabel(
+ infoInOut.title, infoInOut.user);
+ }
}
protected void applyCacheEntry(CacheEntry entry, ItemInfoWithIcon info) {
diff --git a/src/com/android/launcher3/model/data/PackageItemInfo.java b/src/com/android/launcher3/model/data/PackageItemInfo.java
index 7617d7e..a81fe6a 100644
--- a/src/com/android/launcher3/model/data/PackageItemInfo.java
+++ b/src/com/android/launcher3/model/data/PackageItemInfo.java
@@ -16,27 +16,47 @@
package com.android.launcher3.model.data;
+import androidx.annotation.IntDef;
+
import com.android.launcher3.LauncherSettings;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.Objects;
/**
* Represents a {@link Package} in the widget tray section.
*/
public class PackageItemInfo extends ItemInfoWithIcon {
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({NO_CATEGORY, CONVERSATIONS})
+ public @interface Category{}
+ /** The package is not categorized in the widget tray. */
+ public static final int NO_CATEGORY = 0;
+ /** The package is categorized to conversations widget in the widget tray. */
+ public static final int CONVERSATIONS = 1;
/**
* Package name of the {@link PackageItemInfo}.
*/
- public String packageName;
+ public final String packageName;
+
+ /** Represents a widget category shown in the widget tray section. */
+ @Category public final int category;
public PackageItemInfo(String packageName) {
+ this(packageName, NO_CATEGORY);
+ }
+
+ public PackageItemInfo(String packageName, @Category int category) {
this.packageName = packageName;
+ this.category = category;
this.itemType = LauncherSettings.Favorites.ITEM_TYPE_NON_ACTIONABLE;
}
public PackageItemInfo(PackageItemInfo copy) {
this.packageName = copy.packageName;
+ this.category = copy.category;
this.itemType = LauncherSettings.Favorites.ITEM_TYPE_NON_ACTIONABLE;
}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java b/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java
index 6569fb0..b95bb16 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java
@@ -17,8 +17,10 @@
import android.content.Context;
import android.util.AttributeSet;
+import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
+import android.view.View;
import android.view.ViewGroup;
import android.widget.TableLayout;
import android.widget.TableRow;
@@ -31,14 +33,15 @@
import com.android.launcher3.R;
import com.android.launcher3.model.WidgetItem;
import com.android.launcher3.widget.WidgetCell;
-import com.android.launcher3.widget.WidgetImageView;
import java.util.ArrayList;
import java.util.List;
/** A {@link TableLayout} for showing recommended widgets. */
public final class WidgetsRecommendationTableLayout extends TableLayout {
- private static final float SCALE_DOWN_RATIO = 0.9f;
+ private static final String TAG = "WidgetsRecommendationTableLayout";
+ private static final float DOWN_SCALE_RATIO = 0.9f;
+ private static final float MAX_DOWN_SCALE_RATIO = 0.5f;
private final DeviceProfile mDeviceProfile;
private final float mWidgetCellTextViewsHeight;
@@ -119,9 +122,9 @@
getContext()).inflate(R.layout.widget_cell, parent, false);
widget.setOnTouchListener(mWidgetCellOnTouchListener);
- WidgetImageView preview = widget.findViewById(R.id.widget_preview);
- preview.setOnClickListener(mWidgetCellOnClickListener);
- preview.setOnLongClickListener(mWidgetCellOnLongClickListener);
+ View previewContainer = widget.findViewById(R.id.widget_preview_container);
+ previewContainer.setOnClickListener(mWidgetCellOnClickListener);
+ previewContainer.setOnLongClickListener(mWidgetCellOnLongClickListener);
widget.setAnimatePreview(false);
parent.addView(widget);
@@ -131,6 +134,10 @@
private RecommendationTableData fitRecommendedWidgetsToTableSpace(
float previewScale,
List<ArrayList<WidgetItem>> recommendedWidgetsInTable) {
+ if (previewScale < MAX_DOWN_SCALE_RATIO) {
+ Log.w(TAG, "Hide recommended widgets. Can't down scale previews to " + previewScale);
+ return new RecommendationTableData(List.of(), previewScale);
+ }
// A naive estimation of the widgets recommendation table height without inflation.
float totalHeight = 0;
for (int i = 0; i < recommendedWidgetsInTable.size(); i++) {
@@ -157,7 +164,7 @@
/* toIndex= */recommendedWidgetsInTable.size() - 1));
}
- float nextPreviewScale = previewScale * SCALE_DOWN_RATIO;
+ float nextPreviewScale = previewScale * DOWN_SCALE_RATIO;
return fitRecommendedWidgetsToTableSpace(nextPreviewScale, recommendedWidgetsInTable);
}
diff --git a/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java b/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java
index f82f2cc..be18e54 100644
--- a/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java
+++ b/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java
@@ -36,6 +36,7 @@
import com.android.launcher3.widget.picker.WidgetsDiffReporter;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -58,6 +59,9 @@
private static final String TAG = "WidgetsModel";
private static final boolean DEBUG = false;
+ private static final ComponentName CONVERSATION_WIDGET = ComponentName.createRelative(
+ "com.android.systemui", ".people.widget.PeopleSpaceWidgetProvider");
+
/* Map of widgets and shortcuts that are tracked per package. */
private final Map<PackageItemInfo, List<WidgetItem>> mWidgetsList = new HashMap<>();
@@ -156,7 +160,7 @@
// Temporary list for {@link PackageItemInfos} to avoid having to go through
// {@link mPackageItemInfos} to locate the key to be used for {@link #mWidgetsList}
- HashMap<PackageUserKey, PackageItemInfo> tmpPackageItemInfos = new HashMap<>();
+ HashMap<WidgetPackageOrCategoryKey, PackageItemInfo> tmpPackageItemInfos = new HashMap<>();
// Clear the lists only if this is an update on all widgets and shortcuts. If packageUser
// isn't null, only updates the shortcuts and widgets for the app represented in
@@ -168,11 +172,11 @@
mWidgetsList.putAll(rawWidgetsShortcuts.stream()
.filter(new WidgetValidityCheck(app))
.collect(Collectors.groupingBy(item -> {
- PackageUserKey packageUserKey = new PackageUserKey(
- item.componentName.getPackageName(), item.user);
+ WidgetPackageOrCategoryKey packageUserKey = getWidgetPackageOrCategoryKey(item);
PackageItemInfo pInfo = tmpPackageItemInfos.get(packageUserKey);
if (pInfo == null) {
- pInfo = new PackageItemInfo(packageUserKey.mPackageName);
+ pInfo = new PackageItemInfo(item.componentName.getPackageName(),
+ packageUserKey.mCategory);
pInfo.user = item.user;
tmpPackageItemInfos.put(packageUserKey, pInfo);
}
@@ -224,6 +228,13 @@
return null;
}
+ private WidgetPackageOrCategoryKey getWidgetPackageOrCategoryKey(WidgetItem item) {
+ if (CONVERSATION_WIDGET.equals(item.componentName)) {
+ return new WidgetPackageOrCategoryKey(PackageItemInfo.CONVERSATIONS, item.user);
+ }
+ return new WidgetPackageOrCategoryKey(item.componentName.getPackageName(), item.user);
+ }
+
private static class WidgetValidityCheck implements Predicate<WidgetItem> {
private final InvariantDeviceProfile mIdp;
@@ -265,4 +276,40 @@
return true;
}
}
+
+ /** A hash key for grouping widgets by package name or category. */
+ private static class WidgetPackageOrCategoryKey {
+ /**
+ * The package name of the widget provider.
+ *
+ * <p>This shouldn't be empty if {@link #mCategory} has a value,
+ * {@link PackageItemInfo#NO_CATEGORY}.
+ */
+ public final String mPackage;
+ /** A widget category. */
+ @PackageItemInfo.Category public final int mCategory;
+ public final UserHandle mUser;
+ private final int mHashCode;
+
+ WidgetPackageOrCategoryKey(String packageName, UserHandle user) {
+ this(packageName, PackageItemInfo.NO_CATEGORY, user);
+ }
+
+ WidgetPackageOrCategoryKey(@PackageItemInfo.Category int category, UserHandle user) {
+ this("", category, user);
+ }
+
+ private WidgetPackageOrCategoryKey(String packageName,
+ @PackageItemInfo.Category int category, UserHandle user) {
+ mPackage = packageName;
+ mCategory = category;
+ mUser = user;
+ mHashCode = Arrays.hashCode(new Object[]{mPackage, mCategory, mUser});
+ }
+
+ @Override
+ public int hashCode() {
+ return mHashCode;
+ }
+ }
}
\ No newline at end of file
diff --git a/tests/res/layout/test_layout_appwidget_dynamic_colors.xml b/tests/res/layout/test_layout_appwidget_dynamic_colors.xml
index 21625c6..56c343e 100644
--- a/tests/res/layout/test_layout_appwidget_dynamic_colors.xml
+++ b/tests/res/layout/test_layout_appwidget_dynamic_colors.xml
@@ -14,7 +14,7 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
- android:text="prim"/>
+ android:text="neut1"/>
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
@@ -28,7 +28,7 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
- android:text="second"/>
+ android:text="accent1"/>
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
@@ -42,11 +42,11 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
- android:text="neutral"/>
+ android:text="accent2"/>
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
- android:background="@android:color/system_neutral2_500"/>
+ android:background="@android:color/system_accent2_500"/>
</LinearLayout>
</LinearLayout>
\ No newline at end of file