Merge "Fix spring loaded scale when taskbar is present" into sc-dev
diff --git a/AndroidManifest-common.xml b/AndroidManifest-common.xml
index 4fd2e40..4e72260 100644
--- a/AndroidManifest-common.xml
+++ b/AndroidManifest-common.xml
@@ -116,8 +116,7 @@
android:theme="@style/AppItemActivityTheme"
android:excludeFromRecents="true"
android:autoRemoveFromRecents="true"
- android:exported="true"
- android:label="@string/action_add_to_workspace" >
+ android:exported="true">
<intent-filter>
<action android:name="android.content.pm.action.CONFIRM_PIN_SHORTCUT" />
<action android:name="android.content.pm.action.CONFIRM_PIN_APPWIDGET" />
diff --git a/go/AndroidManifest.xml b/go/AndroidManifest.xml
index f36439d..2671604 100644
--- a/go/AndroidManifest.xml
+++ b/go/AndroidManifest.xml
@@ -24,6 +24,8 @@
<uses-sdk android:targetSdkVersion="29" android:minSdkVersion="25"/>
+ <uses-permission android:name="android.permission.GET_TOP_ACTIVITY_INFO" />
+
<application
android:backupAgent="com.android.launcher3.LauncherBackupAgent"
android:fullBackupOnly="true"
diff --git a/go/quickstep/res/values/config.xml b/go/quickstep/res/values/config.xml
index 9dca137..a21381c 100644
--- a/go/quickstep/res/values/config.xml
+++ b/go/quickstep/res/values/config.xml
@@ -20,5 +20,5 @@
<string name="niu_actions_package" translatable="false"/>
<!-- Feature Flags -->
- <bool name="enable_niu_actions">false</bool>
+ <bool name="enable_niu_actions">true</bool>
</resources>
\ No newline at end of file
diff --git a/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java b/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java
index b102a39..36a4e7f 100644
--- a/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java
+++ b/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java
@@ -20,11 +20,21 @@
import static com.android.quickstep.views.OverviewActionsView.DISABLED_ROTATED;
import android.annotation.SuppressLint;
+import android.app.ActivityTaskManager;
+import android.app.IAssistDataReceiver;
+import android.app.assist.AssistContent;
import android.content.Context;
import android.content.Intent;
+import android.graphics.Bitmap;
import android.graphics.Matrix;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.RemoteException;
import android.os.SystemClock;
import android.text.TextUtils;
+import android.util.Log;
import com.android.launcher3.R;
import com.android.quickstep.views.OverviewActionsView;
@@ -40,6 +50,8 @@
public static final String ACTION_TRANSLATE = "com.android.quickstep.ACTION_TRANSLATE";
public static final String ACTION_SEARCH = "com.android.quickstep.ACTION_SEARCH";
public static final String ELAPSED_NANOS = "niu_actions_elapsed_realtime_nanos";
+ public static final String ACTIONS_URL = "niu_actions_app_url";
+ private static final String TAG = "TaskOverlayFactoryGo";
// Empty constructor required for ResourceBasedOverride
public TaskOverlayFactoryGo(Context context) {}
@@ -56,11 +68,16 @@
* @param <T> The type of View in which the overlay will be placed
*/
public static final class TaskOverlayGo<T extends OverviewActionsView> extends TaskOverlay {
+ private static final String ASSIST_KEY_CONTENT = "content";
- private String mPackageName;
+ private String mNIUPackageName;
+ private int mTaskId;
+ private Bundle mAssistData;
+ private final Handler mMainThreadHandler;
private TaskOverlayGo(TaskThumbnailView taskThumbnailView) {
super(taskThumbnailView);
+ mMainThreadHandler = new Handler(Looper.getMainLooper());
}
/**
@@ -70,16 +87,39 @@
public void initOverlay(Task task, ThumbnailData thumbnail, Matrix matrix,
boolean rotated) {
getActionsView().updateDisabledFlags(DISABLED_NO_THUMBNAIL, thumbnail == null);
- mPackageName =
+ mNIUPackageName =
mApplicationContext.getResources().getString(R.string.niu_actions_package);
- if (thumbnail == null || TextUtils.isEmpty(mPackageName)) {
+ if (thumbnail == null || TextUtils.isEmpty(mNIUPackageName)) {
return;
}
getActionsView().updateDisabledFlags(DISABLED_ROTATED, rotated);
boolean isAllowedByPolicy = thumbnail.isRealSnapshot;
getActionsView().setCallbacks(new OverlayUICallbacksGoImpl(isAllowedByPolicy, task));
+
+ mTaskId = task.key.id;
+ AssistDataReceiverImpl receiver = new AssistDataReceiverImpl();
+ receiver.setOverlay(this);
+
+ try {
+ ActivityTaskManager.getService().requestAssistDataForTask(receiver, mTaskId,
+ mApplicationContext.getPackageName());
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to request AssistData");
+ }
+ }
+
+ /**
+ * Called when AssistDataReceiverImpl receives data from ActivityTaskManagerService's
+ * AssistDataRequester
+ */
+ public void onAssistDataReceived(Bundle data) {
+ mMainThreadHandler.post(() -> {
+ if (data != null) {
+ mAssistData = data;
+ }
+ });
}
private void sendNIUIntent(String actionType) {
@@ -88,11 +128,21 @@
}
private Intent createNIUIntent(String actionType) {
- return new Intent(actionType)
+ Intent intent = new Intent(actionType)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK)
.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION)
- .setPackage(mPackageName)
+ .setPackage(mNIUPackageName)
.putExtra(ELAPSED_NANOS, SystemClock.elapsedRealtimeNanos());
+
+ if (mAssistData != null) {
+ final AssistContent content = mAssistData.getParcelable(ASSIST_KEY_CONTENT);
+ Uri webUri = (content == null) ? null : content.getWebUri();
+ if (webUri != null) {
+ intent.putExtra(ACTIONS_URL, webUri.toString());
+ }
+ }
+
+ return intent;
}
protected class OverlayUICallbacksGoImpl extends OverlayUICallbacksImpl
@@ -131,6 +181,26 @@
}
/**
+ * Basic AssistDataReceiver. This is passed to ActivityTaskManagerService, which then requests
+ * the data.
+ */
+ private static final class AssistDataReceiverImpl extends IAssistDataReceiver.Stub {
+ private TaskOverlayGo mOverlay;
+
+ public void setOverlay(TaskOverlayGo overlay) {
+ mOverlay = overlay;
+ }
+
+ @Override
+ public void onHandleAssistData(Bundle data) {
+ mOverlay.onAssistDataReceived(data);
+ }
+
+ @Override
+ public void onHandleAssistScreenshot(Bitmap screenshot) {}
+ }
+
+ /**
* Callbacks the Ui can generate. This is the only way for a Ui to call methods on the
* controller.
*/
diff --git a/quickstep/Android.bp b/quickstep/Android.bp
index 585b6ad..38c9919 100644
--- a/quickstep/Android.bp
+++ b/quickstep/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "packages_apps_Launcher3_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["packages_apps_Launcher3_license"],
+}
+
filegroup {
name: "launcher3-quickstep-robolectric-src",
path: "robolectric_tests",
diff --git a/quickstep/res/layout/taskbar_divider.xml b/quickstep/res/layout/taskbar_divider.xml
index 6e1aa1e..87649f7 100644
--- a/quickstep/res/layout/taskbar_divider.xml
+++ b/quickstep/res/layout/taskbar_divider.xml
@@ -18,6 +18,4 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="@dimen/taskbar_divider_thickness"
android:layout_height="@dimen/taskbar_divider_height"
- android:layout_marginStart="@dimen/taskbar_icon_spacing"
- android:layout_marginEnd="@dimen/taskbar_icon_spacing"
android:background="@color/taskbar_divider" />
\ No newline at end of file
diff --git a/quickstep/res/layout/taskbar_view.xml b/quickstep/res/layout/taskbar_view.xml
new file mode 100644
index 0000000..34a88ea
--- /dev/null
+++ b/quickstep/res/layout/taskbar_view.xml
@@ -0,0 +1,26 @@
+<?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.
+-->
+
+<com.android.launcher3.taskbar.TaskbarView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/taskbar_view"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/taskbar_size"
+ android:background="@android:color/transparent"
+ android:layout_gravity="bottom"
+ android:gravity="center"
+ android:visibility="gone" />
+
diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
index c4becf1..9ab49ce 100644
--- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
@@ -46,6 +46,7 @@
import com.android.launcher3.taskbar.TaskbarActivityContext;
import com.android.launcher3.taskbar.TaskbarController;
import com.android.launcher3.taskbar.TaskbarStateHandler;
+import com.android.launcher3.taskbar.TaskbarView;
import com.android.launcher3.uioverrides.RecentsViewStateController;
import com.android.launcher3.util.ActivityOptionsWrapper;
import com.android.launcher3.util.DisplayController;
@@ -243,9 +244,10 @@
mTaskbarController = null;
}
if (mDeviceProfile.isTaskbarPresent) {
+ TaskbarView taskbarViewOnHome = (TaskbarView) mHotseat.getTaskbarView();
TaskbarActivityContext taskbarActivityContext = new TaskbarActivityContext(this);
mTaskbarController = new TaskbarController(this,
- taskbarActivityContext.getTaskbarContainerView());
+ taskbarActivityContext.getTaskbarContainerView(), taskbarViewOnHome);
mTaskbarController.init();
}
}
diff --git a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
index b1b4d70..df3657d 100644
--- a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
+++ b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
@@ -73,6 +73,7 @@
public static final String LAST_PREDICTION_ENABLED_STATE = "last_prediction_enabled_state";
private static final String LAST_SNAPSHOT_TIME_MILLIS = "LAST_SNAPSHOT_TIME_MILLIS";
+ private static final int NUM_OF_RECOMMENDED_WIDGETS_PREDICATION = 20;
private static final boolean IS_DEBUG = false;
private static final String TAG = "QuickstepModelDelegate";
@@ -217,7 +218,7 @@
registerWidgetsPredictor(apm.createAppPredictionSession(
new AppPredictionContext.Builder(context)
.setUiSurface("widgets")
- .setPredictedTargetCount(mIDP.numColumns)
+ .setPredictedTargetCount(NUM_OF_RECOMMENDED_WIDGETS_PREDICATION)
.build()));
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 8312b82..fc5e2c1 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -54,10 +54,7 @@
return mTaskbarContainerView;
}
- /**
- * @return A LayoutInflater to use in this Context. Views inflated with this LayoutInflater will
- * be able to access this TaskbarActivityContext via ActivityContext.lookupContext().
- */
+ @Override
public LayoutInflater getLayoutInflater() {
return mLayoutInflater;
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarContainerView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarContainerView.java
index 528f43e..5202d91 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarContainerView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarContainerView.java
@@ -84,7 +84,7 @@
private ViewTreeObserverWrapper.OnComputeInsetsListener createTaskbarInsetsComputer() {
return insetsInfo -> {
if (getAlpha() < AlphaUpdateListener.ALPHA_CUTOFF_THRESHOLD
- || mTaskbarView.isDraggingItem()) {
+ || mTaskbarView.getVisibility() != VISIBLE || mTaskbarView.isDraggingItem()) {
// We're invisible or dragging out of taskbar, let touches pass through us.
insetsInfo.touchableRegion.setEmpty();
insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java
index f652961..abf6d54 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java
@@ -19,8 +19,6 @@
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
-import static com.android.launcher3.AbstractFloatingView.TYPE_HIDE_TASKBAR;
-import static com.android.launcher3.AbstractFloatingView.TYPE_REPLACE_TASKBAR_WITH_HOTSEAT;
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.systemui.shared.system.WindowManagerWrapper.ITYPE_BOTTOM_TAPPABLE_ELEMENT;
@@ -43,7 +41,6 @@
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BaseQuickstepLauncher;
import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.Hotseat;
import com.android.launcher3.LauncherState;
import com.android.launcher3.QuickstepTransitionManager;
import com.android.launcher3.R;
@@ -54,6 +51,7 @@
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.touch.ItemClickHandler;
+import com.android.launcher3.views.ActivityContext;
import com.android.quickstep.AnimatedFloat;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -70,7 +68,8 @@
private static final String WINDOW_TITLE = "Taskbar";
private final TaskbarContainerView mTaskbarContainerView;
- private final TaskbarView mTaskbarView;
+ private final TaskbarView mTaskbarViewInApp;
+ private final TaskbarView mTaskbarViewOnHome;
private final BaseQuickstepLauncher mLauncher;
private final WindowManager mWindowManager;
// Layout width and height of the Taskbar in the default state.
@@ -91,14 +90,17 @@
private @Nullable Animator mAnimator;
private boolean mIsAnimatingToLauncher;
+ private boolean mIsAnimatingToApp;
public TaskbarController(BaseQuickstepLauncher launcher,
- TaskbarContainerView taskbarContainerView) {
+ TaskbarContainerView taskbarContainerView, TaskbarView taskbarViewOnHome) {
mLauncher = launcher;
mTaskbarContainerView = taskbarContainerView;
mTaskbarContainerView.construct(createTaskbarContainerViewCallbacks());
- mTaskbarView = mTaskbarContainerView.findViewById(R.id.taskbar_view);
- mTaskbarView.construct(createTaskbarViewCallbacks());
+ mTaskbarViewInApp = mTaskbarContainerView.findViewById(R.id.taskbar_view);
+ mTaskbarViewInApp.construct(createTaskbarViewCallbacks());
+ mTaskbarViewOnHome = taskbarViewOnHome;
+ mTaskbarViewOnHome.construct(createTaskbarViewCallbacks());
mWindowManager = mLauncher.getWindowManager();
mTaskbarSize = new Point(MATCH_PARENT, mLauncher.getDeviceProfile().taskbarSize);
mTaskbarStateHandler = mLauncher.getTaskbarStateHandler();
@@ -115,12 +117,13 @@
return new TaskbarVisibilityControllerCallbacks() {
@Override
public void updateTaskbarBackgroundAlpha(float alpha) {
- mTaskbarView.setBackgroundAlpha(alpha);
+ mTaskbarViewInApp.setBackgroundAlpha(alpha);
}
@Override
public void updateTaskbarVisibilityAlpha(float alpha) {
mTaskbarContainerView.setAlpha(alpha);
+ mTaskbarViewOnHome.setAlpha(alpha);
}
};
}
@@ -196,7 +199,7 @@
public View.OnLongClickListener getItemOnLongClickListener() {
return view -> {
if (mLauncher.hasBeenResumed() && view.getTag() instanceof ItemInfo) {
- alignRealHotseatWithTaskbar();
+ // TODO: remove this path
return mDragController.startWorkspaceDragOnLongClick(view);
} else {
return mDragController.startSystemDragOnLongClick(view);
@@ -205,11 +208,24 @@
}
@Override
- public int getEmptyHotseatViewVisibility() {
+ public int getEmptyHotseatViewVisibility(TaskbarView taskbarView) {
// When on the home screen, we want the empty hotseat views to take up their full
// space so that the others line up with the home screen hotseat.
- return mLauncher.hasBeenResumed() || mIsAnimatingToLauncher
- ? View.INVISIBLE : View.GONE;
+ boolean isOnHomeScreen = taskbarView == mTaskbarViewOnHome
+ || mLauncher.hasBeenResumed() || mIsAnimatingToLauncher;
+ return isOnHomeScreen ? View.INVISIBLE : View.GONE;
+ }
+
+ @Override
+ public float getNonIconScale(TaskbarView taskbarView) {
+ return taskbarView == mTaskbarViewOnHome ? getTaskbarScaleOnHome() : 1f;
+ }
+
+ @Override
+ public void onItemPositionsChanged(TaskbarView taskbarView) {
+ if (taskbarView == mTaskbarViewOnHome) {
+ alignRealHotseatWithTaskbar();
+ }
}
};
}
@@ -218,7 +234,7 @@
return new TaskbarHotseatControllerCallbacks() {
@Override
public void updateHotseatItems(ItemInfo[] hotseatItemInfos) {
- mTaskbarView.updateHotseatItems(hotseatItemInfos);
+ mTaskbarViewInApp.updateHotseatItems(hotseatItemInfos);
mLatestLoadedHotseatItems = hotseatItemInfos;
dedupeAndUpdateRecentItems();
}
@@ -235,7 +251,8 @@
@Override
public void updateRecentTaskAtIndex(int taskIndex, Task task) {
- mTaskbarView.updateRecentTaskAtIndex(taskIndex, task);
+ mTaskbarViewInApp.updateRecentTaskAtIndex(taskIndex, task);
+ mTaskbarViewOnHome.updateRecentTaskAtIndex(taskIndex, task);
}
};
}
@@ -244,16 +261,20 @@
* Initializes the Taskbar, including adding it to the screen.
*/
public void init() {
- mTaskbarView.init(mHotseatController.getNumHotseatIcons(),
+ mTaskbarViewInApp.init(mHotseatController.getNumHotseatIcons(),
mRecentsController.getNumRecentIcons());
- mTaskbarContainerView.init(mTaskbarView);
+ mTaskbarViewOnHome.init(mHotseatController.getNumHotseatIcons(),
+ mRecentsController.getNumRecentIcons());
+ mTaskbarContainerView.init(mTaskbarViewInApp);
addToWindowManager();
mTaskbarStateHandler.setTaskbarCallbacks(createTaskbarStateHandlerCallbacks());
mTaskbarVisibilityController.init();
mHotseatController.init();
mRecentsController.init();
- SCALE_PROPERTY.set(mTaskbarView, mLauncher.hasBeenResumed() ? getTaskbarScaleOnHome() : 1f);
+ SCALE_PROPERTY.set(mTaskbarViewInApp, mLauncher.hasBeenResumed()
+ ? getTaskbarScaleOnHome() : 1f);
+ updateWhichTaskbarViewIsVisible();
}
private TaskbarStateHandlerCallbacks createTaskbarStateHandlerCallbacks() {
@@ -274,7 +295,8 @@
mAnimator.end();
}
- mTaskbarView.cleanup();
+ mTaskbarViewInApp.cleanup();
+ mTaskbarViewOnHome.cleanup();
mTaskbarContainerView.cleanup();
removeFromWindowManager();
mTaskbarStateHandler.setTaskbarCallbacks(null);
@@ -313,7 +335,7 @@
TaskbarContainerView.LayoutParams taskbarLayoutParams =
new TaskbarContainerView.LayoutParams(mTaskbarSize.x, mTaskbarSize.y);
taskbarLayoutParams.gravity = gravity;
- mTaskbarView.setLayoutParams(taskbarLayoutParams);
+ mTaskbarViewInApp.setLayoutParams(taskbarLayoutParams);
mWindowManager.addView(mTaskbarContainerView, mWindowLayoutParams);
}
@@ -330,7 +352,6 @@
mAnimator = createAnimToLauncher(null, duration);
} else {
mAnimator = createAnimToApp(duration);
- replaceTaskbarWithHotseatOrViceVersa();
}
mAnimator.addListener(new AnimatorListenerAdapter() {
@Override
@@ -351,36 +372,41 @@
if (toState != null) {
mTaskbarStateHandler.setStateWithAnimation(toState, new StateAnimationConfig(), anim);
}
- anim.addFloat(mTaskbarView, SCALE_PROPERTY, mTaskbarView.getScaleX(),
+ anim.addFloat(mTaskbarViewInApp, SCALE_PROPERTY, mTaskbarViewInApp.getScaleX(),
getTaskbarScaleOnHome(), LINEAR);
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
mIsAnimatingToLauncher = true;
- mTaskbarView.updateHotseatItemsVisibility();
+ mTaskbarViewInApp.updateHotseatItemsVisibility();
}
@Override
public void onAnimationEnd(Animator animation) {
mIsAnimatingToLauncher = false;
+ updateWhichTaskbarViewIsVisible();
}
});
- anim.addOnFrameCallback(this::alignRealHotseatWithTaskbar);
-
return anim.buildAnim();
}
private Animator createAnimToApp(long duration) {
PendingAnimation anim = new PendingAnimation(duration);
anim.add(mTaskbarVisibilityController.createAnimToBackgroundAlpha(1, duration));
- anim.addFloat(mTaskbarView, SCALE_PROPERTY, mTaskbarView.getScaleX(), 1f, LINEAR);
+ anim.addFloat(mTaskbarViewInApp, SCALE_PROPERTY, mTaskbarViewInApp.getScaleX(), 1f, LINEAR);
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
- mTaskbarView.updateHotseatItemsVisibility();
- setReplaceTaskbarWithHotseat(false);
+ mIsAnimatingToApp = true;
+ mTaskbarViewInApp.updateHotseatItemsVisibility();
+ updateWhichTaskbarViewIsVisible();
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mIsAnimatingToApp = false;
}
});
return anim.buildAnim();
@@ -405,11 +431,11 @@
* @return Whether any Taskbar item could handle the given MotionEvent if given the chance.
*/
public boolean isEventOverAnyTaskbarItem(MotionEvent ev) {
- return mTaskbarView.isEventOverAnyItem(ev);
+ return mTaskbarViewInApp.isEventOverAnyItem(ev);
}
public boolean isDraggingItem() {
- return mTaskbarView.isDraggingItem();
+ return mTaskbarViewInApp.isDraggingItem() || mTaskbarViewOnHome.isDraggingItem();
}
private void dedupeAndUpdateRecentItems() {
@@ -454,7 +480,8 @@
tasksArray[tasksArray.length - 1 - i] = task;
}
- mTaskbarView.updateRecentTasks(tasksArray);
+ mTaskbarViewInApp.updateRecentTasks(tasksArray);
+ mTaskbarViewOnHome.updateRecentTasks(tasksArray);
mRecentsController.loadIconsForTasks(tasksArray);
}
@@ -475,10 +502,11 @@
int hotseatHeight = grid.workspacePadding.bottom + grid.taskbarSize;
int hotseatTopDiff = hotseatHeight - grid.taskbarSize;
- mTaskbarView.getHotseatBoundsAtScale(getTaskbarScaleOnHome()).roundOut(hotseatBounds);
- mLauncher.getHotseat().setPadding(hotseatBounds.left, hotseatBounds.top + hotseatTopDiff,
- mTaskbarView.getWidth() - hotseatBounds.right,
- mTaskbarView.getHeight() - hotseatBounds.bottom);
+ mTaskbarViewOnHome.getHotseatBounds().roundOut(hotseatBounds);
+ mLauncher.getHotseat().setPadding(hotseatBounds.left,
+ hotseatBounds.top + hotseatTopDiff,
+ mTaskbarViewOnHome.getWidth() - hotseatBounds.right,
+ mTaskbarViewOnHome.getHeight() - hotseatBounds.bottom);
}
/**
@@ -486,36 +514,32 @@
* show the real one instead.
*/
public void onLauncherDragLayerHierarchyChanged() {
- replaceTaskbarWithHotseatOrViceVersa();
+ // TODO: remove, as this is a no-op now
}
- private void replaceTaskbarWithHotseatOrViceVersa() {
- boolean replaceTaskbarWithHotseat = AbstractFloatingView.getTopOpenViewWithType(mLauncher,
- TYPE_REPLACE_TASKBAR_WITH_HOTSEAT) != null;
- if (!mLauncher.hasBeenResumed()) {
- replaceTaskbarWithHotseat = false;
- }
- setReplaceTaskbarWithHotseat(replaceTaskbarWithHotseat);
-
- boolean hideTaskbar = AbstractFloatingView.getTopOpenViewWithType(mLauncher,
- TYPE_HIDE_TASKBAR) != null;
- mTaskbarVisibilityController.animateToVisibilityForFloatingView(hideTaskbar ? 0f : 1f);
- }
-
- private void setReplaceTaskbarWithHotseat(boolean replaceTaskbarWithHotseat) {
- Hotseat hotseat = mLauncher.getHotseat();
- if (replaceTaskbarWithHotseat) {
- alignRealHotseatWithTaskbar();
- hotseat.getReplaceTaskbarAlpha().setValue(1f);
- mTaskbarView.setHotseatViewsHidden(true);
+ private void updateWhichTaskbarViewIsVisible() {
+ boolean isInApp = !mLauncher.hasBeenResumed() || mIsAnimatingToLauncher
+ || mIsAnimatingToApp;
+ if (isInApp) {
+ mTaskbarViewInApp.setVisibility(View.VISIBLE);
+ mTaskbarViewOnHome.setVisibility(View.INVISIBLE);
+ mLauncher.getHotseat().setIconsAlpha(0);
} else {
- hotseat.getReplaceTaskbarAlpha().setValue(0f);
- mTaskbarView.setHotseatViewsHidden(false);
+ mTaskbarViewInApp.setVisibility(View.INVISIBLE);
+ mTaskbarViewOnHome.setVisibility(View.VISIBLE);
+ mLauncher.getHotseat().setIconsAlpha(1);
}
}
- private float getTaskbarScaleOnHome() {
- return 1f / mTaskbarContainerView.getTaskbarActivityContext().getTaskbarIconScale();
+ /**
+ * Returns the ratio of the taskbar icon size on home vs in an app.
+ */
+ public float getTaskbarScaleOnHome() {
+ DeviceProfile inAppDp = mTaskbarContainerView.getTaskbarActivityContext()
+ .getDeviceProfile();
+ DeviceProfile onHomeDp = ActivityContext.lookupContext(mTaskbarViewOnHome.getContext())
+ .getDeviceProfile();
+ return (float) onHomeDp.cellWidthPx / inAppDp.cellWidthPx;
}
/**
@@ -561,7 +585,10 @@
protected interface TaskbarViewCallbacks {
View.OnClickListener getItemOnClickListener();
View.OnLongClickListener getItemOnLongClickListener();
- int getEmptyHotseatViewVisibility();
+ int getEmptyHotseatViewVisibility(TaskbarView taskbarView);
+ /** Returns how much to scale non-icon elements such as spacing and dividers. */
+ float getNonIconScale(TaskbarView taskbarView);
+ void onItemPositionsChanged(TaskbarView taskbarView);
}
/**
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index 1d762e9..3567c17 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -15,11 +15,14 @@
*/
package com.android.launcher3.taskbar;
+import android.animation.Animator;
+import android.animation.AnimatorSet;
import android.animation.LayoutTransition;
+import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
-import android.graphics.Matrix;
+import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
@@ -36,6 +39,7 @@
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.Insettable;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.folder.FolderIcon;
@@ -48,20 +52,23 @@
/**
* Hosts the Taskbar content such as Hotseat and Recent Apps. Drawn on top of other apps.
*/
-public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconParent {
+public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconParent, Insettable {
private final ColorDrawable mBackgroundDrawable;
- private final int mItemMarginLeftRight;
+ private final int mDividerWidth;
+ private final int mDividerHeight;
private final int mIconTouchSize;
private final boolean mIsRtl;
private final int mTouchSlop;
private final RectF mTempDelegateBounds = new RectF();
private final RectF mDelegateSlopBounds = new RectF();
private final int[] mTempOutLocation = new int[2];
- private final Matrix mTempMatrix = new Matrix();
// Initialized in TaskbarController constructor.
private TaskbarController.TaskbarViewCallbacks mControllerCallbacks;
+ // Scale on elements that aren't icons.
+ private float mNonIconScale;
+ private int mItemMarginLeftRight;
// Initialized in init().
private LayoutTransition mLayoutTransition;
@@ -78,7 +85,6 @@
private boolean mIsDraggingItem;
// Only non-null when the corresponding Folder is open.
private @Nullable FolderIcon mLeaveBehindFolderIcon;
- private boolean mIsHotseatHidden;
public TaskbarView(@NonNull Context context) {
this(context, null);
@@ -99,7 +105,8 @@
Resources resources = getResources();
mBackgroundDrawable = (ColorDrawable) getBackground();
- mItemMarginLeftRight = resources.getDimensionPixelSize(R.dimen.taskbar_icon_spacing);
+ mDividerWidth = resources.getDimensionPixelSize(R.dimen.taskbar_divider_thickness);
+ mDividerHeight = resources.getDimensionPixelSize(R.dimen.taskbar_divider_height);
mIconTouchSize = resources.getDimensionPixelSize(R.dimen.taskbar_icon_touch_size);
mIsRtl = Utilities.isRtl(resources);
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
@@ -107,11 +114,16 @@
protected void construct(TaskbarController.TaskbarViewCallbacks taskbarViewCallbacks) {
mControllerCallbacks = taskbarViewCallbacks;
+ mNonIconScale = mControllerCallbacks.getNonIconScale(this);
+ mItemMarginLeftRight = getResources().getDimensionPixelSize(R.dimen.taskbar_icon_spacing);
+ mItemMarginLeftRight = Math.round(mItemMarginLeftRight * mNonIconScale);
}
protected void init(int numHotseatIcons, int numRecentIcons) {
mLayoutTransition = new LayoutTransition();
- setLayoutTransitionsEnabled(true);
+ addUpdateListenerForAllLayoutTransitions(
+ () -> mControllerCallbacks.onItemPositionsChanged(this));
+ setLayoutTransition(mLayoutTransition);
mHotseatStartIndex = 0;
mHotseatEndIndex = mHotseatStartIndex + numHotseatIcons - 1;
@@ -125,12 +137,30 @@
updateRecentTasks(new Task[numRecentIcons]);
}
- private void setLayoutTransitionsEnabled(boolean enabled) {
- setLayoutTransition(enabled ? mLayoutTransition : null);
+ private void addUpdateListenerForAllLayoutTransitions(Runnable onUpdate) {
+ addUpdateListenerForLayoutTransition(LayoutTransition.CHANGE_APPEARING, onUpdate);
+ addUpdateListenerForLayoutTransition(LayoutTransition.CHANGE_DISAPPEARING, onUpdate);
+ addUpdateListenerForLayoutTransition(LayoutTransition.CHANGING, onUpdate);
+ addUpdateListenerForLayoutTransition(LayoutTransition.APPEARING, onUpdate);
+ addUpdateListenerForLayoutTransition(LayoutTransition.DISAPPEARING, onUpdate);
+ }
+
+ private void addUpdateListenerForLayoutTransition(int transitionType, Runnable onUpdate) {
+ Animator anim = mLayoutTransition.getAnimator(transitionType);
+ if (anim instanceof ValueAnimator) {
+ ((ValueAnimator) anim).addUpdateListener(valueAnimator -> onUpdate.run());
+ } else {
+ AnimatorSet animSet = new AnimatorSet();
+ ValueAnimator updateAnim = ValueAnimator.ofFloat(0, 1);
+ updateAnim.addUpdateListener(valueAnimator -> onUpdate.run());
+ animSet.playTogether(anim, updateAnim);
+ mLayoutTransition.setAnimator(transitionType, animSet);
+ }
}
protected void cleanup() {
removeAllViews();
+ mHotseatRecentsDivider = null;
}
/**
@@ -170,12 +200,11 @@
if (hotseatView == null || hotseatView.getSourceLayoutResId() != expectedLayoutResId
|| needsReinflate) {
removeView(hotseatView);
- TaskbarActivityContext activityContext =
- ActivityContext.lookupContext(getContext());
+ ActivityContext activityContext = ActivityContext.lookupContext(getContext());
if (isFolder) {
FolderInfo folderInfo = (FolderInfo) hotseatItemInfo;
FolderIcon folderIcon = FolderIcon.inflateFolderAndIcon(expectedLayoutResId,
- activityContext, this, folderInfo);
+ ActivityContext.lookupContext(getContext()), this, folderInfo);
folderIcon.setTextVisible(false);
hotseatView = folderIcon;
} else {
@@ -216,22 +245,12 @@
}
}
- /**
- * Hides or shows the hotseat items immediately (without layout transitions).
- */
- protected void setHotseatViewsHidden(boolean hidden) {
- mIsHotseatHidden = hidden;
- setLayoutTransitionsEnabled(false);
- updateHotseatItemsVisibility();
- setLayoutTransitionsEnabled(true);
- }
-
private void updateHotseatItemVisibility(View hotseatView) {
if (hotseatView.getTag() != null) {
- hotseatView.setVisibility(mIsHotseatHidden ? INVISIBLE : VISIBLE);
+ hotseatView.setVisibility(VISIBLE);
} else {
int oldVisibility = hotseatView.getVisibility();
- int newVisibility = mControllerCallbacks.getEmptyHotseatViewVisibility();
+ int newVisibility = mControllerCallbacks.getEmptyHotseatViewVisibility(this);
hotseatView.setVisibility(newVisibility);
if (oldVisibility == GONE && newVisibility != GONE) {
// By default, the layout transition only runs when going to VISIBLE,
@@ -243,7 +262,11 @@
private View addDivider(int dividerIndex) {
View divider = inflate(R.layout.taskbar_divider);
- addView(divider, dividerIndex);
+ LayoutParams lp = new LayoutParams(mDividerWidth, mDividerHeight);
+ lp.setMargins(mItemMarginLeftRight, 0, mItemMarginLeftRight, 0);
+ divider.setScaleX(mNonIconScale);
+ divider.setScaleY(mNonIconScale);
+ addView(divider, dividerIndex, lp);
return divider;
}
@@ -437,9 +460,9 @@
}
/**
- * @return The bounding box of where the hotseat elements will be when we reach the given scale.
+ * @return The bounding box of where the hotseat elements are relative to this TaskbarView.
*/
- protected RectF getHotseatBoundsAtScale(float taskbarViewScale) {
+ protected RectF getHotseatBounds() {
View firstHotseatView = null, lastHotseatView = null;
for (int i = mHotseatStartIndex; i <= mHotseatEndIndex; i++) {
View child = getChildAt(i);
@@ -455,14 +478,11 @@
}
View leftmostHotseatView = !mIsRtl ? firstHotseatView : lastHotseatView;
View rightmostHotseatView = !mIsRtl ? lastHotseatView : firstHotseatView;
- RectF hotseatBounds = new RectF(
+ return new RectF(
leftmostHotseatView.getLeft() - mItemMarginLeftRight,
leftmostHotseatView.getTop(),
rightmostHotseatView.getRight() + mItemMarginLeftRight,
rightmostHotseatView.getBottom());
- mTempMatrix.setScale(taskbarViewScale, taskbarViewScale, getPivotX(), getPivotY());
- mTempMatrix.mapRect(hotseatBounds);
- return hotseatBounds;
}
// FolderIconParent implemented methods.
@@ -493,7 +513,12 @@
}
private View inflate(@LayoutRes int layoutResId) {
- TaskbarActivityContext taskbarActivityContext = ActivityContext.lookupContext(getContext());
- return taskbarActivityContext.getLayoutInflater().inflate(layoutResId, this, false);
+ return ActivityContext.lookupContext(getContext()).getLayoutInflater()
+ .inflate(layoutResId, this, false);
+ }
+
+ @Override
+ public void setInsets(Rect insets) {
+ // Ignore, we just implement Insettable to draw behind system insets.
}
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java b/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
index fb58bf6..aa770d2 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
@@ -82,20 +82,6 @@
}
@Override
- public ScaleAndTranslation getHotseatScaleAndTranslation(Launcher launcher) {
- if ((getVisibleElements(launcher) & HOTSEAT_ICONS) != 0) {
- // Translate hotseat offscreen if we show it in overview.
- RecentsView recentsView = launcher.getOverviewPanel();
- ScaleAndTranslation scaleAndTranslation = super.getHotseatScaleAndTranslation(launcher);
- scaleAndTranslation.translationY += LayoutUtils.getShelfTrackingDistance(launcher,
- launcher.getDeviceProfile(),
- recentsView.getPagedOrientationHandler());
- return scaleAndTranslation;
- }
- return super.getHotseatScaleAndTranslation(launcher);
- }
-
- @Override
protected float getDepthUnchecked(Context context) {
return 1f;
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
index 5a28cfd..d8a5f9b 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
@@ -78,40 +78,11 @@
}
@Override
- public ScaleAndTranslation getHotseatScaleAndTranslation(Launcher launcher) {
- if ((getVisibleElements(launcher) & HOTSEAT_ICONS) != 0) {
- DeviceProfile dp = launcher.getDeviceProfile();
- if (dp.allAppsIconSizePx >= dp.iconSizePx) {
- return new ScaleAndTranslation(1, 0, 0);
- } else {
- float scale = ((float) dp.allAppsIconSizePx) / dp.iconSizePx;
- // Distance between the screen center (which is the pivotY for hotseat) and the
- // bottom of the hotseat (which we want to preserve)
- float distanceFromBottom = dp.heightPx / 2 - dp.hotseatBarBottomPaddingPx;
- // On scaling, the bottom edge is moved closer to the pivotY. We move the
- // hotseat back down so that the bottom edge's position is preserved.
- float translationY = distanceFromBottom * (1 - scale);
- return new ScaleAndTranslation(scale, 0, translationY);
- }
- }
- return getWorkspaceScaleAndTranslation(launcher);
- }
-
- @Override
public float[] getOverviewScaleAndOffset(Launcher launcher) {
return new float[] {NO_SCALE, NO_OFFSET};
}
@Override
- public ScaleAndTranslation getQsbScaleAndTranslation(Launcher launcher) {
- if (this == OVERVIEW) {
- // Treat the QSB as part of the hotseat so they move together.
- return getHotseatScaleAndTranslation(launcher);
- }
- return super.getQsbScaleAndTranslation(launcher);
- }
-
- @Override
public PageAlphaProvider getWorkspacePageAlphaProvider(Launcher launcher) {
return new PageAlphaProvider(DEACCEL_2) {
@Override
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 6da2201..b492825 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -617,7 +617,7 @@
final boolean passed = mCurrentShift.value >= MIN_PROGRESS_FOR_OVERVIEW;
if (passed != mPassedOverviewThreshold) {
mPassedOverviewThreshold = passed;
- if (!mDeviceState.isTwoButtonNavMode()) {
+ if (mDeviceState.isTwoButtonNavMode()) {
performHapticFeedback();
}
}
@@ -1334,7 +1334,11 @@
}
private void invalidateHandler() {
- mInputConsumerProxy.destroy();
+ if (!LIVE_TILE.get() || !mActivityInterface.isInLiveTileMode()
+ || mGestureState.getEndTarget() != RECENTS) {
+ mInputConsumerProxy.destroy();
+ mTaskAnimationManager.setLiveTileCleanUpHandler(null);
+ }
endRunningWindowAnim(false /* cancel */);
if (mGestureEndCallback != null) {
@@ -1526,6 +1530,7 @@
apps[apps.length - 1] = appearedTaskTarget;
launchOtherTaskInLiveTileMode(appearedTaskTarget.taskId, apps);
});
+ mTaskAnimationManager.setLiveTileCleanUpHandler(mInputConsumerProxy::destroy);
ActivityManagerWrapper.getInstance().registerTaskStackListener(
mLiveTileRestartListener);
}
diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
index 02c2763..9a454f2 100644
--- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java
+++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
@@ -50,6 +50,7 @@
private GestureState mLastGestureState;
private RemoteAnimationTargetCompat mLastAppearedTaskTarget;
private Consumer<RemoteAnimationTargetCompat> mLaunchOtherTaskHandler;
+ private Runnable mLiveTileCleanUpHandler;
private Context mCtx;
TaskAnimationManager(Context ctx) {
@@ -169,6 +170,10 @@
mLaunchOtherTaskHandler = handler;
}
+ public void setLiveTileCleanUpHandler(Runnable runnable) {
+ mLiveTileCleanUpHandler = runnable;
+ }
+
/**
* Finishes the running recents animation.
*/
@@ -206,6 +211,11 @@
* Cleans up the recents animation entirely.
*/
private void cleanUpRecentsAnimation() {
+ if (mLiveTileCleanUpHandler != null) {
+ mLiveTileCleanUpHandler.run();
+ mLiveTileCleanUpHandler = null;
+ }
+
// Release all the target leashes
if (mTargets != null) {
mTargets.release();
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 4747f18..1fb9465 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -887,6 +887,9 @@
if (mGestureState != null) {
mGestureState.dump(pw);
}
+ pw.println("Input state:");
+ pw.println(" mInputMonitorCompat=" + mInputMonitorCompat);
+ pw.println(" mInputEventReceiver=" + mInputEventReceiver);
SysUINavigationMode.INSTANCE.get(this).dump(pw);
pw.println("TouchState:");
BaseDraggingActivity createdOverviewActivity = mOverviewComponentObserver == null ? null
diff --git a/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java b/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
index ae644cd..3faf72a 100644
--- a/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
+++ b/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
@@ -112,20 +112,32 @@
}
// Set up springs for the hotseat and qsb.
- ViewGroup hotseatChild = (ViewGroup) hotseat.getChildAt(0);
+ ViewGroup hotseatIcons = hotseat.getShortcutsAndWidgets();
if (grid.isVerticalBarLayout()) {
- for (int i = hotseatChild.getChildCount() - 1; i >= 0; i--) {
- View child = hotseatChild.getChildAt(i);
+ for (int i = hotseatIcons.getChildCount() - 1; i >= 0; i--) {
+ View child = hotseatIcons.getChildAt(i);
CellLayout.LayoutParams lp = ((CellLayout.LayoutParams) child.getLayoutParams());
addStaggeredAnimationForView(child, lp.cellY + 1, totalRows);
}
} else {
- for (int i = hotseatChild.getChildCount() - 1; i >= 0; i--) {
- View child = hotseatChild.getChildAt(i);
- addStaggeredAnimationForView(child, grid.inv.numRows + 1, totalRows);
+ final int hotseatRow, qsbRow, taskbarRow;
+ if (grid.isTaskbarPresent) {
+ qsbRow = grid.inv.numRows + 1;
+ hotseatRow = grid.inv.numRows + 2;
+ } else {
+ hotseatRow = grid.inv.numRows + 1;
+ qsbRow = grid.inv.numRows + 2;
+ }
+ // Taskbar and hotseat overlap.
+ taskbarRow = hotseatRow;
+
+ for (int i = hotseatIcons.getChildCount() - 1; i >= 0; i--) {
+ View child = hotseatIcons.getChildAt(i);
+ addStaggeredAnimationForView(child, hotseatRow, totalRows);
}
- addStaggeredAnimationForView(hotseat.getQsb(), grid.inv.numRows + 2, totalRows);
+ addStaggeredAnimationForView(hotseat.getQsb(), qsbRow, totalRows);
+ addStaggeredAnimationForView(hotseat.getTaskbarView(), taskbarRow, totalRows);
}
if (animateOverviewScrim) {
diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
index e042b35..a0af68a 100644
--- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -101,7 +101,7 @@
@Override
protected void onTaskLaunchAnimationEnd(boolean success) {
if (success) {
- mActivity.getStateManager().goToState(NORMAL, false /* animate */);
+ mActivity.getStateManager().moveToRestState();
} else {
LauncherState state = mActivity.getStateManager().getState();
mActivity.getAllAppsController().setState(state);
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 7adfc1c..f216985 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -1018,6 +1018,7 @@
mLiveTileTaskViewSimulator.taskSecondaryTranslation.value = 0;
mLiveTileTaskViewSimulator.fullScreenProgress.value = 0;
mLiveTileTaskViewSimulator.recentsViewScale.value = 1;
+ mLiveTileTaskViewSimulator.gridProgress.value = 0;
}
if (mRunningTaskTileHidden) {
setRunningTaskHidden(mRunningTaskTileHidden);
@@ -1740,6 +1741,7 @@
for (int i = 0; i < taskCount; i++) {
getTaskViewAt(i).setGridProgress(gridProgress);
}
+ mLiveTileTaskViewSimulator.gridProgress.value = gridProgress;
mClearAllButton.setGridProgress(gridProgress);
}
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index 809adcb..2b7e6fd 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -298,7 +298,6 @@
private boolean mEndQuickswitchCuj;
private View mContextualChipWrapper;
- private View mContextualChip;
private final float[] mIconCenterCoords = new float[2];
private final float[] mChipCenterCoords = new float[2];
@@ -447,9 +446,9 @@
}
mModalness = modalness;
mIconView.setAlpha(comp(modalness));
- if (mContextualChip != null) {
- mContextualChip.setScaleX(comp(modalness));
- mContextualChip.setScaleY(comp(modalness));
+ if (mContextualChipWrapper != null) {
+ mContextualChipWrapper.setScaleX(comp(modalness));
+ mContextualChipWrapper.setScaleY(comp(modalness));
}
mDigitalWellBeingToast.updateBannerOffset(modalness,
mCurrentFullscreenParams.mCurrentDrawnInsets.top
@@ -689,10 +688,10 @@
.getInterpolation(progress);
mIconView.setScaleX(scale);
mIconView.setScaleY(scale);
- if (mContextualChip != null && mContextualChipWrapper != null) {
+ if (mContextualChipWrapper != null && mContextualChipWrapper != null) {
mContextualChipWrapper.setAlpha(scale);
- mContextualChip.setScaleX(scale);
- mContextualChip.setScaleY(scale);
+ mContextualChipWrapper.setScaleX(Math.min(scale, comp(mModalness)));
+ mContextualChipWrapper.setScaleY(Math.min(scale, comp(mModalness)));
}
mDigitalWellBeingToast.updateBannerOffset(1f - scale,
mCurrentFullscreenParams.mCurrentDrawnInsets.top
@@ -797,14 +796,12 @@
int expectedChipHeight = getExpectedViewHeight(view);
float chipOffset = getResources().getDimension(R.dimen.chip_hint_vertical_offset);
layoutParams.bottomMargin = -expectedChipHeight - (int) chipOffset;
- mContextualChip = ((FrameLayout) mContextualChipWrapper).getChildAt(0);
- mContextualChip.setScaleX(0f);
- mContextualChip.setScaleY(0f);
+ mContextualChipWrapper.setScaleX(0f);
+ mContextualChipWrapper.setScaleY(0f);
addView(view, getChildCount(), layoutParams);
- if (mContextualChip != null) {
- mContextualChip.animate().scaleX(1f).scaleY(1f).setDuration(50);
- }
if (mContextualChipWrapper != null) {
+ float scale = comp(mModalness);
+ mContextualChipWrapper.animate().scaleX(scale).scaleY(scale).setDuration(50);
mChipTouchDelegate = new TransformingTouchDelegate(mContextualChipWrapper);
}
}
@@ -825,7 +822,6 @@
}
View oldContextualChipWrapper = mContextualChipWrapper;
mContextualChipWrapper = null;
- mContextualChip = null;
mChipTouchDelegate = null;
return oldContextualChipWrapper;
}
diff --git a/res/drawable/add_item_dialog_background.xml b/res/drawable/add_item_dialog_background.xml
new file mode 100644
index 0000000..04bde8f
--- /dev/null
+++ b/res/drawable/add_item_dialog_background.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle" >
+ <solid android:color="?android:attr/colorBackground" />
+ <corners
+ android:topLeftRadius="?android:attr/dialogCornerRadius"
+ android:topRightRadius="?android:attr/dialogCornerRadius" />
+</shape>
\ No newline at end of file
diff --git a/res/drawable/add_item_dialog_button_background.xml b/res/drawable/add_item_dialog_button_background.xml
new file mode 100644
index 0000000..1b4591f
--- /dev/null
+++ b/res/drawable/add_item_dialog_button_background.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<inset
+ android:insetLeft="@dimen/pin_widget_button_inset_horizontal"
+ android:insetRight="@dimen/pin_widget_button_inset_horizontal"
+ android:insetTop="@dimen/pin_widget_button_inset_vertical"
+ android:insetBottom="@dimen/pin_widget_button_inset_vertical"
+ xmlns:android="http://schemas.android.com/apk/res/android">
+ <ripple
+ android:color="?android:attr/colorControlHighlight">
+ <item>
+ <shape android:tint="?android:attr/colorAccent" android:shape="rectangle">
+ <corners android:radius="18dp" />
+ <solid android:color="#FFFFFF" />
+ <padding
+ android:left="@dimen/pin_widget_button_padding_horizontal"
+ android:top="@dimen/pin_widget_button_padding_vertical"
+ android:right="@dimen/pin_widget_button_padding_horizontal"
+ android:bottom="@dimen/pin_widget_button_padding_vertical" />
+ </shape>
+ </item>
+ </ripple>
+</inset>
\ No newline at end of file
diff --git a/res/drawable/middle_item_primary.xml b/res/drawable/middle_item_primary.xml
index c975714..0c04ea1 100644
--- a/res/drawable/middle_item_primary.xml
+++ b/res/drawable/middle_item_primary.xml
@@ -16,5 +16,5 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="?attr/popupColorPrimary"/>
- <corners android:radius="@dimen/popup_middle_item_radius" />
+ <corners android:radius="@dimen/popup_smaller_radius" />
</shape>
\ No newline at end of file
diff --git a/res/drawable/widgets_list_single_item_ripple.xml b/res/drawable/widgets_list_single_item_ripple.xml
new file mode 100644
index 0000000..b8b6f42
--- /dev/null
+++ b/res/drawable/widgets_list_single_item_ripple.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="?android:attr/colorControlHighlight">
+ <item android:id="@android:id/mask">
+ <shape android:shape="rectangle">
+ <corners
+ android:topLeftRadius="@dimen/widget_list_top_bottom_corner_radius"
+ android:topRightRadius="@dimen/widget_list_top_bottom_corner_radius"
+ android:bottomLeftRadius="@dimen/widget_list_top_bottom_corner_radius"
+ android:bottomRightRadius="@dimen/widget_list_top_bottom_corner_radius" />
+ </shape>
+ </item>
+ <item android:id="@android:id/background">
+ <shape android:shape="rectangle">
+ <solid android:color="?android:attr/colorBackground" />
+ <corners
+ android:topLeftRadius="@dimen/widget_list_top_bottom_corner_radius"
+ android:topRightRadius="@dimen/widget_list_top_bottom_corner_radius"
+ android:bottomLeftRadius="@dimen/widget_list_top_bottom_corner_radius"
+ android:bottomRightRadius="@dimen/widget_list_top_bottom_corner_radius" />
+ </shape>
+ </item>
+</ripple>
\ No newline at end of file
diff --git a/res/layout/add_item_confirmation_activity.xml b/res/layout/add_item_confirmation_activity.xml
index b1a1efe..d5e7333 100644
--- a/res/layout/add_item_confirmation_activity.xml
+++ b/res/layout/add_item_confirmation_activity.xml
@@ -17,70 +17,51 @@
*/
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/add_item_confirmation"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:padding="24dp"
android:orientation="vertical">
- <ScrollView
+
+ <TextView
+ style="@style/TextHeadline"
+ android:id="@+id/widget_appName"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_horizontal"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textSize="24sp"
+ android:ellipsize="end"
+ android:fadingEdge="horizontal"
+ android:singleLine="true"
+ android:maxLines="1" />
+
+ <include layout="@layout/widget_cell"
+ android:id="@+id/widget_cell"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
- android:clipToPadding="false">
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
-
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingBottom="20dp"
- android:paddingLeft="24dp"
- android:paddingRight="24dp"
- android:paddingTop="4dp"
- android:text="@string/add_item_request_drag_hint" />
-
- <FrameLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:background="?android:attr/colorPrimaryDark"
- android:theme="?attr/widgetsTheme">
-
- <com.android.launcher3.widget.WidgetCell
- android:id="@+id/widget_cell"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal"
- android:layout_weight="1"
- android:background="?android:attr/colorPrimaryDark"
- android:focusable="true"
- android:gravity="center_horizontal"
- android:orientation="vertical" >
-
- <include layout="@layout/widget_cell_content" />
-
- </com.android.launcher3.widget.WidgetCell>
- </FrameLayout>
- </LinearLayout>
- </ScrollView>
+ android:layout_marginVertical="16dp" />
<LinearLayout
- style="?android:attr/buttonBarStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="end"
- android:paddingBottom="4dp"
- android:paddingEnd="12dp"
- android:paddingStart="12dp"
- android:paddingTop="4dp" >
+ android:padding="8dp"
+ android:orientation="horizontal">
<Button
- style="?android:attr/buttonBarButtonStyle"
+ style="@style/Widget.DeviceDefault.Button.Rounded.Colored"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="onCancelClick"
android:text="@android:string/cancel" />
+
+ <Space
+ android:layout_width="4dp"
+ android:layout_height="wrap_content" />
+
<Button
- style="?android:attr/buttonBarButtonStyle"
+ style="@style/Widget.DeviceDefault.Button.Rounded.Colored"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="onPlaceAutomaticallyClick"
diff --git a/res/layout/app_widget_resize_frame.xml b/res/layout/app_widget_resize_frame.xml
index 2e476df..671dbc6 100644
--- a/res/layout/app_widget_resize_frame.xml
+++ b/res/layout/app_widget_resize_frame.xml
@@ -26,6 +26,7 @@
<!-- Frame -->
<ImageView
+ android:id="@+id/widget_resize_frame"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
diff --git a/res/layout/deep_shortcut.xml b/res/layout/deep_shortcut.xml
index d6b4a37..0d11b50 100644
--- a/res/layout/deep_shortcut.xml
+++ b/res/layout/deep_shortcut.xml
@@ -32,6 +32,8 @@
android:paddingEnd="@dimen/popup_padding_end"
android:drawableEnd="@drawable/ic_drag_handle"
android:drawablePadding="@dimen/deep_shortcut_drawable_padding"
+ android:singleLine="true"
+ android:ellipsize="end"
android:textSize="14sp"
android:textColor="?android:attr/textColorPrimary"
launcher:layoutHorizontal="true"
diff --git a/res/layout/system_shortcut.xml b/res/layout/system_shortcut.xml
index 68251e4..9f45f30 100644
--- a/res/layout/system_shortcut.xml
+++ b/res/layout/system_shortcut.xml
@@ -31,7 +31,8 @@
android:paddingStart="@dimen/deep_shortcuts_text_padding_start"
android:paddingEnd="@dimen/popup_padding_end"
android:textSize="14sp"
- android:maxLines="1"
+ android:singleLine="true"
+ android:ellipsize="end"
android:textColor="?android:attr/textColorPrimary"
launcher:iconDisplay="shortcut_popup"
launcher:layoutHorizontal="true"
diff --git a/res/layout/taskbar_view.xml b/res/layout/taskbar_view.xml
new file mode 100644
index 0000000..96ae43d
--- /dev/null
+++ b/res/layout/taskbar_view.xml
@@ -0,0 +1,21 @@
+<?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.
+-->
+<Space
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:visibility="gone" />
\ No newline at end of file
diff --git a/res/layout/widget_cell_content.xml b/res/layout/widget_cell_content.xml
index 7b85d9b..30bd8b1 100644
--- a/res/layout/widget_cell_content.xml
+++ b/res/layout/widget_cell_content.xml
@@ -18,10 +18,11 @@
android:layout_height="wrap_content">
<!-- The image of the widget. This view does not support padding. Any placement adjustment
- should be done using margins. -->
+ should be done using margins. Width & height are set at runtime after scaling the preview
+ image. -->
<com.android.launcher3.widget.WidgetImageView
android:id="@+id/widget_preview"
- android:layout_width="wrap_content"
+ android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1"
android:importantForAccessibility="no"
@@ -38,28 +39,28 @@
android:singleLine="true"
android:maxLines="1"
android:textColor="?android:attr/textColorPrimary"
- android:textSize="14sp" />
+ android:textSize="@dimen/widget_cell_font_size" />
- <!-- The original dimensions of the widget (can't be the same text as above due to different
- style. -->
+ <!-- The original dimensions of the widget -->
<TextView
android:id="@+id/widget_dims"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
- android:textColor="?android:attr/textColorTertiary"
- android:textSize="14sp"
- android:alpha="0.8" />
+ android:textColor="?android:attr/textColorSecondary"
+ android:textSize="@dimen/widget_cell_font_size"
+ android:alpha="0.7" />
<TextView
android:id="@+id/widget_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
- android:textSize="14sp"
- android:textColor="?android:attr/textColorTertiary"
+ android:textSize="@dimen/widget_cell_font_size"
+ android:textColor="?android:attr/textColorSecondary"
android:maxLines="2"
android:ellipsize="end"
- android:fadingEdge="horizontal" />
+ android:fadingEdge="horizontal"
+ android:alpha="0.7" />
</merge>
\ No newline at end of file
diff --git a/res/layout/widgets_bottom_sheet.xml b/res/layout/widgets_bottom_sheet.xml
index d18ba56..8002d1d 100644
--- a/res/layout/widgets_bottom_sheet.xml
+++ b/res/layout/widgets_bottom_sheet.xml
@@ -24,41 +24,7 @@
android:elevation="@dimen/deep_shortcuts_elevation"
android:layout_gravity="bottom"
android:theme="?attr/widgetsTheme">
- <View
- android:layout_width="48dp"
- android:layout_height="2dp"
- android:layout_gravity="center_horizontal"
- android:layout_marginBottom="16dp"
- android:background="?android:attr/textColorSecondary"/>
- <TextView
- style="@style/TextHeadline"
- android:id="@+id/title"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center_horizontal"
- android:textColor="?android:attr/textColorPrimary"
- android:textSize="24sp"/>
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center_horizontal"
- android:paddingTop="4dp"
- android:fontFamily="sans-serif"
- android:textColor="?android:attr/textColorTertiary"
- android:textSize="14sp"
- android:text="@string/long_press_widget_to_add"/>
-
- <ScrollView
- android:id="@+id/widgets_table_scroll_view"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:fadeScrollbars="false"
- android:layout_marginVertical="16dp">
- <include layout="@layout/widgets_table_container"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal" />
- </ScrollView>
+ <include layout="@layout/widgets_bottom_sheet_content" />
</com.android.launcher3.widget.WidgetsBottomSheet>
\ No newline at end of file
diff --git a/res/layout/widgets_bottom_sheet_content.xml b/res/layout/widgets_bottom_sheet_content.xml
new file mode 100644
index 0000000..a9d523a
--- /dev/null
+++ b/res/layout/widgets_bottom_sheet_content.xml
@@ -0,0 +1,43 @@
+<?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">
+ <View
+ android:layout_width="48dp"
+ android:layout_height="2dp"
+ android:layout_gravity="center_horizontal"
+ android:layout_marginBottom="16dp"
+ android:background="?android:attr/textColorSecondary"/>
+ <TextView
+ style="@style/TextHeadline"
+ android:id="@+id/title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_horizontal"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textSize="24sp"/>
+
+ <ScrollView
+ android:id="@+id/widgets_table_scroll_view"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:fadeScrollbars="false"
+ android:layout_marginVertical="16dp">
+ <include layout="@layout/widgets_table_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal" />
+ </ScrollView>
+</merge>
diff --git a/res/layout/widgets_full_sheet_search_and_recommendations.xml b/res/layout/widgets_full_sheet_search_and_recommendations.xml
index 1219f57..e5df175 100644
--- a/res/layout/widgets_full_sheet_search_and_recommendations.xml
+++ b/res/layout/widgets_full_sheet_search_and_recommendations.xml
@@ -18,12 +18,15 @@
android:id="@+id/search_and_recommendations_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:padding="16dp"
+ android:paddingHorizontal="16dp"
+ android:layout_marginBottom="16dp"
android:orientation="vertical">
<View
android:id="@+id/collapse_handle"
android:layout_width="48dp"
android:layout_height="2dp"
+ android:layout_marginTop="16dp"
+ android:elevation="2dp"
android:layout_gravity="center_horizontal"
android:background="?android:attr/textColorSecondary"/>
<TextView
@@ -36,4 +39,11 @@
android:textColor="?android:attr/textColorSecondary"
android:text="@string/widget_button_text"/>
<include layout="@layout/widgets_search_bar"/>
+
+ <com.android.launcher3.widget.picker.WidgetsRecommendationTableLayout
+ android:id="@+id/recommended_widget_table"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="16dp"
+ android:visibility="gone" />
</LinearLayout>
diff --git a/res/layout/widgets_list_row_header.xml b/res/layout/widgets_list_row_header.xml
index ed3a042..598041c 100644
--- a/res/layout/widgets_list_row_header.xml
+++ b/res/layout/widgets_list_row_header.xml
@@ -56,7 +56,8 @@
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
- android:textColor="?android:attr/textColorTertiary"
+ android:textColor="?android:attr/textColorSecondary"
+ android:alpha="0.7"
tools:text="m widgets, n shortcuts" />
</LinearLayout>
diff --git a/res/layout/widgets_search_bar.xml b/res/layout/widgets_search_bar.xml
index 021058b..1db7462 100644
--- a/res/layout/widgets_search_bar.xml
+++ b/res/layout/widgets_search_bar.xml
@@ -6,7 +6,8 @@
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="16dp"
- android:background="@drawable/bg_widgets_searchbox">
+ android:background="@drawable/bg_widgets_searchbox"
+ android:elevation="2dp">
<com.android.launcher3.ExtendedEditText
android:id="@+id/widgets_search_bar_edit_text"
diff --git a/res/values-night/styles.xml b/res/values-night/styles.xml
index 510e1f4..07a5096 100644
--- a/res/values-night/styles.xml
+++ b/res/values-night/styles.xml
@@ -21,6 +21,8 @@
<style name="AppItemActivityTheme" parent="@android:style/Theme.DeviceDefault.Dialog.Alert">
<item name="widgetsTheme">@style/WidgetContainerTheme.Dark</item>
+ <item name="android:windowBackground">@drawable/add_item_dialog_background</item>
+ <item name="android:windowNoTitle">true</item>
</style>
</resources>
\ No newline at end of file
diff --git a/res/values-v31/colors.xml b/res/values-v31/colors.xml
index 6baf39e..24aac10 100644
--- a/res/values-v31/colors.xml
+++ b/res/values-v31/colors.xml
@@ -17,17 +17,17 @@
*/
-->
<resources>
- <color name="popup_color_primary_light">@android:color/system_primary_50</color>
- <color name="popup_color_secondary_light">@android:color/system_primary_100</color>
- <color name="popup_color_tertiary_light">@android:color/system_primary_300</color>
- <color name="popup_color_primary_dark">@android:color/system_primary_800</color>
- <color name="popup_color_secondary_dark">@android:color/system_primary_900</color>
- <color name="popup_color_tertiary_dark">@android:color/system_primary_700</color>
+ <color name="popup_color_primary_light">@android:color/system_neutral1_50</color>
+ <color name="popup_color_secondary_light">@android:color/system_neutral2_100</color>
+ <color name="popup_color_tertiary_light">@android:color/system_neutral2_300</color>
+ <color name="popup_color_primary_dark">@android:color/system_neutral1_800</color>
+ <color name="popup_color_secondary_dark">@android:color/system_neutral1_900</color>
+ <color name="popup_color_tertiary_dark">@android:color/system_neutral2_700</color>
- <color name="workspace_text_color_light">@android:color/system_primary_50</color>
- <color name="workspace_text_color_dark">@android:color/system_primary_900</color>
+ <color name="workspace_text_color_light">@android:color/system_neutral1_50</color>
+ <color name="workspace_text_color_dark">@android:color/system_neutral1_900</color>
- <color name="text_color_primary_dark">@android:color/system_primary_50</color>
- <color name="text_color_secondary_dark">@android:color/system_primary_200</color>
- <color name="text_color_tertiary_dark">@android:color/system_primary_400</color>
+ <color name="text_color_primary_dark">@android:color/system_neutral1_50</color>
+ <color name="text_color_secondary_dark">@android:color/system_neutral2_200</color>
+ <color name="text_color_tertiary_dark">@android:color/system_neutral2_400</color>
</resources>
\ No newline at end of file
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index c607c98..cf830c7 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -109,6 +109,7 @@
<!-- Widget tray -->
<dimen name="widget_cell_vertical_padding">8dp</dimen>
<dimen name="widget_cell_horizontal_padding">16dp</dimen>
+ <dimen name="widget_cell_font_size">14sp</dimen>
<dimen name="widget_list_top_bottom_corner_radius">28dp</dimen>
@@ -137,6 +138,12 @@
<dimen name="shortcut_preview_padding_right">0dp</dimen>
<dimen name="shortcut_preview_padding_top">0dp</dimen>
+<!-- Pin widget dialog -->
+ <dimen name="pin_widget_button_padding_horizontal">8dp</dimen>
+ <dimen name="pin_widget_button_padding_vertical">4dp</dimen>
+ <dimen name="pin_widget_button_inset_horizontal">4dp</dimen>
+ <dimen name="pin_widget_button_inset_vertical">6dp</dimen>
+
<!-- Dragging -->
<!-- Drag padding to add to the bottom of drop targets -->
<dimen name="drop_target_drag_padding">14dp</dimen>
@@ -184,16 +191,15 @@
<!-- Deep shortcuts -->
<dimen name="deep_shortcuts_elevation">0dp</dimen>
- <dimen name="bg_popup_item_width">234dp</dimen>
+ <dimen name="bg_popup_item_width">216dp</dimen>
<dimen name="bg_popup_item_height">56dp</dimen>
- <dimen name="bg_popup_item_condensed_height">48dp</dimen>
<dimen name="pre_drag_view_scale">6dp</dimen>
<!-- an icon with shortcuts must be dragged this far before the container is removed. -->
<dimen name="deep_shortcuts_start_drag_threshold">16dp</dimen>
<dimen name="deep_shortcut_icon_size">32dp</dimen>
<dimen name="popup_margin">2dp</dimen>
<dimen name="popup_single_item_radius">100dp</dimen>
- <dimen name="popup_middle_item_radius">4dp</dimen>
+ <dimen name="popup_smaller_radius">4dp</dimen>
<dimen name="deep_shortcut_drawable_padding">12dp</dimen>
<dimen name="deep_shortcut_drag_handle_size">16dp</dimen>
<dimen name="popup_padding_start">10dp</dimen>
@@ -277,4 +283,7 @@
<!-- Taskbar related (placeholders to compile in Launcher3 without Quickstep) -->
<dimen name="taskbar_size">0dp</dimen>
+ <!-- Size of the maximum radius for the enforced rounded rectangles. -->
+ <dimen name="enforced_rounded_corner_max_radius">16dp</dimen>
+
</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 1eb123b..7c372830 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -269,8 +269,6 @@
<string name="app_waiting_download_title"><xliff:g id="name" example="Messenger">%1$s</xliff:g> waiting to install</string>
<!-- Strings for widgets & more in the popup container/bottom sheet -->
- <!-- Title for a bottom sheet that shows widgets for a particular app -->
- <string name="widgets_bottom_sheet_title"><xliff:g id="name" example="Messenger">%1$s</xliff:g> widgets</string>
<!-- Accessibility title for the popup containing a list of widgets. [CHAR_LIMIT=50] -->
<string name="widgets_list">Widgets list</string>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index adc2238..a27cdac 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -145,6 +145,8 @@
<style name="AppItemActivityTheme" parent="@android:style/Theme.DeviceDefault.Light.Dialog.Alert">
<item name="widgetsTheme">@style/WidgetContainerTheme</item>
+ <item name="android:windowBackground">@drawable/add_item_dialog_background</item>
+ <item name="android:windowNoTitle">true</item>
</style>
<style name="HomeSettingsTheme" parent="@android:style/Theme.DeviceDefault.Settings">
@@ -281,4 +283,8 @@
<item name="android:colorControlHighlight">#DFE1E5</item>
<item name="android:colorForeground">@color/all_apps_bg_hand_fill_dark</item>
</style>
+
+ <style name="Widget.DeviceDefault.Button.Rounded.Colored" parent="@android:style/Widget.DeviceDefault.Button.Colored">
+ <item name="android:background">@drawable/add_item_dialog_button_background</item>
+ </style>
</resources>
diff --git a/robolectric_tests/Android.bp b/robolectric_tests/Android.bp
index 50309b7..bf32362 100644
--- a/robolectric_tests/Android.bp
+++ b/robolectric_tests/Android.bp
@@ -16,6 +16,15 @@
// Launcher Robolectric test target.
//
// "robolectric_android-all-stub", not needed, we write our own stubs
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "packages_apps_Launcher3_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["packages_apps_Launcher3_license"],
+}
+
filegroup {
name: "launcher3-robolectric-resources",
path: "resources",
@@ -47,4 +56,3 @@
timeout: 36000,
},
}
-
diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java
index 8071782..ab91785 100644
--- a/src/com/android/launcher3/AppWidgetResizeFrame.java
+++ b/src/com/android/launcher3/AppWidgetResizeFrame.java
@@ -14,12 +14,15 @@
import android.content.Context;
import android.graphics.Point;
import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.GradientDrawable;
import android.os.Bundle;
import android.util.AttributeSet;
import android.util.SizeF;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
+import android.widget.ImageView;
import androidx.annotation.Nullable;
@@ -100,6 +103,8 @@
private int mRunningVInc;
private int mMinHSpan;
private int mMinVSpan;
+ private int mMaxHSpan;
+ private int mMaxVSpan;
private int mDeltaX;
private int mDeltaY;
private int mDeltaXAddOn;
@@ -164,6 +169,15 @@
DragLayer dl = launcher.getDragLayer();
AppWidgetResizeFrame frame = (AppWidgetResizeFrame) launcher.getLayoutInflater()
.inflate(R.layout.app_widget_resize_frame, dl, false);
+ if (widget.hasEnforcedCornerRadius()) {
+ float enforcedCornerRadius = widget.getEnforcedCornerRadius();
+ ImageView imageView = frame.findViewById(R.id.widget_resize_frame);
+ Drawable d = imageView.getDrawable();
+ if (d instanceof GradientDrawable) {
+ GradientDrawable gd = (GradientDrawable) d.mutate();
+ gd.setCornerRadius(enforcedCornerRadius);
+ }
+ }
frame.setupForWidget(widget, cellLayout, dl);
((DragLayer.LayoutParams) frame.getLayoutParams()).customPosition = true;
@@ -183,6 +197,8 @@
mMinHSpan = info.minSpanX;
mMinVSpan = info.minSpanY;
+ mMaxHSpan = info.maxSpanX;
+ mMaxVSpan = info.maxSpanY;
mWidgetPadding = AppWidgetHostView.getDefaultPaddingForWidget(getContext(),
widgetView.getAppWidgetInfo().provider, null);
@@ -314,7 +330,7 @@
// expandability.
mTempRange1.set(cellX, spanX + cellX);
int hSpanDelta = mTempRange1.applyDeltaAndBound(mLeftBorderActive, mRightBorderActive,
- hSpanInc, mMinHSpan, mCellLayout.getCountX(), mTempRange2);
+ hSpanInc, mMinHSpan, mMaxHSpan, mCellLayout.getCountX(), mTempRange2);
cellX = mTempRange2.start;
spanX = mTempRange2.size();
if (hSpanDelta != 0) {
@@ -323,7 +339,7 @@
mTempRange1.set(cellY, spanY + cellY);
int vSpanDelta = mTempRange1.applyDeltaAndBound(mTopBorderActive, mBottomBorderActive,
- vSpanInc, mMinVSpan, mCellLayout.getCountY(), mTempRange2);
+ vSpanInc, mMinVSpan, mMaxVSpan, mCellLayout.getCountY(), mTempRange2);
cellY = mTempRange2.start;
spanY = mTempRange2.size();
if (vSpanDelta != 0) {
@@ -642,12 +658,15 @@
* @param minSize minimum size after with the moving edge should not be shifted any further.
* For eg, if delta = -3 when moving the endEdge brings the size to less than
* minSize, only delta = -2 will applied
+ * @param maxSize maximum size after with the moving edge should not be shifted any further.
+ * For eg, if delta = -3 when moving the endEdge brings the size to greater
+ * than maxSize, only delta = -2 will applied
* @param maxEnd The maximum value to the end edge (start edge is always restricted to 0)
* @return the amount of increase when endEdge was moves and the amount of decrease when
* the start edge was moved.
*/
public int applyDeltaAndBound(boolean moveStart, boolean moveEnd, int delta,
- int minSize, int maxEnd, IntRange out) {
+ int minSize, int maxSize, int maxEnd, IntRange out) {
applyDelta(moveStart, moveEnd, delta, out);
if (out.start < 0) {
out.start = 0;
@@ -662,6 +681,13 @@
out.end = out.start + minSize;
}
}
+ if (out.size() > maxSize) {
+ if (moveStart) {
+ out.start = out.end - maxSize;
+ } else if (moveEnd) {
+ out.end = out.start + maxSize;
+ }
+ }
return moveEnd ? out.size() - size() : size() - out.size();
}
}
diff --git a/src/com/android/launcher3/ButtonDropTarget.java b/src/com/android/launcher3/ButtonDropTarget.java
index 459b9a8..4740079 100644
--- a/src/com/android/launcher3/ButtonDropTarget.java
+++ b/src/com/android/launcher3/ButtonDropTarget.java
@@ -21,14 +21,9 @@
import static com.android.launcher3.LauncherState.NORMAL;
import android.animation.AnimatorSet;
-import android.animation.FloatArrayEvaluator;
-import android.animation.ObjectAnimator;
-import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Resources;
-import android.graphics.ColorMatrix;
-import android.graphics.ColorMatrixColorFilter;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.text.TextUtils;
@@ -45,10 +40,7 @@
import com.android.launcher3.dragndrop.DragController;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.dragndrop.DragOptions;
-import com.android.launcher3.dragndrop.DragView;
import com.android.launcher3.model.data.ItemInfo;
-import com.android.launcher3.util.Themes;
-import com.android.launcher3.util.Thunk;
/**
* Implements a DropTarget.
@@ -72,6 +64,7 @@
private static final int[] sTempCords = new int[2];
private static final int DRAG_VIEW_DROP_DURATION = 285;
+ private static final float DRAG_VIEW_HOVER_OVER_OPACITY = 0.65f;
public static final int TOOLTIP_DEFAULT = 0;
public static final int TOOLTIP_LEFT = 1;
@@ -89,9 +82,6 @@
/** An item must be dragged at least this many pixels before this drop target is enabled. */
private final int mDragDistanceThreshold;
- /** The paint applied to the drag view on hover */
- protected int mHoverColor = 0;
-
protected CharSequence mText;
protected ColorStateList mOriginalTextColor;
protected Drawable mDrawable;
@@ -101,7 +91,6 @@
private int mToolTipLocation;
private AnimatorSet mCurrentColorAnim;
- @Thunk ColorMatrix mSrcFilter, mDstFilter, mCurrentFilter;
public ButtonDropTarget(Context context, AttributeSet attrs) {
this(context, attrs, 0);
@@ -177,8 +166,7 @@
mToolTip.showAsDropDown(this, x, y);
}
- d.dragView.setColor(mHoverColor);
- animateTextColor(mHoverColor);
+ d.dragView.setAlpha(DRAG_VIEW_HOVER_OVER_OPACITY);
if (d.stateAnnouncer != null) {
d.stateAnnouncer.cancel();
}
@@ -190,51 +178,15 @@
// Do nothing
}
- protected void resetHoverColor() {
- animateTextColor(mOriginalTextColor.getDefaultColor());
- }
-
- private void animateTextColor(int targetColor) {
- if (mCurrentColorAnim != null) {
- mCurrentColorAnim.cancel();
- }
-
- mCurrentColorAnim = new AnimatorSet();
- mCurrentColorAnim.setDuration(DragView.COLOR_CHANGE_DURATION);
-
- if (mSrcFilter == null) {
- mSrcFilter = new ColorMatrix();
- mDstFilter = new ColorMatrix();
- mCurrentFilter = new ColorMatrix();
- }
-
- int defaultTextColor = mOriginalTextColor.getDefaultColor();
- Themes.setColorChangeOnMatrix(defaultTextColor, getTextColor(), mSrcFilter);
- Themes.setColorChangeOnMatrix(defaultTextColor, targetColor, mDstFilter);
-
- ValueAnimator anim1 = ValueAnimator.ofObject(
- new FloatArrayEvaluator(mCurrentFilter.getArray()),
- mSrcFilter.getArray(), mDstFilter.getArray());
- anim1.addUpdateListener((anim) -> {
- mDrawable.setColorFilter(new ColorMatrixColorFilter(mCurrentFilter));
- invalidate();
- });
-
- mCurrentColorAnim.play(anim1);
- mCurrentColorAnim.play(ObjectAnimator.ofArgb(this, TEXT_COLOR, targetColor));
- mCurrentColorAnim.start();
- }
-
@Override
public final void onDragExit(DragObject d) {
hideTooltip();
if (!d.dragComplete) {
d.dragView.setColor(0);
- resetHoverColor();
+ d.dragView.setAlpha(1f);
} else {
- // Restore the hover color
- d.dragView.setColor(mHoverColor);
+ d.dragView.setAlpha(DRAG_VIEW_HOVER_OVER_OPACITY);
}
}
diff --git a/src/com/android/launcher3/DeleteDropTarget.java b/src/com/android/launcher3/DeleteDropTarget.java
index cc119c9..e46aad2 100644
--- a/src/com/android/launcher3/DeleteDropTarget.java
+++ b/src/com/android/launcher3/DeleteDropTarget.java
@@ -53,9 +53,6 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- // Get the hover color
- mHoverColor = getResources().getColor(R.color.delete_target_hover_tint);
-
setDrawable(R.drawable.ic_remove_shadow);
}
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 02571a0..fa19ee6 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -17,6 +17,7 @@
package com.android.launcher3;
import static com.android.launcher3.ResourceUtils.pxFromDp;
+import static com.android.launcher3.Utilities.dpiFromPx;
import android.content.Context;
import android.content.res.Configuration;
@@ -38,6 +39,8 @@
import com.android.launcher3.util.DisplayController.Info;
import com.android.launcher3.util.WindowBounds;
+import java.io.PrintWriter;
+
public class DeviceProfile {
private static final float TABLET_MIN_DPS = 600;
@@ -91,8 +94,10 @@
public float workspaceSpringLoadShrinkFactor;
public final int workspaceSpringLoadedBottomSpace;
+ private final int extraSpace;
public int workspaceTopPadding;
public int workspaceBottomPadding;
+ public int extraHotseatBottomPadding;
// Workspace page indicator
public final int workspacePageIndicatorHeight;
@@ -109,7 +114,6 @@
public int workspaceCellPaddingXPx;
public int cellYPaddingPx;
- public int cellYPaddingOriginalPx;
// Folder
public float folderLabelTextScale;
@@ -199,8 +203,7 @@
mInfo = info;
// Constants from resources
- float swDPs = Utilities.dpiFromPx(
- Math.min(info.smallestSize.x, info.smallestSize.y), info.metrics);
+ float swDPs = dpiFromPx(Math.min(info.smallestSize.x, info.smallestSize.y), info.metrics);
boolean allowRotation = context.getResources().getBoolean(R.bool.allow_rotation);
// Tablet UI is built with assumption that simulated landscape is disabled.
isTablet = allowRotation && swDPs >= TABLET_MIN_DPS;
@@ -295,22 +298,22 @@
+ (isScalableGrid ? 0 : hotseatExtraVerticalSize)));
// Calculate all of the remaining variables.
- int extraSpace = updateAvailableDimensions(res);
+ extraSpace = updateAvailableDimensions(res);
// Now that we have all of the variables calculated, we can tune certain sizes.
if (isScalableGrid) {
DevicePadding padding = inv.devicePaddings.getDevicePadding(extraSpace);
workspaceTopPadding = padding.getWorkspaceTopPadding(extraSpace);
workspaceBottomPadding = padding.getWorkspaceBottomPadding(extraSpace);
- float hotseatBarBottomPadding = padding.getHotseatBottomPadding(extraSpace);
- hotseatBarSizePx += hotseatBarBottomPadding;
- hotseatBarBottomPaddingPx += hotseatBarBottomPadding;
+ extraHotseatBottomPadding = padding.getHotseatBottomPadding(extraSpace);
+ hotseatBarSizePx += extraHotseatBottomPadding;
+ hotseatBarBottomPaddingPx += extraHotseatBottomPadding;
} else if (!isVerticalBarLayout() && isPhone && isTallDevice) {
// We increase the hotseat size when there is extra space.
// ie. For a display with a large aspect ratio, we can keep the icons on the workspace
// in portrait mode closer together by adding more height to the hotseat.
// Note: This calculation was created after noticing a pattern in the design spec.
- extraSpace = getCellSize().y - iconSizePx - iconDrawablePaddingPx * 2
+ int extraSpace = getCellSize().y - iconSizePx - iconDrawablePaddingPx * 2
- workspacePageIndicatorHeight;
hotseatBarSizePx += extraSpace;
hotseatBarBottomPaddingPx += extraSpace;
@@ -794,6 +797,93 @@
}
}
+ private String pxToDpStr(String name, float value) {
+ return "\t" + name + ": " + value + "px (" + dpiFromPx(value, mInfo.metrics) + "dp)";
+ }
+
+ public void dump(String prefix, PrintWriter writer) {
+ writer.println(prefix + "DeviceProfile:");
+ writer.println(prefix + "\t1 dp = " + mInfo.metrics.density + " px");
+
+ writer.println(prefix + "\tisTablet:" + isTablet);
+ writer.println(prefix + "\tisLargeTablet:" + isLargeTablet);
+ writer.println(prefix + "\tisPhone:" + isPhone);
+ writer.println(prefix + "\ttransposeLayoutWithOrientation:"
+ + transposeLayoutWithOrientation);
+
+ writer.println(prefix + "\tisLandscape:" + isLandscape);
+ writer.println(prefix + "\tisMultiWindowMode:" + isMultiWindowMode);
+
+ writer.println(prefix + pxToDpStr("windowX", windowX));
+ writer.println(prefix + pxToDpStr("windowY", windowY));
+ writer.println(prefix + pxToDpStr("widthPx", widthPx));
+ writer.println(prefix + pxToDpStr("heightPx", heightPx));
+
+ writer.println(prefix + pxToDpStr("availableWidthPx", availableWidthPx));
+ writer.println(prefix + pxToDpStr("availableHeightPx", availableHeightPx));
+
+ writer.println(prefix + "\taspectRatio:" + aspectRatio);
+
+ writer.println(prefix + "\tisScalableGrid:" + isScalableGrid);
+
+ writer.println(prefix + "\tinv.minCellWidth:" + inv.minCellWidth + "dp");
+ writer.println(prefix + "\tinv.minCellHeight:" + inv.minCellHeight + "dp");
+
+ writer.println(prefix + pxToDpStr("cellWidthPx", cellWidthPx));
+ writer.println(prefix + pxToDpStr("cellHeightPx", cellHeightPx));
+
+ writer.println(prefix + pxToDpStr("getCellSize().x", getCellSize().x));
+ writer.println(prefix + pxToDpStr("getCellSize().y", getCellSize().y));
+
+ writer.println(prefix + "\tinv.iconSize:" + inv.iconSize + "dp");
+ writer.println(prefix + pxToDpStr("iconSizePx", iconSizePx));
+ writer.println(prefix + pxToDpStr("iconTextSizePx", iconTextSizePx));
+ writer.println(prefix + pxToDpStr("iconDrawablePaddingPx", iconDrawablePaddingPx));
+
+ writer.println(prefix + pxToDpStr("folderCellWidthPx", folderCellWidthPx));
+ writer.println(prefix + pxToDpStr("folderCellHeightPx", folderCellHeightPx));
+ writer.println(prefix + pxToDpStr("folderChildIconSizePx", folderChildIconSizePx));
+ writer.println(prefix + pxToDpStr("folderChildTextSizePx", folderChildTextSizePx));
+ writer.println(prefix + pxToDpStr("folderChildDrawablePaddingPx",
+ folderChildDrawablePaddingPx));
+
+ writer.println(prefix + pxToDpStr("cellLayoutBorderSpacingPx",
+ cellLayoutBorderSpacingPx));
+ writer.println(prefix + pxToDpStr("desiredWorkspaceLeftRightMarginPx",
+ desiredWorkspaceLeftRightMarginPx));
+
+ writer.println(prefix + pxToDpStr("allAppsIconSizePx", allAppsIconSizePx));
+ writer.println(prefix + pxToDpStr("allAppsIconTextSizePx", allAppsIconTextSizePx));
+ writer.println(prefix + pxToDpStr("allAppsIconDrawablePaddingPx",
+ allAppsIconDrawablePaddingPx));
+ writer.println(prefix + pxToDpStr("allAppsCellHeightPx", allAppsCellHeightPx));
+
+ writer.println(prefix + pxToDpStr("hotseatBarSizePx", hotseatBarSizePx));
+ writer.println(prefix + pxToDpStr("hotseatCellHeightPx", hotseatCellHeightPx));
+ writer.println(prefix + pxToDpStr("hotseatBarTopPaddingPx", hotseatBarTopPaddingPx));
+ writer.println(prefix + pxToDpStr("hotseatBarBottomPaddingPx", hotseatBarBottomPaddingPx));
+ writer.println(prefix + pxToDpStr("hotseatBarSidePaddingStartPx",
+ hotseatBarSidePaddingStartPx));
+ writer.println(prefix + pxToDpStr("hotseatBarSidePaddingEndPx",
+ hotseatBarSidePaddingEndPx));
+
+ writer.println(prefix + "\tisTaskbarPresent:" + isTaskbarPresent);
+
+ writer.println(prefix + pxToDpStr("taskbarSize", taskbarSize));
+ writer.println(prefix + pxToDpStr("nonOverlappingTaskbarInset",
+ nonOverlappingTaskbarInset));
+
+ writer.println(prefix + pxToDpStr("workspacePadding.left", workspacePadding.left));
+ writer.println(prefix + pxToDpStr("workspacePadding.top", workspacePadding.top));
+ writer.println(prefix + pxToDpStr("workspacePadding.right", workspacePadding.right));
+ writer.println(prefix + pxToDpStr("workspacePadding.bottom", workspacePadding.bottom));
+
+ writer.println(prefix + pxToDpStr("extraSpace", extraSpace));
+ writer.println(prefix + pxToDpStr("workspaceTopPadding", workspaceTopPadding));
+ writer.println(prefix + pxToDpStr("workspaceBottomPadding", workspaceBottomPadding));
+ writer.println(prefix + pxToDpStr("extraHotseatBottomPadding", extraHotseatBottomPadding));
+ }
+
private static Context getContext(Context c, Info info, int orientation) {
Configuration config = new Configuration(c.getResources().getConfiguration());
config.orientation = orientation;
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index af4a843..4049ed6 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -29,8 +29,6 @@
import androidx.annotation.Nullable;
-import com.android.launcher3.util.MultiValueAlpha;
-
import java.util.function.Consumer;
/**
@@ -38,10 +36,6 @@
*/
public class Hotseat extends CellLayout implements Insettable {
- private static final int ALPHA_INDEX_STATE = 0;
- private static final int ALPHA_INDEX_REPLACE_TASKBAR = 1;
- private static final int NUM_ALPHA_CHANNELS = 2;
-
// Ratio of empty space, qsb should take up to appear visually centered.
public static final float QSB_CENTER_FACTOR = .325f;
@@ -52,10 +46,12 @@
@Nullable
private Consumer<Boolean> mOnVisibilityAggregatedCallback;
- private final MultiValueAlpha mMultiValueAlpha;
private final View mQsb;
private final int mQsbHeight;
+ private final View mTaskbarView;
+ private final int mTaskbarViewHeight;
+
public Hotseat(Context context) {
this(context, null);
}
@@ -66,12 +62,15 @@
public Hotseat(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
- mMultiValueAlpha = new MultiValueAlpha(this, NUM_ALPHA_CHANNELS, MultiValueAlpha.Mode.MAX);
- mMultiValueAlpha.setUpdateVisibility(true);
mQsb = LayoutInflater.from(context).inflate(R.layout.search_container_hotseat, this, false);
mQsbHeight = mQsb.getLayoutParams().height;
addView(mQsb);
+
+ mTaskbarView = LayoutInflater.from(context).inflate(R.layout.taskbar_view, this, false);
+ mTaskbarViewHeight = mTaskbarView.getLayoutParams().height;
+ // We want taskbar in the back so its background applies to Hotseat as well.
+ addView(mTaskbarView, 0);
}
/**
@@ -193,6 +192,8 @@
int width = getShortcutsAndWidgets().getMeasuredWidth();
mQsb.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(mQsbHeight, MeasureSpec.EXACTLY));
+ mTaskbarView.measure(MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(mTaskbarViewHeight, MeasureSpec.EXACTLY));
}
@Override
@@ -212,6 +213,13 @@
- (dp.isTaskbarPresent ? dp.taskbarSize : dp.getInsets().bottom);
int top = bottom - mQsbHeight;
mQsb.layout(left, top, right, bottom);
+
+ int taskbarWidth = mTaskbarView.getMeasuredWidth();
+ left = (r - l - taskbarWidth) / 2;
+ right = left + taskbarWidth;
+ bottom = b - t;
+ top = bottom - mTaskbarViewHeight;
+ mTaskbarView.layout(left, top, right, bottom);
}
/**
@@ -221,12 +229,11 @@
return mWorkspace.getFirstMatch(new CellLayout[] { this }, itemOperator);
}
- public MultiValueAlpha.AlphaProperty getStateAlpha() {
- return mMultiValueAlpha.getProperty(ALPHA_INDEX_STATE);
- }
-
- public MultiValueAlpha.AlphaProperty getReplaceTaskbarAlpha() {
- return mMultiValueAlpha.getProperty(ALPHA_INDEX_REPLACE_TASKBAR);
+ /**
+ * Sets the alpha value of just our ShortcutAndWidgetContainer.
+ */
+ public void setIconsAlpha(float alpha) {
+ getShortcutsAndWidgets().setAlpha(alpha);
}
/**
@@ -235,4 +242,11 @@
public View getQsb() {
return mQsb;
}
+
+ /**
+ * Returns the Taskbar inside hotseat
+ */
+ public View getTaskbarView() {
+ return mTaskbarView;
+ }
}
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index c57f621..89c0f66 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -2634,6 +2634,7 @@
mDragLayer.dump(prefix, writer);
mStateManager.dump(prefix, writer);
mPopupDataProvider.dump(prefix, writer);
+ mDeviceProfile.dump(prefix, writer);
try {
FileLog.flushAll(writer);
diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java
index e9a3495..06bc438 100644
--- a/src/com/android/launcher3/LauncherState.java
+++ b/src/com/android/launcher3/LauncherState.java
@@ -176,21 +176,12 @@
return launcher.getNormalOverviewScaleAndOffset();
}
- public ScaleAndTranslation getQsbScaleAndTranslation(Launcher launcher) {
- return new ScaleAndTranslation(NO_SCALE, NO_OFFSET, NO_OFFSET);
- }
-
public float getOverviewFullscreenProgress() {
return 0;
}
public int getVisibleElements(Launcher launcher) {
- DeviceProfile deviceProfile = launcher.getDeviceProfile();
- int flags = WORKSPACE_PAGE_INDICATOR | VERTICAL_SWIPE_INDICATOR | TASKBAR;
- if (!deviceProfile.isTaskbarPresent) {
- flags |= HOTSEAT_ICONS;
- }
- return flags;
+ return HOTSEAT_ICONS | WORKSPACE_PAGE_INDICATOR | VERTICAL_SWIPE_INDICATOR | TASKBAR;
}
/**
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index b084eb1..72eff62 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -63,6 +63,7 @@
import com.android.launcher3.views.ActivityContext;
import java.util.ArrayList;
+import java.util.List;
/**
* An abstraction of the original Workspace which supports browsing through a
@@ -304,6 +305,21 @@
}
/**
+ * Returns the currently visible pages.
+ */
+ protected Iterable<View> getVisiblePages() {
+ int panelCount = getPanelCount();
+ List<View> visiblePages = new ArrayList<>(panelCount);
+ for (int i = mCurrentPage; i < mCurrentPage + panelCount; i++) {
+ View page = getPageAt(i);
+ if (page != null) {
+ visiblePages.add(page);
+ }
+ }
+ return visiblePages;
+ }
+
+ /**
* Returns true if the view is on one of the current pages, false otherwise.
*/
public boolean isVisible(View child) {
@@ -1052,10 +1068,7 @@
// Try canceling the long press. It could also have been scheduled
// by a distant descendant, so use the mAllowLongPress flag to block
// everything
- final View currentPage = getPageAt(mCurrentPage);
- if (currentPage != null) {
- currentPage.cancelLongPress();
- }
+ getVisiblePages().forEach(View::cancelLongPress);
}
protected float getScrollProgress(int screenCenter, View v, int page) {
diff --git a/src/com/android/launcher3/SecondaryDropTarget.java b/src/com/android/launcher3/SecondaryDropTarget.java
index 8bc5ad0..858b72e 100644
--- a/src/com/android/launcher3/SecondaryDropTarget.java
+++ b/src/com/android/launcher3/SecondaryDropTarget.java
@@ -44,7 +44,6 @@
import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.util.PackageManagerHelper;
-import com.android.launcher3.util.Themes;
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import java.net.URISyntaxException;
@@ -109,15 +108,12 @@
mCurrentAccessibilityAction = action;
if (action == UNINSTALL) {
- mHoverColor = getResources().getColor(R.color.uninstall_target_hover_tint);
setDrawable(R.drawable.ic_uninstall_shadow);
updateText(R.string.uninstall_drop_target_label);
} else if (action == DISMISS_PREDICTION) {
- mHoverColor = Themes.getColorAccent(getContext());
setDrawable(R.drawable.ic_block_shadow);
updateText(R.string.dismiss_prediction_label);
} else if (action == RECONFIGURE) {
- mHoverColor = Themes.getColorAccent(getContext());
setDrawable(R.drawable.ic_setup_shadow);
updateText(R.string.gadget_setup_text);
}
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index 412754e..6db7a75 100644
--- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -54,7 +54,6 @@
import com.android.launcher3.graphics.WorkspaceDragScrim;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.util.DynamicResource;
-import com.android.launcher3.util.MultiValueAlpha;
import com.android.systemui.plugins.ResourceProvider;
/**
@@ -96,7 +95,6 @@
ScaleAndTranslation scaleAndTranslation = state.getWorkspaceScaleAndTranslation(mLauncher);
ScaleAndTranslation hotseatScaleAndTranslation = state.getHotseatScaleAndTranslation(
mLauncher);
- ScaleAndTranslation qsbScaleAndTranslation = state.getQsbScaleAndTranslation(mLauncher);
mNewScale = scaleAndTranslation.scale;
PageAlphaProvider pageAlphaProvider = state.getWorkspacePageAlphaProvider(mLauncher);
final int childCount = mWorkspace.getChildCount();
@@ -135,8 +133,8 @@
}
float hotseatIconsAlpha = (elements & HOTSEAT_ICONS) != 0 ? 1 : 0;
- propertySetter.setFloat(hotseat.getStateAlpha(), MultiValueAlpha.VALUE,
- hotseatIconsAlpha, config.getInterpolator(ANIM_HOTSEAT_FADE, fadeInterpolator));
+ propertySetter.setViewAlpha(hotseat, hotseatIconsAlpha,
+ config.getInterpolator(ANIM_HOTSEAT_FADE, fadeInterpolator));
float workspacePageIndicatorAlpha = (elements & WORKSPACE_PAGE_INDICATOR) != 0 ? 1 : 0;
propertySetter.setViewAlpha(mLauncher.getWorkspace().getPageIndicator(),
workspacePageIndicatorAlpha, fadeInterpolator);
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index 78c404f..591de04 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -15,7 +15,6 @@
*/
package com.android.launcher3.allapps;
-import static com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItem;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_TAP_ON_PERSONAL_TAB;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_TAP_ON_WORK_TAB;
import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_HAS_SHORTCUT_PERMISSION;
@@ -63,7 +62,6 @@
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.keyboard.FocusedItemDecorator;
import com.android.launcher3.model.data.AppInfo;
-import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.MultiValueAlpha;
@@ -564,37 +562,9 @@
/**
* Handles selection on focused view and returns success
*/
- public boolean selectFocusedView(View v) {
- ItemInfo headerItem = getHighlightedItemFromHeader();
- if (headerItem != null) {
- return mLauncher.startActivitySafely(v, headerItem.getIntent(), headerItem);
- }
- AdapterItem focusedItem = getActiveRecyclerView().getApps().getFocusedChild();
- if (focusedItem != null) {
- View focusedView = getActiveRecyclerView().getLayoutManager()
- .findViewByPosition(focusedItem.position);
- if (focusedView != null && mSearchAdapterProvider.onAdapterItemSelected(focusedItem,
- focusedView)) {
- return true;
- }
- }
- if (focusedItem != null && focusedItem.appInfo != null) {
- ItemInfo itemInfo = focusedItem.appInfo;
- return mLauncher.startActivitySafely(v, itemInfo.getIntent(), itemInfo);
- }
- return false;
- }
-
- /**
- * Returns the ItemInfo of a focused view inside {@link FloatingHeaderView}
- */
- public ItemInfo getHighlightedItemFromHeader() {
- View view = getFloatingHeaderView().getFocusedChild();
- if (view != null && view.getTag() instanceof ItemInfo) {
- return ((ItemInfo) view.getTag());
- }
-
- return null;
+ public boolean launchHighlightedItem() {
+ if (mSearchAdapterProvider == null) return false;
+ return mSearchAdapterProvider.launchHighlightedItem();
}
public SearchAdapterProvider getSearchAdapterProvider() {
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
index f307a53..66575eb 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -189,6 +189,7 @@
case SCROLL_STATE_DRAGGING:
mgr.logger().sendToInteractionJankMonitor(
LAUNCHER_ALLAPPS_VERTICAL_SWIPE_BEGIN, this);
+ requestFocus();
getWindowInsetsController().hide(WindowInsets.Type.ime());
break;
case SCROLL_STATE_IDLE:
diff --git a/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java b/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java
index 269e390..0bd2f44 100644
--- a/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java
+++ b/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java
@@ -22,13 +22,12 @@
import android.graphics.RectF;
import android.view.View;
-import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.graphics.ColorUtils;
import androidx.recyclerview.widget.RecyclerView;
import com.android.launcher3.R;
-import com.android.launcher3.allapps.AllAppsGridAdapter.AppsGridLayoutManager;
+import com.android.launcher3.allapps.search.SearchAdapterProvider;
import com.android.launcher3.allapps.search.SectionDecorationInfo;
import com.android.launcher3.util.Themes;
@@ -48,6 +47,7 @@
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
List<AllAppsGridAdapter.AdapterItem> adapterItems = mAppsView.getApps().getAdapterItems();
+ SearchAdapterProvider adapterProvider = mAppsView.getSearchAdapterProvider();
for (int i = 0; i < parent.getChildCount(); i++) {
View view = parent.getChildAt(i);
int position = parent.getChildAdapterPosition(view);
@@ -56,7 +56,7 @@
SectionDecorationInfo sectionInfo = adapterItem.sectionDecorationInfo;
SectionDecorationHandler decorationHandler = sectionInfo.getDecorationHandler();
if (decorationHandler != null) {
- if (sectionInfo.isFocusedView()) {
+ if (view.equals(adapterProvider.getHighlightedItem())) {
decorationHandler.onFocusDraw(c, view);
} else {
decorationHandler.onGroupDraw(c, view);
@@ -66,28 +66,6 @@
}
}
- // Fallback logic in case non of the SearchTarget is labeled as focused item.
- private void drawDecoration(@NonNull Canvas c,
- @NonNull SectionDecorationHandler decorationHandler,
- @NonNull RecyclerView parent) {
- if (decorationHandler.mIsFullWidth) {
- decorationHandler.mBounds.left = parent.getPaddingLeft();
- decorationHandler.mBounds.right = parent.getWidth() - parent.getPaddingRight();
- }
- if (mAppsView.getFloatingHeaderView().getFocusedChild() == null
- && mAppsView.getApps().getFocusedChild() != null) {
- int index = mAppsView.getApps().getFocusedChildIndex();
- AppsGridLayoutManager layoutManager = (AppsGridLayoutManager)
- mAppsView.getActiveRecyclerView().getLayoutManager();
- if (layoutManager.findFirstVisibleItemPosition() <= index
- && index < parent.getChildCount()) {
- RecyclerView.ViewHolder vh = parent.findViewHolderForAdapterPosition(index);
- if (vh != null) decorationHandler.onFocusDraw(c, vh.itemView);
- }
- }
- decorationHandler.reset();
- }
-
/**
* Handles grouping and drawing of items in the same all apps sections.
*/
@@ -102,7 +80,7 @@
private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private final boolean mIsTopRound;
private final boolean mIsBottomRound;
- private float [] mCorners;
+ private float[] mCorners;
private float mFillSpacing;
public SectionDecorationHandler(Context context, boolean isFullWidth, int fillAlpha,
@@ -134,7 +112,6 @@
*/
public void onGroupDraw(Canvas canvas, View view) {
if (view == null) return;
-
mPaint.setColor(mFillcolor);
mBounds.set(view.getLeft(), view.getTop(), view.getRight(), view.getBottom());
onDraw(canvas);
diff --git a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
index d3c9993..79718fb 100644
--- a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
+++ b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
@@ -35,7 +35,6 @@
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.search.SearchAlgorithm;
import com.android.launcher3.search.SearchCallback;
-import com.android.launcher3.util.PackageManagerHelper;
/**
* An interface to a search box that AllApps can command.
@@ -105,30 +104,14 @@
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
- if (FeatureFlags.ENABLE_DEVICE_SEARCH.get()) {
- if (actionId == EditorInfo.IME_ACTION_SEARCH || actionId == EditorInfo.IME_ACTION_GO) {
- mLauncher.getStatsLogManager().logger()
- .log(LAUNCHER_ALLAPPS_FOCUSED_ITEM_SELECTED_WITH_IME);
- // selectFocusedView should return SearchTargetEvent that is passed onto onClick
- if (Launcher.getLauncher(mLauncher).getAppsView().selectFocusedView(v)) {
- return true;
- }
- }
- }
- // Skip if it's not the right action
- if (actionId != EditorInfo.IME_ACTION_SEARCH) {
- return false;
+ if (actionId == EditorInfo.IME_ACTION_SEARCH || actionId == EditorInfo.IME_ACTION_GO) {
+ mLauncher.getStatsLogManager().logger()
+ .log(LAUNCHER_ALLAPPS_FOCUSED_ITEM_SELECTED_WITH_IME);
+ // selectFocusedView should return SearchTargetEvent that is passed onto onClick
+ return Launcher.getLauncher(mLauncher).getAppsView().launchHighlightedItem();
}
-
- // Skip if the query is empty
- String query = v.getText().toString();
- if (query.isEmpty()) {
- return false;
- }
- return mLauncher.startActivitySafely(v,
- PackageManagerHelper.getMarketSearchIntent(mLauncher, query), null
- );
+ return false;
}
@Override
diff --git a/src/com/android/launcher3/allapps/search/DefaultSearchAdapterProvider.java b/src/com/android/launcher3/allapps/search/DefaultSearchAdapterProvider.java
index e268f56..ba895ed 100644
--- a/src/com/android/launcher3/allapps/search/DefaultSearchAdapterProvider.java
+++ b/src/com/android/launcher3/allapps/search/DefaultSearchAdapterProvider.java
@@ -15,31 +15,31 @@
*/
package com.android.launcher3.allapps.search;
-import android.net.Uri;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.android.launcher3.BaseDraggingActivity;
+import com.android.launcher3.BubbleTextView;
import com.android.launcher3.allapps.AllAppsGridAdapter;
+import com.android.launcher3.model.data.ItemInfo;
/**
* Provides views for local search results
*/
public class DefaultSearchAdapterProvider extends SearchAdapterProvider {
+ private View mHighlightedView;
+
public DefaultSearchAdapterProvider(BaseDraggingActivity launcher) {
super(launcher);
}
@Override
public void onBindView(AllAppsGridAdapter.ViewHolder holder, int position) {
-
- }
-
- @Override
- public void onSliceStatusUpdate(Uri sliceUri) {
-
+ if (position == 0) {
+ mHighlightedView = holder.itemView;
+ }
}
@Override
@@ -54,7 +54,17 @@
}
@Override
- public boolean onAdapterItemSelected(AllAppsGridAdapter.AdapterItem adapterItem, View view) {
+ public boolean launchHighlightedItem() {
+ if (mHighlightedView instanceof BubbleTextView
+ && mHighlightedView.getTag() instanceof ItemInfo) {
+ ItemInfo itemInfo = (ItemInfo) mHighlightedView.getTag();
+ return mLauncher.startActivitySafely(mHighlightedView, itemInfo.getIntent(), itemInfo);
+ }
return false;
}
+
+ @Override
+ public View getHighlightedItem() {
+ return mHighlightedView;
+ }
}
diff --git a/src/com/android/launcher3/allapps/search/SearchAdapterProvider.java b/src/com/android/launcher3/allapps/search/SearchAdapterProvider.java
index 0864090..a650a7d 100644
--- a/src/com/android/launcher3/allapps/search/SearchAdapterProvider.java
+++ b/src/com/android/launcher3/allapps/search/SearchAdapterProvider.java
@@ -43,7 +43,8 @@
/**
* Called from LiveSearchManager to notify slice status updates.
*/
- public abstract void onSliceStatusUpdate(Uri sliceUri);
+ public void onSliceStatusUpdate(Uri sliceUri) {
+ }
/**
* Returns whether or not viewType can be handled by searchProvider
@@ -74,6 +75,12 @@
* handles selection event on search adapter item. Returns false if provider can not handle
* event
*/
- public abstract boolean onAdapterItemSelected(AllAppsGridAdapter.AdapterItem adapterItem,
- View view);
+ public abstract boolean launchHighlightedItem();
+
+ /**
+ * Returns the current highlighted view
+ */
+ public abstract View getHighlightedItem();
+
+
}
diff --git a/src/com/android/launcher3/allapps/search/SectionDecorationInfo.java b/src/com/android/launcher3/allapps/search/SectionDecorationInfo.java
index 0b64fca..56dd63c 100644
--- a/src/com/android/launcher3/allapps/search/SectionDecorationInfo.java
+++ b/src/com/android/launcher3/allapps/search/SectionDecorationInfo.java
@@ -21,22 +21,11 @@
* Info class for a search section that is primarily used for decoration.
*/
public class SectionDecorationInfo {
-
- public static final int QUICK_LAUNCH = 1 << 0;
public static final int GROUPING = 1 << 1;
private String mSectionId;
- private boolean mFocused;
private SectionDecorationHandler mDecorationHandler;
- public boolean isFocusedView() {
- return mFocused;
- }
-
- public void setFocusedView(boolean focused) {
- mFocused = focused;
- }
-
public SectionDecorationInfo() {
this(null);
}
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 96251f0..7f76d27 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -215,6 +215,9 @@
public static final BooleanFlag ENABLE_SPLIT_SELECT = getDebugFlag(
"ENABLE_SPLIT_SELECT", false, "Uses new split screen selection overview UI");
+ public static final BooleanFlag ENABLE_ENFORCED_ROUNDED_CORNERS = new DeviceFlag(
+ "ENABLE_ENFORCED_ROUNDED_CORNERS", true, "Enforce rounded corners on all App Widgets");
+
public static void initialize(Context context) {
synchronized (sDebugFlags) {
for (DebugFlag flag : sDebugFlags) {
diff --git a/src/com/android/launcher3/dragndrop/AddItemActivity.java b/src/com/android/launcher3/dragndrop/AddItemActivity.java
index 7bc9865..b7a7366 100644
--- a/src/com/android/launcher3/dragndrop/AddItemActivity.java
+++ b/src/com/android/launcher3/dragndrop/AddItemActivity.java
@@ -37,11 +37,14 @@
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
+import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.DragShadowBuilder;
import android.view.View.OnLongClickListener;
import android.view.View.OnTouchListener;
+import android.view.WindowManager;
+import android.widget.TextView;
import com.android.launcher3.BaseActivity;
import com.android.launcher3.InvariantDeviceProfile;
@@ -127,6 +130,9 @@
if (savedInstanceState == null) {
logCommand(LAUNCHER_ADD_EXTERNAL_ITEM_START);
}
+
+ TextView widgetAppName = findViewById(R.id.widget_appName);
+ widgetAppName.setText(getApplicationInfo().labelRes);
}
@Override
@@ -326,4 +332,15 @@
.withItemInfo((ItemInfo) mWidgetCell.getWidgetView().getTag())
.log(command);
}
+
+ @Override
+ public void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ View view = getWindow().getDecorView();
+ WindowManager.LayoutParams layoutParams =
+ (WindowManager.LayoutParams) view.getLayoutParams();
+ layoutParams.gravity = Gravity.BOTTOM;
+ layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT;
+ getWindowManager().updateViewLayout(view, layoutParams);
+ }
}
diff --git a/src/com/android/launcher3/dragndrop/AppWidgetHostViewDrawable.java b/src/com/android/launcher3/dragndrop/AppWidgetHostViewDrawable.java
index 92ae670..5cd95dc 100644
--- a/src/com/android/launcher3/dragndrop/AppWidgetHostViewDrawable.java
+++ b/src/com/android/launcher3/dragndrop/AppWidgetHostViewDrawable.java
@@ -17,8 +17,12 @@
import android.graphics.Canvas;
import android.graphics.ColorFilter;
+import android.graphics.Outline;
import android.graphics.Paint;
+import android.graphics.Path;
import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import com.android.launcher3.widget.LauncherAppWidgetHostView;
@@ -28,14 +32,30 @@
private final LauncherAppWidgetHostView mAppWidgetHostView;
private Paint mPaint = new Paint();
+ private final Path mClipPath;
public AppWidgetHostViewDrawable(LauncherAppWidgetHostView appWidgetHostView) {
mAppWidgetHostView = appWidgetHostView;
+ Path clipPath = null;
+ if (appWidgetHostView.getClipToOutline()) {
+ Outline outline = new Outline();
+ mAppWidgetHostView.getOutlineProvider().getOutline(mAppWidgetHostView, outline);
+ Rect rect = new Rect();
+ if (outline.getRect(rect)) {
+ float radius = outline.getRadius();
+ clipPath = new Path();
+ clipPath.addRoundRect(new RectF(rect), radius, radius, Path.Direction.CCW);
+ }
+ }
+ mClipPath = clipPath;
}
@Override
public void draw(Canvas canvas) {
int saveCount = canvas.saveLayer(0, 0, getIntrinsicWidth(), getIntrinsicHeight(), mPaint);
+ if (mClipPath != null) {
+ canvas.clipPath(mClipPath);
+ }
mAppWidgetHostView.draw(canvas);
canvas.restoreToCount(saveCount);
}
diff --git a/src/com/android/launcher3/dragndrop/DragLayer.java b/src/com/android/launcher3/dragndrop/DragLayer.java
index 7a6b4f9..419c3f1 100644
--- a/src/com/android/launcher3/dragndrop/DragLayer.java
+++ b/src/com/android/launcher3/dragndrop/DragLayer.java
@@ -110,6 +110,8 @@
mDragController = dragController;
recreateControllers();
+ mOverviewScrim.setup();
+
mWorkspaceDragScrim = new WorkspaceDragScrim((this));
mWorkspaceDragScrim.setWorkspace(workspace);
@@ -118,8 +120,6 @@
mRootView = (LauncherRootView) getParent();
mSysUiScrim = new SysUiScrim(mRootView);
mRootView.setSysUiScrim(mSysUiScrim);
-
-
}
@Override
@@ -555,7 +555,6 @@
public void setInsets(Rect insets) {
super.setInsets(insets);
mSysUiScrim.onInsetsChanged(insets, mAllowSysuiScrims);
- mOverviewScrim.onInsetsChanged(insets);
}
public WorkspaceDragScrim getWorkspaceDragScrim() {
diff --git a/src/com/android/launcher3/folder/ClippedFolderIconLayoutRule.java b/src/com/android/launcher3/folder/ClippedFolderIconLayoutRule.java
index 5954efa..c67efef 100644
--- a/src/com/android/launcher3/folder/ClippedFolderIconLayoutRule.java
+++ b/src/com/android/launcher3/folder/ClippedFolderIconLayoutRule.java
@@ -97,7 +97,7 @@
double thetaShift = 0;
if (curNumItems == 3) {
- thetaShift = Math.PI / 6;
+ thetaShift = Math.PI / 2;
} else if (curNumItems == 4) {
thetaShift = Math.PI / 4;
}
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index bcb3a54..ec7155c 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -26,6 +26,7 @@
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_CONVERTED_TO_ICON;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_LABEL_UPDATED;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ITEM_DROP_COMPLETED;
+import static com.android.launcher3.util.DisplayController.getSingleFrameMs;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -695,6 +696,9 @@
mPageIndicator.stopAllAnimations();
startAnimation(anim);
+ // Because t=0 has the folder match the folder icon, we can skip the
+ // first frame and have the same movement one frame earlier.
+ anim.setCurrentPlayTime(Math.min(getSingleFrameMs(getContext()), anim.getTotalDuration()));
// Make sure the folder picks up the last drag move even if the finger doesn't move.
if (mDragController.isDragging()) {
diff --git a/src/com/android/launcher3/graphics/OverviewScrim.java b/src/com/android/launcher3/graphics/OverviewScrim.java
index c0c3e5e..53303db 100644
--- a/src/com/android/launcher3/graphics/OverviewScrim.java
+++ b/src/com/android/launcher3/graphics/OverviewScrim.java
@@ -18,10 +18,6 @@
import static android.view.View.VISIBLE;
-import static com.android.launcher3.LauncherState.HOTSEAT_ICONS;
-import static com.android.launcher3.LauncherState.OVERVIEW;
-
-import android.graphics.Rect;
import android.util.FloatProperty;
import android.view.View;
import android.view.ViewGroup;
@@ -55,15 +51,15 @@
public OverviewScrim(View view) {
super(view);
- mStableScrimmedView = mCurrentScrimmedView = mLauncher.getOverviewPanel();
onExtractedColorsChanged(mWallpaperColorInfo);
}
- public void onInsetsChanged(Rect insets) {
- mStableScrimmedView = (OVERVIEW.getVisibleElements(mLauncher) & HOTSEAT_ICONS) != 0
- ? mLauncher.getHotseat()
- : mLauncher.getOverviewPanel();
+ /**
+ * Initializes once view hierarchy is established.
+ */
+ public void setup() {
+ mStableScrimmedView = mCurrentScrimmedView = mLauncher.getOverviewPanel();
}
public void updateCurrentScrimmedView(ViewGroup root) {
diff --git a/src/com/android/launcher3/notification/NotificationItemView.java b/src/com/android/launcher3/notification/NotificationItemView.java
index d44d158..e954480 100644
--- a/src/com/android/launcher3/notification/NotificationItemView.java
+++ b/src/com/android/launcher3/notification/NotificationItemView.java
@@ -92,6 +92,10 @@
});
}
+ public void updateBackgroundColor(int color) {
+ mMainView.updateBackgroundColor(color);
+ }
+
public void addGutter() {
if (mGutter == null) {
mGutter = mPopupContainer.inflateAndAdd(R.layout.notification_gutter, mRootView);
diff --git a/src/com/android/launcher3/notification/NotificationMainView.java b/src/com/android/launcher3/notification/NotificationMainView.java
index 9b06523..c995666 100644
--- a/src/com/android/launcher3/notification/NotificationMainView.java
+++ b/src/com/android/launcher3/notification/NotificationMainView.java
@@ -97,15 +97,24 @@
super.onFinishInflate();
mTextAndBackground = findViewById(R.id.text_and_background);
- ColorDrawable colorBackground = (ColorDrawable) mTextAndBackground.getBackground();
- mBackgroundColor = colorBackground.getColor();
- RippleDrawable rippleBackground = new RippleDrawable(ColorStateList.valueOf(
- Themes.getAttrColor(getContext(), android.R.attr.colorControlHighlight)),
- colorBackground, null);
- mTextAndBackground.setBackground(rippleBackground);
mTitleView = mTextAndBackground.findViewById(R.id.title);
mTextView = mTextAndBackground.findViewById(R.id.text);
mIconView = findViewById(R.id.popup_item_icon);
+
+ ColorDrawable colorBackground = (ColorDrawable) mTextAndBackground.getBackground();
+ updateBackgroundColor(colorBackground.getColor());
+ }
+
+ public void updateBackgroundColor(int color) {
+ mBackgroundColor = color;
+ RippleDrawable rippleBackground = new RippleDrawable(ColorStateList.valueOf(
+ Themes.getAttrColor(getContext(), android.R.attr.colorControlHighlight)),
+ new ColorDrawable(color), null);
+ mTextAndBackground.setBackground(rippleBackground);
+ if (mNotificationInfo != null) {
+ mIconView.setBackground(mNotificationInfo.getIconForBackground(getContext(),
+ mBackgroundColor));
+ }
}
public void setSwipeDetector(SingleAxisSwipeDetector swipeDetector) {
diff --git a/src/com/android/launcher3/popup/ArrowPopup.java b/src/com/android/launcher3/popup/ArrowPopup.java
index 6aa9812..3736538 100644
--- a/src/com/android/launcher3/popup/ArrowPopup.java
+++ b/src/com/android/launcher3/popup/ArrowPopup.java
@@ -17,10 +17,12 @@
package com.android.launcher3.popup;
import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
+import static com.android.launcher3.popup.PopupPopulator.MAX_SHORTCUTS;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
+import android.animation.ArgbEvaluator;
import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
@@ -28,6 +30,8 @@
import android.content.res.Resources;
import android.graphics.Outline;
import android.graphics.Rect;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.util.AttributeSet;
import android.util.Pair;
@@ -63,6 +67,9 @@
*/
public abstract class ArrowPopup<T extends BaseDraggingActivity> extends AbstractFloatingView {
+ // +1 for system shortcut view
+ private static final int MAX_NUM_CHILDREN = MAX_SHORTCUTS + 1;
+
private final Rect mTempRect = new Rect();
protected final LayoutInflater mInflater;
@@ -93,6 +100,9 @@
private Runnable mOnCloseCallback = () -> { };
+ private int mArrowColor;
+ private final int[] mColors;
+
public ArrowPopup(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mInflater = LayoutInflater.from(context);
@@ -120,16 +130,24 @@
R.dimen.popup_arrow_horizontal_center_offset) - (mArrowWidth / 2);
mArrowPointRadius = resources.getDimensionPixelSize(R.dimen.popup_arrow_corner_radius);
+ int smallerRadius = resources.getDimensionPixelSize(R.dimen.popup_smaller_radius);
mRoundedTop = new GradientDrawable();
- mRoundedTop.setColor(Themes.getAttrColor(context, R.attr.popupColorPrimary));
mRoundedTop.setCornerRadii(new float[] { mOutlineRadius, mOutlineRadius, mOutlineRadius,
- mOutlineRadius, 0, 0, 0, 0});
+ mOutlineRadius, smallerRadius, smallerRadius, smallerRadius, smallerRadius});
mRoundedBottom = new GradientDrawable();
- mRoundedBottom.setColor(Themes.getAttrColor(context, R.attr.popupColorPrimary));
- mRoundedBottom.setCornerRadii(new float[] { 0, 0, 0, 0, mOutlineRadius, mOutlineRadius,
- mOutlineRadius, mOutlineRadius});
+ mRoundedBottom.setCornerRadii(new float[] { smallerRadius, smallerRadius, smallerRadius,
+ smallerRadius, mOutlineRadius, mOutlineRadius, mOutlineRadius, mOutlineRadius});
+ int primaryColor = Themes.getAttrColor(context, R.attr.popupColorPrimary);
+ int secondaryColor = Themes.getAttrColor(context, R.attr.popupColorSecondary);
+ ArgbEvaluator argb = new ArgbEvaluator();
+ mColors = new int[MAX_NUM_CHILDREN];
+ // Interpolate between the two colors, exclusive.
+ float step = 1f / (MAX_NUM_CHILDREN + 1);
+ for (int i = 0; i < mColors.length; ++i) {
+ mColors[i] = (int) argb.evaluate((i + 1) * step, primaryColor, secondaryColor);
+ }
}
public ArrowPopup(Context context, AttributeSet attrs) {
@@ -187,6 +205,7 @@
int numVisibleShortcut = 0;
View lastView = null;
+ int numVisibleChild = 0;
for (int i = 0; i < count; i++) {
View view = getChildAt(i);
boolean isShortcut = view instanceof DeepShortcutView;
@@ -207,16 +226,42 @@
view.setBackground(mRoundedTop);
} else if (numVisibleShortcut == (totalVisibleShortcuts - 1)) {
view.setBackground(mRoundedBottom);
+ } else {
+ view.setBackgroundResource(R.drawable.middle_item_primary);
}
numVisibleShortcut++;
}
}
+
+ int color = mColors[numVisibleChild % mColors.length];
+ setChildColor(view, color);
+
+ // Arrow color matches the first child or the last child.
+ if (!mIsAboveIcon && numVisibleChild == 0) {
+ mArrowColor = color;
+ } else if (mIsAboveIcon) {
+ mArrowColor = color;
+ }
+
+ numVisibleChild++;
}
}
measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
}
/**
+ * Sets the background color of the child.
+ */
+ protected void setChildColor(View view, int color) {
+ Drawable bg = view.getBackground();
+ if (bg instanceof GradientDrawable) {
+ ((GradientDrawable) bg.mutate()).setColor(color);
+ } else if (bg instanceof ColorDrawable) {
+ ((ColorDrawable) bg.mutate()).setColor(color);
+ }
+ }
+
+ /**
* Shows the popup at the desired location, optionally reversing the children.
* @param viewsToFlip number of views from the top to to flip in case of reverse order
*/
@@ -228,7 +273,6 @@
}
onInflationComplete(reverseOrder);
assignMarginsAndBackgrounds();
- orientAboutObject();
if (shouldAddArrow()) {
addArrow();
}
@@ -242,7 +286,6 @@
setupForDisplay();
onInflationComplete(false);
assignMarginsAndBackgrounds();
- orientAboutObject();
if (shouldAddArrow()) {
addArrow();
}
@@ -293,7 +336,7 @@
mOutlineRadius, getMeasuredWidth(), getMeasuredHeight(),
mArrowOffsetHorizontal, -mArrowOffsetVertical,
!mIsAboveIcon, mIsLeftAligned,
- Themes.getAttrColor(getContext(), R.attr.popupColorPrimary)));
+ mArrowColor));
mArrow.setElevation(getElevation());
}
@@ -339,10 +382,18 @@
private void orientAboutObject(boolean allowAlignLeft, boolean allowAlignRight) {
measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
- int width = getMeasuredWidth();
int extraVerticalSpace = mArrowHeight + mArrowOffsetVertical
+ getResources().getDimensionPixelSize(R.dimen.popup_vertical_padding);
- int height = getMeasuredHeight() + extraVerticalSpace;
+ // The margins are added after we call this method, so we need to account for them here.
+ int numVisibleChildren = 0;
+ for (int i = getChildCount() - 1; i >= 0; --i) {
+ if (getChildAt(i).getVisibility() == VISIBLE) {
+ numVisibleChildren++;
+ }
+ }
+ int childMargins = (numVisibleChildren - 1) * mMargin;
+ int height = getMeasuredHeight() + extraVerticalSpace + childMargins;
+ int width = getMeasuredWidth();
getTargetObjectLocation(mTempRect);
InsettableFrameLayout dragLayer = getPopupContainer();
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index 4087f49..c282ae8 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -60,6 +60,7 @@
import com.android.launcher3.notification.NotificationInfo;
import com.android.launcher3.notification.NotificationItemView;
import com.android.launcher3.notification.NotificationKeyData;
+import com.android.launcher3.notification.NotificationMainView;
import com.android.launcher3.popup.PopupDataProvider.PopupDataChangeListener;
import com.android.launcher3.shortcuts.DeepShortcutView;
import com.android.launcher3.shortcuts.ShortcutDragPreviewProvider;
@@ -170,6 +171,14 @@
return false;
}
+ @Override
+ protected void setChildColor(View v, int color) {
+ super.setChildColor(v, color);
+ if (v.getId() == R.id.notification_container && mNotificationItemView != null) {
+ mNotificationItemView.updateBackgroundColor(color);
+ }
+ }
+
/**
* Returns true if we can show the container.
*/
@@ -333,19 +342,11 @@
private void updateHiddenShortcuts() {
int allowedCount = mNotificationItemView != null
? MAX_SHORTCUTS_IF_NOTIFICATIONS : MAX_SHORTCUTS;
- int originalHeight = getResources().getDimensionPixelSize(R.dimen.bg_popup_item_height);
- int itemHeight = mNotificationItemView != null ?
- getResources().getDimensionPixelSize(R.dimen.bg_popup_item_condensed_height)
- : originalHeight;
- float iconScale = ((float) itemHeight) / originalHeight;
int total = mShortcuts.size();
for (int i = 0; i < total; i++) {
DeepShortcutView view = mShortcuts.get(i);
view.setVisibility(i >= allowedCount ? GONE : VISIBLE);
- view.getLayoutParams().height = itemHeight;
- view.getIconView().setScaleX(iconScale);
- view.getIconView().setScaleY(iconScale);
}
}
@@ -567,6 +568,7 @@
// No more notifications, remove the notification views and expand all shortcuts.
mNotificationItemView.removeAllViews();
mNotificationItemView = null;
+ mNotificationContainer.setVisibility(GONE);
updateHiddenShortcuts();
assignMarginsAndBackgrounds();
} else {
diff --git a/src/com/android/launcher3/states/HintState.java b/src/com/android/launcher3/states/HintState.java
index fd1d965..eb2c551 100644
--- a/src/com/android/launcher3/states/HintState.java
+++ b/src/com/android/launcher3/states/HintState.java
@@ -53,10 +53,4 @@
public ScaleAndTranslation getWorkspaceScaleAndTranslation(Launcher launcher) {
return new ScaleAndTranslation(0.92f, 0, 0);
}
-
- @Override
- public ScaleAndTranslation getQsbScaleAndTranslation(Launcher launcher) {
- // Treat the QSB as part of the hotseat so they move together.
- return getHotseatScaleAndTranslation(launcher);
- }
}
diff --git a/src/com/android/launcher3/views/ActivityContext.java b/src/com/android/launcher3/views/ActivityContext.java
index 505c6ce..71aa4ac 100644
--- a/src/com/android/launcher3/views/ActivityContext.java
+++ b/src/com/android/launcher3/views/ActivityContext.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.content.ContextWrapper;
import android.graphics.Rect;
+import android.view.LayoutInflater;
import android.view.View.AccessibilityDelegate;
import com.android.launcher3.DeviceProfile;
@@ -67,13 +68,28 @@
}
/**
+ * Returns a LayoutInflater that is cloned in this Context, so that Views inflated by it will
+ * have the same Context. (i.e. {@link #lookupContext(Context)} will find this ActivityContext.)
+ */
+ default LayoutInflater getLayoutInflater() {
+ if (this instanceof Context) {
+ Context context = (Context) this;
+ return LayoutInflater.from(context).cloneInContext(context);
+ }
+ return null;
+ }
+
+ /**
* The root view to support drag-and-drop and popup support.
*/
BaseDragLayer getDragLayer();
DeviceProfile getDeviceProfile();
- static <T extends ActivityContext> T lookupContext(Context context) {
+ /**
+ * Returns the ActivityContext associated with the given Context.
+ */
+ static <T extends Context & ActivityContext> T lookupContext(Context context) {
if (context instanceof ActivityContext) {
return (T) context;
} else if (context instanceof ContextWrapper) {
diff --git a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
index 5c18faf..2e542ed 100644
--- a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Canvas;
+import android.graphics.Outline;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Handler;
@@ -32,12 +33,14 @@
import android.view.View;
import android.view.ViewDebug;
import android.view.ViewGroup;
+import android.view.ViewOutlineProvider;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.AdapterView;
import android.widget.Advanceable;
import android.widget.RemoteViews;
import androidx.annotation.Nullable;
+import androidx.annotation.UiThread;
import com.android.launcher3.CheckLongPressHelper;
import com.android.launcher3.Launcher;
@@ -95,6 +98,18 @@
private final Rect mWidgetSizeAtDrag = new Rect();
private final RectF mTempRectF = new RectF();
private final boolean mIsRtl;
+ private final Rect mEnforcedRectangle = new Rect();
+ private final float mEnforcedCornerRadius;
+ private final ViewOutlineProvider mCornerRadiusEnforcementOutline = new ViewOutlineProvider() {
+ @Override
+ public void getOutline(View view, Outline outline) {
+ if (mEnforcedRectangle.isEmpty() || mEnforcedCornerRadius <= 0) {
+ outline.setEmpty();
+ } else {
+ outline.setRoundRect(mEnforcedRectangle, mEnforcedCornerRadius);
+ }
+ }
+ };
public LauncherAppWidgetHostView(Context context) {
super(context);
@@ -112,6 +127,8 @@
mIsRtl = Utilities.isRtl(context.getResources());
mColorExtractor = LocalColorExtractor.newInstance(getContext());
mColorExtractor.setListener(this);
+
+ mEnforcedCornerRadius = RoundedCornerEnforcement.computeEnforcedRadius(getContext());
}
@Override
@@ -169,7 +186,7 @@
if (viewGroup instanceof AdapterView) {
return true;
} else {
- for (int i=0; i < viewGroup.getChildCount(); i++) {
+ for (int i = 0; i < viewGroup.getChildCount(); i++) {
View child = viewGroup.getChildAt(i);
if (child instanceof ViewGroup) {
if (checkScrollableRecursively((ViewGroup) child)) {
@@ -272,6 +289,8 @@
int pageId = mWorkspace.getPageIndexForScreenId(info.screenId);
updateColorExtraction(mCurrentWidgetSize, pageId);
}
+
+ enforceRoundedCorners();
}
/** Starts the drag mode. */
@@ -469,4 +488,39 @@
}
return false;
}
+
+ @UiThread
+ private void resetRoundedCorners() {
+ setOutlineProvider(ViewOutlineProvider.BACKGROUND);
+ setClipToOutline(false);
+ }
+
+ @UiThread
+ private void enforceRoundedCorners() {
+ if (mEnforcedCornerRadius <= 0 || !RoundedCornerEnforcement.isRoundedCornerEnabled(this)) {
+ resetRoundedCorners();
+ return;
+ }
+ View background = RoundedCornerEnforcement.findBackground(this);
+ if (RoundedCornerEnforcement.hasAppWidgetOptedOut(this, background)) {
+ resetRoundedCorners();
+ return;
+ }
+ RoundedCornerEnforcement.computeRoundedRectangle(this,
+ background,
+ mEnforcedRectangle);
+ setOutlineProvider(mCornerRadiusEnforcementOutline);
+ setClipToOutline(true);
+ }
+
+ /** Returns the corner radius currently enforced, in pixels. */
+ public float getEnforcedCornerRadius() {
+ return mEnforcedCornerRadius;
+ }
+
+ /** Returns true if the corner radius are enforced for this App Widget. */
+ public boolean hasEnforcedCornerRadius() {
+ return getClipToOutline();
+ }
+
}
diff --git a/src/com/android/launcher3/widget/RoundedCornerEnforcement.java b/src/com/android/launcher3/widget/RoundedCornerEnforcement.java
new file mode 100644
index 0000000..99eccd1
--- /dev/null
+++ b/src/com/android/launcher3/widget/RoundedCornerEnforcement.java
@@ -0,0 +1,170 @@
+/*
+ * 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;
+
+import android.appwidget.AppWidgetHostView;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Rect;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.IdRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.config.FeatureFlags;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Utilities to compute the enforced the use of rounded corners on App Widgets.
+ */
+public class RoundedCornerEnforcement {
+ // This class is only a namespace and not meant to be instantiated.
+ private RoundedCornerEnforcement() {
+ }
+
+ /**
+ * Find the background view for a widget.
+ *
+ * @param appWidget the view containing the App Widget (typically the instance of
+ * {@link AppWidgetHostView}).
+ */
+ @Nullable
+ public static View findBackground(@NonNull View appWidget) {
+ List<View> backgrounds = findViewsWithId(appWidget, android.R.id.background);
+ if (backgrounds.size() == 1) {
+ return backgrounds.get(0);
+ }
+ // Really, the argument should contain the widget, so it cannot be the background.
+ if (appWidget instanceof ViewGroup) {
+ ViewGroup vg = (ViewGroup) appWidget;
+ if (vg.getChildCount() > 0) {
+ return findUndefinedBackground(vg.getChildAt(0));
+ }
+ }
+ return appWidget;
+ }
+
+ /**
+ * Check whether the app widget has opted out of the enforcement.
+ */
+ public static boolean hasAppWidgetOptedOut(@NonNull View appWidget, @NonNull View background) {
+ return background.getId() == android.R.id.background && background.getClipToOutline();
+ }
+
+ /** Check if the app widget is in the deny list. */
+ public static boolean isRoundedCornerEnabled(@NonNull View view) {
+ if (!Utilities.ATLEAST_S || !FeatureFlags.ENABLE_ENFORCED_ROUNDED_CORNERS.get()) {
+ return false;
+ }
+ // Here we need to test if the view's component is in the (to be created) deny list.
+ return true;
+ }
+
+ /**
+ * Computes the rounded rectangle needed for this app widget.
+ *
+ * @param appWidget View onto which the rounded rectangle will be applied.
+ * @param background Background view. This must be either {@code appWidget} or a descendant
+ * of {@code appWidget}.
+ * @param outRect Rectangle set to the rounded rectangle coordinates, in the reference frame
+ * of {@code appWidget}.
+ */
+ public static void computeRoundedRectangle(@NonNull View appWidget, @NonNull View background,
+ @NonNull Rect outRect) {
+ outRect.left = 0;
+ outRect.right = background.getWidth();
+ outRect.top = 0;
+ outRect.bottom = background.getHeight();
+ while (background != appWidget) {
+ outRect.offset(background.getLeft(), background.getTop());
+ background = (View) background.getParent();
+ }
+ }
+
+ /**
+ * Computes the radius of the rounded rectangle that should be applied to a widget expanded
+ * in the given context.
+ */
+ public static float computeEnforcedRadius(@NonNull Context context) {
+ if (!Utilities.ATLEAST_S) {
+ return 0;
+ }
+ Resources res = context.getResources();
+ float systemRadius = res.getDimension(android.R.dimen.system_app_widget_background_radius);
+ float defaultRadius = res.getDimension(R.dimen.enforced_rounded_corner_max_radius);
+ return Math.min(defaultRadius, systemRadius);
+ }
+
+ private static List<View> findViewsWithId(View view, @IdRes int viewId) {
+ List<View> output = new ArrayList<>();
+ accumulateViewsWithId(view, viewId, output);
+ return output;
+ }
+
+ // Traverse views. If the predicate returns true, continue on the children, otherwise, don't.
+ private static void accumulateViewsWithId(View view, @IdRes int viewId, List<View> output) {
+ if (view.getId() == viewId) {
+ output.add(view);
+ return;
+ }
+ if (view instanceof ViewGroup) {
+ ViewGroup vg = (ViewGroup) view;
+ for (int i = 0; i < vg.getChildCount(); i++) {
+ accumulateViewsWithId(vg.getChildAt(i), viewId, output);
+ }
+ }
+ }
+
+ private static boolean isViewVisible(View view) {
+ if (view.getVisibility() != View.VISIBLE) {
+ return false;
+ }
+ return !view.willNotDraw() || view.getForeground() != null || view.getBackground() != null;
+ }
+
+ @Nullable
+ private static View findUndefinedBackground(View current) {
+ if (current.getVisibility() != View.VISIBLE) {
+ return null;
+ }
+ if (isViewVisible(current)) {
+ return current;
+ }
+ View lastVisibleView = null;
+ // Find the first view that is either not a ViewGroup, or a ViewGroup which will draw
+ // something, or a ViewGroup that contains more than one view.
+ if (current instanceof ViewGroup) {
+ ViewGroup vg = (ViewGroup) current;
+ for (int i = 0; i < vg.getChildCount(); i++) {
+ View visibleView = findUndefinedBackground(vg.getChildAt(i));
+ if (visibleView != null) {
+ if (lastVisibleView != null) {
+ return current; // At least two visible children
+ }
+ lastVisibleView = visibleView;
+ }
+ }
+ }
+ return lastVisibleView;
+ }
+}
diff --git a/src/com/android/launcher3/widget/WidgetCell.java b/src/com/android/launcher3/widget/WidgetCell.java
index 5328041..1b0e1ce 100644
--- a/src/com/android/launcher3/widget/WidgetCell.java
+++ b/src/com/android/launcher3/widget/WidgetCell.java
@@ -74,6 +74,7 @@
protected int mPreviewHeight;
protected int mPresetPreviewSize;
private int mCellSize;
+ private float mPreviewScale = 1f;
private WidgetImageView mWidgetImage;
private TextView mWidgetName;
@@ -254,8 +255,8 @@
}
if (drawable != null) {
LayoutParams layoutParams = (LayoutParams) mWidgetImage.getLayoutParams();
- layoutParams.width = drawable.getIntrinsicWidth();
- layoutParams.height = drawable.getIntrinsicHeight();
+ layoutParams.width = (int) (drawable.getIntrinsicWidth() * mPreviewScale);
+ layoutParams.height = (int) (drawable.getIntrinsicHeight() * mPreviewScale);
mWidgetImage.setLayoutParams(layoutParams);
mWidgetImage.setDrawable(drawable, mWidgetPreviewLoader.getBadgeForUser(mItem.user,
@@ -305,10 +306,16 @@
/** Sets the widget preview image size in number of cells. */
public void setPreviewSize(int spanX, int spanY) {
+ setPreviewSize(spanX, spanY, 1f);
+ }
+
+ /** Sets the widget preview image size, in number of cells, and preview scale. */
+ public void setPreviewSize(int spanX, int spanY, float previewScale) {
int padding = 2 * getResources()
.getDimensionPixelSize(R.dimen.widget_preview_shortcut_padding);
mPreviewWidth = mDeviceProfile.cellWidthPx * spanX + padding;
mPreviewHeight = mDeviceProfile.cellHeightPx * spanY + padding;
+ mPreviewScale = previewScale;
}
@Override
diff --git a/src/com/android/launcher3/widget/WidgetsBottomSheet.java b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
index e6d54a9..2fda86c 100644
--- a/src/com/android/launcher3/widget/WidgetsBottomSheet.java
+++ b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
@@ -119,8 +119,7 @@
public void populateAndShow(ItemInfo itemInfo) {
mOriginalItemInfo = itemInfo;
- ((TextView) findViewById(R.id.title)).setText(getContext().getString(
- R.string.widgets_bottom_sheet_title, mOriginalItemInfo.title));
+ ((TextView) findViewById(R.id.title)).setText(mOriginalItemInfo.title);
onWidgetsBound();
attachToContainer();
@@ -140,7 +139,7 @@
WidgetsTableUtils.groupWidgetItemsIntoTable(widgets, mMaxHorizontalSpan).forEach(row -> {
TableRow tableRow = new TableRow(getContext());
- tableRow.setGravity(Gravity.CENTER_VERTICAL);
+ tableRow.setGravity(Gravity.TOP);
row.forEach(widgetItem -> {
WidgetCell widget = addItemCell(tableRow);
widget.setPreviewSize(widgetItem.spanX, widgetItem.spanY);
diff --git a/src/com/android/launcher3/widget/picker/SearchAndRecommendationsScrollController.java b/src/com/android/launcher3/widget/picker/SearchAndRecommendationsScrollController.java
index 7eb5b83..7f84077 100644
--- a/src/com/android/launcher3/widget/picker/SearchAndRecommendationsScrollController.java
+++ b/src/com/android/launcher3/widget/picker/SearchAndRecommendationsScrollController.java
@@ -35,6 +35,7 @@
private final SearchAndRecommendationViewHolder mViewHolder;
private final WidgetsRecyclerView mPrimaryRecyclerView;
private final WidgetsRecyclerView mSearchRecyclerView;
+ private final int mTabsHeight;
// The following are only non null if mHasWorkProfile is true.
@Nullable private final WidgetsRecyclerView mWorkRecyclerView;
@@ -42,10 +43,28 @@
@Nullable private final PersonalWorkPagedView mPrimaryWorkViewPager;
private WidgetsRecyclerView mCurrentRecyclerView;
- private int mMaxCollapsibleHeight = 0;
+
+ /**
+ * The vertical distance, in pixels, until the search is pinned at the top of the screen when
+ * the user scrolls down the recycler view.
+ */
+ private int mCollapsibleHeightForSearch = 0;
+ /**
+ * The vertical distance, in pixels, until the recommendation table disappears from the top of
+ * the screen when the user scrolls down the recycler view.
+ */
+ private int mCollapsibleHeightForRecommendation = 0;
+ /**
+ * The vertical distance, in pixels, until the tabs is pinned at the top of the screen when the
+ * user scrolls down the recycler view.
+ *
+ * <p>Always 0 if there is no work profile.
+ */
+ private int mCollapsibleHeightForTabs = 0;
SearchAndRecommendationsScrollController(
boolean hasWorkProfile,
+ int tabsHeight,
SearchAndRecommendationViewHolder viewHolder,
WidgetsRecyclerView primaryRecyclerView,
@Nullable WidgetsRecyclerView workRecyclerView,
@@ -55,46 +74,63 @@
mHasWorkProfile = hasWorkProfile;
mViewHolder = viewHolder;
mPrimaryRecyclerView = primaryRecyclerView;
+ mCurrentRecyclerView = mPrimaryRecyclerView;
mWorkRecyclerView = workRecyclerView;
mSearchRecyclerView = searchRecyclerView;
mPrimaryWorkTabsView = personalWorkTabsView;
mPrimaryWorkViewPager = primaryWorkViewPager;
mCurrentRecyclerView = mPrimaryRecyclerView;
+ mTabsHeight = tabsHeight;
}
/** Sets the current active {@link WidgetsRecyclerView}. */
public void setCurrentRecyclerView(WidgetsRecyclerView currentRecyclerView) {
mCurrentRecyclerView = currentRecyclerView;
+ mCurrentRecyclerView = currentRecyclerView;
+ mViewHolder.mHeaderTitle.setTranslationY(0);
+ mViewHolder.mRecommendedWidgetsTable.setTranslationY(0);
+ mViewHolder.mSearchBar.setTranslationY(0);
+
+ if (mHasWorkProfile) {
+ mPrimaryWorkTabsView.setTranslationY(0);
+ }
}
/**
* Updates the margin and padding of {@link WidgetsFullSheet} to accumulate collapsible views.
+ *
+ * @return {@code true} if margins or/and padding of views in the search and recommendations
+ * container have been updated.
*/
- public void updateMarginAndPadding() {
- // The maximum vertical distance, in pixels, until the last collapsible element is not
- // visible from the screen when the user scrolls down the recycler view.
- mMaxCollapsibleHeight = mViewHolder.mContainer.getPaddingTop()
- + measureHeightWithVerticalMargins(mViewHolder.mCollapseHandle)
- + measureHeightWithVerticalMargins(mViewHolder.mHeaderTitle);
+ public boolean updateMarginAndPadding() {
+ boolean hasMarginOrPaddingUpdated = false;
+ mCollapsibleHeightForSearch = measureHeightWithVerticalMargins(mViewHolder.mHeaderTitle);
+ mCollapsibleHeightForRecommendation =
+ measureHeightWithVerticalMargins(mViewHolder.mHeaderTitle)
+ + measureHeightWithVerticalMargins(mViewHolder.mCollapseHandle)
+ + measureHeightWithVerticalMargins((View) mViewHolder.mSearchBar)
+ + measureHeightWithVerticalMargins(mViewHolder.mRecommendedWidgetsTable);
int topContainerHeight = measureHeightWithVerticalMargins(mViewHolder.mContainer);
if (mHasWorkProfile) {
+ mCollapsibleHeightForTabs = measureHeightWithVerticalMargins(mViewHolder.mHeaderTitle)
+ + measureHeightWithVerticalMargins(mViewHolder.mRecommendedWidgetsTable);
// In a work profile setup, the full widget sheet contains the following views:
- // ------- -|
- // Widgets -|---> LinearLayout for search & recommendations
- // Search bar -|
- // Personal | Work
+ // ------- (pinned) -|
+ // Widgets (collapsible) -|---> LinearLayout for search & recommendations
+ // Search bar (pinned) -|
+ // Widgets recommendation (collapsible)-|
+ // Personal | Work (pinned)
// View Pager
//
// Views after the search & recommendations are not bound by RelativelyLayout param.
// To position them on the expected location, padding & margin are added to these views
// Tabs should have a padding of the height of the search & recommendations container.
- mPrimaryWorkTabsView.setPadding(
- mPrimaryWorkTabsView.getPaddingLeft(),
- topContainerHeight,
- mPrimaryWorkTabsView.getPaddingRight(),
- mPrimaryWorkTabsView.getPaddingBottom());
+ RelativeLayout.LayoutParams tabsLayoutParams =
+ (RelativeLayout.LayoutParams) mPrimaryWorkTabsView.getLayoutParams();
+ tabsLayoutParams.topMargin = topContainerHeight;
+ mPrimaryWorkTabsView.setLayoutParams(tabsLayoutParams);
// Instead of setting the top offset directly, we split the top offset into two values:
// 1. topOffsetAfterAllViewsCollapsed: this is the top offset after all collapsible
@@ -124,39 +160,52 @@
//
// When the views are first inflated, the sum of topOffsetAfterAllViewsCollapsed and
// mMaxCollapsibleDistance should equal to the top container height.
- int tabsViewActualHeight = measureHeightWithVerticalMargins(mPrimaryWorkTabsView)
- - mPrimaryWorkTabsView.getPaddingTop();
int topOffsetAfterAllViewsCollapsed =
- topContainerHeight + tabsViewActualHeight - mMaxCollapsibleHeight;
+ topContainerHeight + mTabsHeight - mCollapsibleHeightForTabs;
- RelativeLayout.LayoutParams layoutParams =
+ RelativeLayout.LayoutParams viewPagerLayoutParams =
(RelativeLayout.LayoutParams) mPrimaryWorkViewPager.getLayoutParams();
- layoutParams.setMargins(0, topOffsetAfterAllViewsCollapsed, 0, 0);
- mPrimaryWorkViewPager.setLayoutParams(layoutParams);
- mPrimaryWorkViewPager.requestLayout();
+ if (viewPagerLayoutParams.topMargin != topOffsetAfterAllViewsCollapsed) {
+ viewPagerLayoutParams.topMargin = topOffsetAfterAllViewsCollapsed;
+ mPrimaryWorkViewPager.setLayoutParams(viewPagerLayoutParams);
+ hasMarginOrPaddingUpdated = true;
+ }
- mPrimaryRecyclerView.setPadding(
- mPrimaryRecyclerView.getPaddingLeft(),
- mMaxCollapsibleHeight,
- mPrimaryRecyclerView.getPaddingRight(),
- mPrimaryRecyclerView.getPaddingBottom());
- mWorkRecyclerView.setPadding(
- mWorkRecyclerView.getPaddingLeft(),
- mMaxCollapsibleHeight,
- mWorkRecyclerView.getPaddingRight(),
- mWorkRecyclerView.getPaddingBottom());
+ if (mPrimaryRecyclerView.getPaddingTop() != mCollapsibleHeightForTabs) {
+ mPrimaryRecyclerView.setPadding(
+ mPrimaryRecyclerView.getPaddingLeft(),
+ mCollapsibleHeightForTabs,
+ mPrimaryRecyclerView.getPaddingRight(),
+ mPrimaryRecyclerView.getPaddingBottom());
+ hasMarginOrPaddingUpdated = true;
+ }
+ if (mWorkRecyclerView.getPaddingTop() != mCollapsibleHeightForTabs) {
+ mWorkRecyclerView.setPadding(
+ mWorkRecyclerView.getPaddingLeft(),
+ mCollapsibleHeightForTabs,
+ mWorkRecyclerView.getPaddingRight(),
+ mWorkRecyclerView.getPaddingBottom());
+ hasMarginOrPaddingUpdated = true;
+ }
} else {
- mPrimaryRecyclerView.setPadding(
- mPrimaryRecyclerView.getPaddingLeft(),
- topContainerHeight,
- mPrimaryRecyclerView.getPaddingRight(),
- mPrimaryRecyclerView.getPaddingBottom());
+ if (mPrimaryRecyclerView.getPaddingTop() != topContainerHeight) {
+ mPrimaryRecyclerView.setPadding(
+ mPrimaryRecyclerView.getPaddingLeft(),
+ topContainerHeight,
+ mPrimaryRecyclerView.getPaddingRight(),
+ mPrimaryRecyclerView.getPaddingBottom());
+ hasMarginOrPaddingUpdated = true;
+ }
}
- mSearchRecyclerView.setPadding(
- mSearchRecyclerView.getPaddingLeft(),
- topContainerHeight,
- mSearchRecyclerView.getPaddingRight(),
- mSearchRecyclerView.getPaddingBottom());
+ if (mSearchRecyclerView.getPaddingTop() != topContainerHeight) {
+ mSearchRecyclerView.setPadding(
+ mSearchRecyclerView.getPaddingLeft(),
+ topContainerHeight,
+ mSearchRecyclerView.getPaddingRight(),
+ mSearchRecyclerView.getPaddingBottom());
+ hasMarginOrPaddingUpdated = true;
+ }
+ return hasMarginOrPaddingUpdated;
}
/**
@@ -168,13 +217,22 @@
// Always use the recycler view offset because fast scroller offset has a different scale.
int recyclerViewYOffset = mCurrentRecyclerView.getCurrentScrollY();
if (recyclerViewYOffset < 0) return;
- if (mMaxCollapsibleHeight > 0) {
- int yDisplacement = Math.max(-recyclerViewYOffset, -mMaxCollapsibleHeight);
+
+ if (mCollapsibleHeightForRecommendation > 0) {
+ int yDisplacement = Math.max(-recyclerViewYOffset,
+ -mCollapsibleHeightForRecommendation);
mViewHolder.mHeaderTitle.setTranslationY(yDisplacement);
- mViewHolder.mSearchBar.setTranslationY(yDisplacement);
- if (mHasWorkProfile) {
- mPrimaryWorkTabsView.setTranslationY(yDisplacement);
- }
+ mViewHolder.mRecommendedWidgetsTable.setTranslationY(yDisplacement);
+ }
+
+ if (mCollapsibleHeightForSearch > 0) {
+ int searchYDisplacement = Math.max(-recyclerViewYOffset, -mCollapsibleHeightForSearch);
+ mViewHolder.mSearchBar.setTranslationY(searchYDisplacement);
+ }
+
+ if (mHasWorkProfile && mCollapsibleHeightForTabs > 0) {
+ int yDisplacementForTabs = Math.max(-recyclerViewYOffset, -mCollapsibleHeightForTabs);
+ mPrimaryWorkTabsView.setTranslationY(yDisplacementForTabs);
}
}
@@ -189,6 +247,9 @@
/** private the height, in pixel, + the vertical margins of a given view. */
private static int measureHeightWithVerticalMargins(View view) {
+ if (view.getVisibility() != View.VISIBLE) {
+ return 0;
+ }
MarginLayoutParams marginLayoutParams = (MarginLayoutParams) view.getLayoutParams();
return view.getMeasuredHeight() + marginLayoutParams.bottomMargin
+ marginLayoutParams.topMargin;
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index dc375ca..f43f712 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -33,6 +33,7 @@
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
+import android.view.ViewGroup;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.widget.TextView;
@@ -48,6 +49,7 @@
import com.android.launcher3.R;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.compat.AccessibilityManagerCompat;
+import com.android.launcher3.model.WidgetItem;
import com.android.launcher3.views.RecyclerViewFastScroller;
import com.android.launcher3.views.TopRoundedCornerView;
import com.android.launcher3.widget.BaseWidgetSheet;
@@ -55,6 +57,7 @@
import com.android.launcher3.widget.model.WidgetsListBaseEntry;
import com.android.launcher3.widget.picker.search.SearchModeListener;
import com.android.launcher3.widget.picker.search.WidgetsSearchBar;
+import com.android.launcher3.widget.util.WidgetsTableUtils;
import com.android.launcher3.workprofile.PersonalWorkPagedView;
import com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip.OnActivePageChangedListener;
@@ -68,10 +71,15 @@
public class WidgetsFullSheet extends BaseWidgetSheet
implements Insettable, ProviderChangedListener, OnActivePageChangedListener,
WidgetsRecyclerView.HeaderViewDimensionsProvider, SearchModeListener {
+ private static final String TAG = WidgetsFullSheet.class.getSimpleName();
private static final long DEFAULT_OPEN_DURATION = 267;
private static final long FADE_IN_DURATION = 150;
private static final float VERTICAL_START_POSITION = 0.3f;
+ // 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.
+ private static final float RECOMMENDATION_TABLE_HEIGHT_RATIO = 0.75f;
private final Rect mInsets = new Rect();
private final boolean mHasWorkProfile;
@@ -81,10 +89,12 @@
mCurrentUser.equals(entry.mPkgItem.user);
private final Predicate<WidgetsListBaseEntry> mWorkWidgetsFilter =
mPrimaryWidgetsFilter.negate();
+ private final int mTabsHeight;
+ private final int mWidgetCellHorizontalPadding;
@Nullable private PersonalWorkPagedView mViewPager;
- private int mInitialTabsHeight = 0;
private boolean mIsInSearchMode;
+ private int mMaxSpansPerRow = 4;
private View mTabsView;
private TextView mNoWidgetsView;
private SearchAndRecommendationViewHolder mSearchAndRecommendationViewHolder;
@@ -96,6 +106,12 @@
mAdapters.put(AdapterHolder.PRIMARY, new AdapterHolder(AdapterHolder.PRIMARY));
mAdapters.put(AdapterHolder.WORK, new AdapterHolder(AdapterHolder.WORK));
mAdapters.put(AdapterHolder.SEARCH, new AdapterHolder(AdapterHolder.SEARCH));
+ mTabsHeight = mHasWorkProfile
+ ? getContext().getResources()
+ .getDimensionPixelSize(R.dimen.all_apps_header_tab_height)
+ : 0;
+ mWidgetCellHorizontalPadding = 2 * getResources().getDimensionPixelOffset(
+ R.dimen.widget_cell_horizontal_padding);
}
public WidgetsFullSheet(Context context, AttributeSet attrs) {
@@ -140,6 +156,7 @@
findViewById(R.id.search_and_recommendations_container));
mSearchAndRecommendationsScrollController = new SearchAndRecommendationsScrollController(
mHasWorkProfile,
+ mTabsHeight,
mSearchAndRecommendationViewHolder,
findViewById(R.id.primary_widgets_list_view),
mHasWorkProfile ? findViewById(R.id.work_widgets_list_view) : null,
@@ -150,6 +167,7 @@
mNoWidgetsView = findViewById(R.id.no_widgets_text);
+ onRecommendedWidgetsBound();
onWidgetsBound();
mSearchAndRecommendationViewHolder.mSearchBar.initialize(
@@ -257,6 +275,22 @@
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ doMeasure(widthMeasureSpec, heightMeasureSpec);
+
+ if (mSearchAndRecommendationsScrollController.updateMarginAndPadding()) {
+ doMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+
+ if (updateMaxSpansPerRow()) {
+ doMeasure(widthMeasureSpec, heightMeasureSpec);
+
+ if (mSearchAndRecommendationsScrollController.updateMarginAndPadding()) {
+ doMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+ }
+ }
+
+ private void doMeasure(int widthMeasureSpec, int heightMeasureSpec) {
DeviceProfile deviceProfile = mLauncher.getDeviceProfile();
int widthUsed;
if (mInsets.bottom > 0) {
@@ -272,24 +306,29 @@
widthUsed, heightMeasureSpec, heightUsed);
setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec),
MeasureSpec.getSize(heightMeasureSpec));
+ }
- int paddingPx = 2 * getResources().getDimensionPixelOffset(
- R.dimen.widget_cell_horizontal_padding);
- int maxSpansPerRow = getMeasuredWidth() / (deviceProfile.cellWidthPx + paddingPx);
- mAdapters.get(AdapterHolder.PRIMARY).mWidgetsListAdapter.setMaxHorizontalSpansPerRow(
- maxSpansPerRow);
- mAdapters.get(AdapterHolder.SEARCH).mWidgetsListAdapter.setMaxHorizontalSpansPerRow(
- maxSpansPerRow);
- if (mHasWorkProfile) {
- mAdapters.get(AdapterHolder.WORK).mWidgetsListAdapter.setMaxHorizontalSpansPerRow(
- maxSpansPerRow);
+ /** Returns {@code true} if the max spans have been updated. */
+ private boolean updateMaxSpansPerRow() {
+ if (getMeasuredWidth() == 0) return false;
+
+ int previousMaxSpansPerRow = mMaxSpansPerRow;
+ mMaxSpansPerRow = getMeasuredWidth()
+ / (mLauncher.getDeviceProfile().cellWidthPx + mWidgetCellHorizontalPadding);
+
+ if (previousMaxSpansPerRow != mMaxSpansPerRow) {
+ mAdapters.get(AdapterHolder.PRIMARY).mWidgetsListAdapter.setMaxHorizontalSpansPerRow(
+ mMaxSpansPerRow);
+ mAdapters.get(AdapterHolder.SEARCH).mWidgetsListAdapter.setMaxHorizontalSpansPerRow(
+ mMaxSpansPerRow);
+ if (mHasWorkProfile) {
+ mAdapters.get(AdapterHolder.WORK).mWidgetsListAdapter.setMaxHorizontalSpansPerRow(
+ mMaxSpansPerRow);
+ }
+ onRecommendedWidgetsBound();
+ return true;
}
-
- if (mInitialTabsHeight == 0 && mTabsView != null) {
- mInitialTabsHeight = measureHeightWithVerticalMargins(mTabsView);
- }
-
- mSearchAndRecommendationsScrollController.updateMarginAndPadding();
+ return false;
}
@Override
@@ -346,6 +385,8 @@
mViewPager.snapToPage(AdapterHolder.PRIMARY);
}
attachScrollbarToRecyclerView(mAdapters.get(AdapterHolder.PRIMARY).mWidgetsRecyclerView);
+
+ mSearchAndRecommendationsScrollController.updateMarginAndPadding();
}
@Override
@@ -357,6 +398,8 @@
private void setViewVisibilityBasedOnSearch(boolean isInSearchMode) {
mIsInSearchMode = isInSearchMode;
+ mSearchAndRecommendationViewHolder.mRecommendedWidgetsTable
+ .setVisibility(isInSearchMode ? GONE : VISIBLE);
if (mHasWorkProfile) {
mViewPager.setVisibility(isInSearchMode ? GONE : VISIBLE);
mTabsView.setVisibility(isInSearchMode ? GONE : VISIBLE);
@@ -374,6 +417,25 @@
mAdapters.get(AdapterHolder.WORK).mWidgetsListAdapter.resetExpandedHeader();
}
+ @Override
+ public void onRecommendedWidgetsBound() {
+ List<WidgetItem> recommendedWidgets =
+ mLauncher.getPopupDataProvider().getRecommendedWidgets();
+ WidgetsRecommendationTableLayout table =
+ mSearchAndRecommendationViewHolder.mRecommendedWidgetsTable;
+ if (recommendedWidgets.size() > 0) {
+ float maxTableHeight =
+ (mLauncher.getDeviceProfile().heightPx - mTabsHeight - getHeaderViewHeight())
+ * RECOMMENDATION_TABLE_HEIGHT_RATIO;
+ List<ArrayList<WidgetItem>> recommendedWidgetsInTable =
+ WidgetsTableUtils.groupWidgetItemsIntoTable(recommendedWidgets,
+ mMaxSpansPerRow);
+ table.setRecommendedWidgets(recommendedWidgetsInTable, maxTableHeight);
+ } else {
+ table.setVisibility(GONE);
+ }
+ }
+
private void open(boolean animate) {
if (animate) {
if (getPopupContainer().getInsets().bottom > 0) {
@@ -515,6 +577,7 @@
apps.getIconCache(),
/* iconClickListener= */ WidgetsFullSheet.this,
/* iconLongClickListener= */ WidgetsFullSheet.this);
+ mWidgetsListAdapter.setHasStableIds(true);
switch (mAdapterType) {
case PRIMARY:
mWidgetsListAdapter.setFilter(mPrimaryWidgetsFilter);
@@ -530,24 +593,35 @@
void setup(WidgetsRecyclerView recyclerView) {
mWidgetsRecyclerView = recyclerView;
mWidgetsRecyclerView.setAdapter(mWidgetsListAdapter);
+ // Disables animation because it disrupts the item focus upon adapter item change.
+ mWidgetsRecyclerView.setItemAnimator(null);
mWidgetsRecyclerView.setHeaderViewDimensionsProvider(WidgetsFullSheet.this);
mWidgetsRecyclerView.setEdgeEffectFactory(
((TopRoundedCornerView) mContent).createEdgeEffectFactory());
mWidgetsListAdapter.setApplyBitmapDeferred(false, mWidgetsRecyclerView);
+ mWidgetsListAdapter.setMaxHorizontalSpansPerRow(mMaxSpansPerRow);
}
}
final class SearchAndRecommendationViewHolder {
- final View mContainer;
+ final ViewGroup mContainer;
final View mCollapseHandle;
final WidgetsSearchBar mSearchBar;
final TextView mHeaderTitle;
+ final WidgetsRecommendationTableLayout mRecommendedWidgetsTable;
- SearchAndRecommendationViewHolder(View searchAndRecommendationContainer) {
+ SearchAndRecommendationViewHolder(ViewGroup searchAndRecommendationContainer) {
mContainer = searchAndRecommendationContainer;
mCollapseHandle = mContainer.findViewById(R.id.collapse_handle);
mSearchBar = mContainer.findViewById(R.id.widgets_search_bar);
mHeaderTitle = mContainer.findViewById(R.id.title);
+ mRecommendedWidgetsTable = mContainer.findViewById(R.id.recommended_widget_table);
+ mRecommendedWidgetsTable.setWidgetCellOnTouchListener((view, event) -> {
+ getRecyclerView().onTouchEvent(event);
+ return false;
+ });
+ mRecommendedWidgetsTable.setWidgetCellLongClickListener(WidgetsFullSheet.this);
+ mRecommendedWidgetsTable.setWidgetCellOnClickListener(WidgetsFullSheet.this);
}
}
}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java b/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java
index cab1e02..d841c64 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java
@@ -43,6 +43,7 @@
import com.android.launcher3.widget.model.WidgetsListSearchHeaderEntry;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.function.Predicate;
@@ -216,7 +217,9 @@
@Override
public long getItemId(int pos) {
- return pos;
+ return Arrays.hashCode(new Object[]{
+ mVisibleEntries.get(pos).mPkgItem.hashCode(),
+ getItemViewType(pos)});
}
@Override
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinder.java b/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinder.java
index f126321..e57f4d8 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinder.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinder.java
@@ -52,7 +52,9 @@
public void bindViewHolder(WidgetsListHeaderHolder viewHolder, WidgetsListHeaderEntry data,
int position) {
WidgetsListHeader widgetsListHeader = viewHolder.mWidgetsListHeader;
- if (position == 0) {
+ if (mWidgetsListAdapter.getItemCount() == 1) {
+ widgetsListHeader.setBackgroundResource(R.drawable.widgets_list_single_item_ripple);
+ } else if (position == 0) {
widgetsListHeader.setBackgroundResource(R.drawable.widgets_list_top_ripple);
} else if (position == mWidgetsListAdapter.getItemCount() - 1) {
widgetsListHeader.setBackgroundResource(R.drawable.widgets_list_bottom_ripple);
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderViewHolderBinder.java b/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderViewHolderBinder.java
index 37713e1..b98f5e1 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderViewHolderBinder.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderViewHolderBinder.java
@@ -53,7 +53,9 @@
public void bindViewHolder(WidgetsListSearchHeaderHolder viewHolder,
WidgetsListSearchHeaderEntry data, int position) {
WidgetsListHeader widgetsListHeader = viewHolder.mWidgetsListHeader;
- if (position == 0) {
+ if (mWidgetsListAdapter.getItemCount() == 1) {
+ widgetsListHeader.setBackgroundResource(R.drawable.widgets_list_single_item_ripple);
+ } else if (position == 0) {
widgetsListHeader.setBackgroundResource(R.drawable.widgets_list_top_ripple);
} else if (position == mWidgetsListAdapter.getItemCount() - 1) {
widgetsListHeader.setBackgroundResource(R.drawable.widgets_list_bottom_ripple);
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java b/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
index d0be35d..c1d64b1 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
@@ -158,7 +158,7 @@
tableRow = (TableRow) table.getChildAt(i);
} else {
tableRow = new TableRow(table.getContext());
- tableRow.setGravity(Gravity.CENTER_VERTICAL);
+ tableRow.setGravity(Gravity.TOP);
table.addView(tableRow);
}
if (tableRow.getChildCount() > widgetItems.size()) {
diff --git a/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java b/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java
new file mode 100644
index 0000000..6569fb0
--- /dev/null
+++ b/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java
@@ -0,0 +1,175 @@
+/*
+ * 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.content.Context;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+import android.widget.TableLayout;
+import android.widget.TableRow;
+
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAppState;
+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 final DeviceProfile mDeviceProfile;
+ private final float mWidgetCellTextViewsHeight;
+
+ private float mRecommendationTableMaxHeight = Float.MAX_VALUE;
+ @Nullable private OnLongClickListener mWidgetCellOnLongClickListener;
+ @Nullable private OnClickListener mWidgetCellOnClickListener;
+ @Nullable private OnTouchListener mWidgetCellOnTouchListener;
+
+ public WidgetsRecommendationTableLayout(Context context) {
+ this(context, /* attrs= */ null);
+ }
+
+ public WidgetsRecommendationTableLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mDeviceProfile = Launcher.getLauncher(context).getDeviceProfile();
+ // There are 1 row for title, 1 row for dimension and 2 rows for description.
+ mWidgetCellTextViewsHeight = 4 * getResources().getDimension(R.dimen.widget_cell_font_size);
+ }
+
+ /** Sets a {@link android.view.View.OnLongClickListener} for all widget cells in this table. */
+ public void setWidgetCellLongClickListener(OnLongClickListener onLongClickListener) {
+ mWidgetCellOnLongClickListener = onLongClickListener;
+ }
+
+ /** Sets a {@link android.view.View.OnClickListener} for all widget cells in this table. */
+ public void setWidgetCellOnClickListener(OnClickListener widgetCellOnClickListener) {
+ mWidgetCellOnClickListener = widgetCellOnClickListener;
+ }
+
+ /** Sets a {@link android.view.View.OnTouchListener} for all widget cells in this table. */
+ public void setWidgetCellOnTouchListener(OnTouchListener widgetCellOnTouchListener) {
+ mWidgetCellOnTouchListener = widgetCellOnTouchListener;
+ }
+
+ /**
+ * Sets a list of recommended widgets that would like to be displayed in this table within the
+ * desired {@code recommendationTableMaxHeight}.
+ *
+ * <p>If the content can't fit {@code recommendationTableMaxHeight}, this view will remove a
+ * last row from the {@code recommendedWidgets} until it fits or only one row left. If the only
+ * row still doesn't fit, we scale down the preview image.
+ */
+ public void setRecommendedWidgets(List<ArrayList<WidgetItem>> recommendedWidgets,
+ float recommendationTableMaxHeight) {
+ mRecommendationTableMaxHeight = recommendationTableMaxHeight;
+ RecommendationTableData data = fitRecommendedWidgetsToTableSpace(/* previewScale= */ 1f,
+ recommendedWidgets);
+ bindData(data);
+ }
+
+ private void bindData(RecommendationTableData data) {
+ if (data.mRecommendationTable.size() == 0) {
+ setVisibility(GONE);
+ return;
+ }
+
+ removeAllViews();
+
+ for (int i = 0; i < data.mRecommendationTable.size(); i++) {
+ List<WidgetItem> widgetItems = data.mRecommendationTable.get(i);
+ TableRow tableRow = new TableRow(getContext());
+ tableRow.setGravity(Gravity.TOP);
+
+ for (WidgetItem widgetItem : widgetItems) {
+ WidgetCell widgetCell = addItemCell(tableRow);
+ widgetCell.setPreviewSize(widgetItem.spanX, widgetItem.spanY, data.mPreviewScale);
+ widgetCell.applyFromCellItem(widgetItem,
+ LauncherAppState.getInstance(getContext()).getWidgetCache());
+ widgetCell.ensurePreview();
+ }
+ addView(tableRow);
+ }
+ setVisibility(VISIBLE);
+ }
+
+ private WidgetCell addItemCell(ViewGroup parent) {
+ WidgetCell widget = (WidgetCell) LayoutInflater.from(
+ 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);
+ widget.setAnimatePreview(false);
+
+ parent.addView(widget);
+ return widget;
+ }
+
+ private RecommendationTableData fitRecommendedWidgetsToTableSpace(
+ float previewScale,
+ List<ArrayList<WidgetItem>> recommendedWidgetsInTable) {
+ // A naive estimation of the widgets recommendation table height without inflation.
+ float totalHeight = 0;
+ for (int i = 0; i < recommendedWidgetsInTable.size(); i++) {
+ List<WidgetItem> widgetItems = recommendedWidgetsInTable.get(i);
+ float rowHeight = 0;
+ for (int j = 0; j < widgetItems.size(); j++) {
+ float previewHeight = widgetItems.get(j).spanY * mDeviceProfile.allAppsCellHeightPx
+ * previewScale;
+ rowHeight = Math.max(rowHeight, previewHeight + mWidgetCellTextViewsHeight);
+ }
+ totalHeight += rowHeight;
+ }
+
+ if (totalHeight < mRecommendationTableMaxHeight) {
+ return new RecommendationTableData(recommendedWidgetsInTable, previewScale);
+ }
+
+ if (recommendedWidgetsInTable.size() > 1) {
+ // We don't want to scale down widgets preview unless we really need to. Reduce the
+ // num of row by 1 to see if it fits.
+ return fitRecommendedWidgetsToTableSpace(
+ previewScale,
+ recommendedWidgetsInTable.subList(/* fromIndex= */0,
+ /* toIndex= */recommendedWidgetsInTable.size() - 1));
+ }
+
+ float nextPreviewScale = previewScale * SCALE_DOWN_RATIO;
+ return fitRecommendedWidgetsToTableSpace(nextPreviewScale, recommendedWidgetsInTable);
+ }
+
+ /** Data class for the widgets recommendation table and widgets preview scaling. */
+ private class RecommendationTableData {
+ private final List<ArrayList<WidgetItem>> mRecommendationTable;
+ private final float mPreviewScale;
+
+ RecommendationTableData(List<ArrayList<WidgetItem>> recommendationTable,
+ float previewScale) {
+ mRecommendationTable = recommendationTable;
+ mPreviewScale = previewScale;
+ }
+ }
+}
diff --git a/tests/Android.bp b/tests/Android.bp
index 8a73483..da55c28 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -11,6 +11,15 @@
// 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 {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "packages_apps_Launcher3_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["packages_apps_Launcher3_license"],
+}
+
filegroup {
name: "launcher3-test-src-common",
srcs: ["src_common/**/*.java"],
diff --git a/tests/res/layout/test_layout_appwidget_dynamic_colors.xml b/tests/res/layout/test_layout_appwidget_dynamic_colors.xml
index c5ab030..21625c6 100644
--- a/tests/res/layout/test_layout_appwidget_dynamic_colors.xml
+++ b/tests/res/layout/test_layout_appwidget_dynamic_colors.xml
@@ -18,7 +18,7 @@
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
- android:background="@android:color/system_primary_500"/>
+ android:background="@android:color/system_neutral1_500"/>
</LinearLayout>
<LinearLayout
android:orientation = "horizontal"
@@ -32,7 +32,7 @@
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
- android:background="@android:color/system_secondary_500"/>
+ android:background="@android:color/system_accent1_500"/>
</LinearLayout>
<LinearLayout
android:orientation = "horizontal"
@@ -46,7 +46,7 @@
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
- android:background="@android:color/system_neutral_500"/>
+ android:background="@android:color/system_neutral2_500"/>
</LinearLayout>
</LinearLayout>
\ No newline at end of file
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index a7b92b7..7bfe33c 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -1214,7 +1214,7 @@
final MotionEvent event = getMotionEvent(downTime, currentTime, action, point.x, point.y);
assertTrue("injectInputEvent failed",
- mInstrumentation.getUiAutomation().injectInputEvent(event, true));
+ mInstrumentation.getUiAutomation().injectInputEvent(event, true, false));
event.recycle();
}
diff --git a/tests/tapl/com/android/launcher3/tapl/Widgets.java b/tests/tapl/com/android/launcher3/tapl/Widgets.java
index 22f4d31..fe4c712 100644
--- a/tests/tapl/com/android/launcher3/tapl/Widgets.java
+++ b/tests/tapl/com/android/launcher3/tapl/Widgets.java
@@ -30,7 +30,6 @@
import com.android.launcher3.testing.TestProtocol;
import java.util.Collection;
-import java.util.List;
/**
* All widgets container.
@@ -106,7 +105,8 @@
fullWidgetsPicker.wait(Until.scrollable(true), WAIT_TIME_MS));
final Point displaySize = mLauncher.getRealDisplaySize();
- final UiObject2 widgetsContainer = findTestAppWidgetsTableContainer();
+ Rect headerRect = new Rect();
+ final UiObject2 widgetsContainer = findTestAppWidgetsTableContainer(headerRect);
mLauncher.assertTrue("Can't locate widgets list for the test app: "
+ mLauncher.getLauncherPackageName(),
widgetsContainer != null);
@@ -132,7 +132,12 @@
mLauncher.assertTrue("Too many attempts", ++i <= 40);
final int scroll = getWidgetsScroll();
- mLauncher.scrollToLastVisibleRow(fullWidgetsPicker, tableRows, 0);
+ mLauncher.scroll(
+ fullWidgetsPicker,
+ Direction.DOWN,
+ headerRect,
+ 10,
+ true);
final int newScroll = getWidgetsScroll();
mLauncher.assertTrue(
"Scrolled in a wrong direction in Widgets: from " + scroll + " to "
@@ -143,7 +148,7 @@
}
/** Finds the widgets list of this test app from the collapsed full widgets picker. */
- private UiObject2 findTestAppWidgetsTableContainer() {
+ private UiObject2 findTestAppWidgetsTableContainer(Rect outHeaderRect) {
final BySelector headerSelector = By.res(mLauncher.getLauncherPackageName(),
"widgets_list_header");
final BySelector targetAppSelector = By.clazz("android.widget.TextView").text(
@@ -156,6 +161,7 @@
UiObject2 fullWidgetsPicker = verifyActiveContainer();
UiObject2 header = fullWidgetsPicker.findObject(headerSelector);
+ outHeaderRect.set(0, 0, 0, header.getVisibleBounds().height());
mLauncher.assertTrue("Can't find a widget header", header != null);
// Look for a header that has the test app name.
@@ -179,11 +185,14 @@
if (widgetsContainer != null) {
return widgetsContainer;
}
- mLauncher.scrollToLastVisibleRow(fullWidgetsPicker, List.of(headerTitle), 0);
- } else {
- mLauncher.scrollToLastVisibleRow(fullWidgetsPicker, fullWidgetsPicker.getChildren(),
- 0);
+
}
+ mLauncher.scroll(
+ fullWidgetsPicker,
+ Direction.DOWN,
+ outHeaderRect,
+ /* steps= */ 10,
+ /* slowDown= */ true);
}
return null;