Merge "Update gesture nav colors and animation for dark/light theming" into sc-dev
diff --git a/quickstep/res/drawable/bg_wellbeing_toast.xml b/quickstep/res/drawable/bg_wellbeing_toast.xml
index 65730f6..4dc981f 100644
--- a/quickstep/res/drawable/bg_wellbeing_toast.xml
+++ b/quickstep/res/drawable/bg_wellbeing_toast.xml
@@ -13,7 +13,9 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
- <solid android:color="#E61A73E8" />
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:priv-android="http://schemas.android.com/apk/prv/res/android"
+ android:shape="rectangle">
+ <solid android:color="?priv-android:attr/colorAccentPrimary" />
<corners android:radius="?android:attr/dialogCornerRadius" />
</shape>
\ No newline at end of file
diff --git a/quickstep/res/layout/digital_wellbeing_toast.xml b/quickstep/res/layout/digital_wellbeing_toast.xml
index 83594e4..c4642e4 100644
--- a/quickstep/res/layout/digital_wellbeing_toast.xml
+++ b/quickstep/res/layout/digital_wellbeing_toast.xml
@@ -16,12 +16,13 @@
-->
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:priv-android="http://schemas.android.com/apk/prv/res/android"
+ style="@style/TextTitle"
android:layout_width="match_parent"
android:layout_height="48dp"
android:background="@drawable/bg_wellbeing_toast"
- android:fontFamily="sans-serif"
android:forceHasOverlappingRendering="false"
android:gravity="center"
android:importantForAccessibility="noHideDescendants"
- android:textColor="@android:color/white"
+ android:textColor="?priv-android:attr/textColorOnAccent"
android:textSize="14sp"/>
\ No newline at end of file
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 1c7242d..342313d 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -76,6 +76,7 @@
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.UserHandle;
+import android.os.VibrationEffect;
import android.text.Layout;
import android.text.StaticLayout;
import android.text.TextPaint;
@@ -132,6 +133,7 @@
import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
import com.android.launcher3.util.Themes;
import com.android.launcher3.util.TranslateEdgeEffect;
+import com.android.launcher3.util.VibratorWrapper;
import com.android.launcher3.util.ViewPool;
import com.android.quickstep.AnimatedFloat;
import com.android.quickstep.BaseActivityInterface;
@@ -342,6 +344,17 @@
private static final float INITIAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET = 0.55f;
private static final float ADDITIONAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET = 0.05f;
+ private static final int SNAP_TO_PAGE_VIBRATION_PRIMITIVE =
+ Utilities.ATLEAST_S ? VibrationEffect.Composition.PRIMITIVE_LOW_TICK : -1;
+ private static final float SNAP_TO_PAGE_VIBRATION_PRIMITIVE_SCALE = 0.4f;
+ private static final VibrationEffect SNAP_TO_PAGE_VIBRATION_FALLBACK =
+ VibrationEffect.createPredefined(VibrationEffect.EFFECT_TEXTURE_TICK);
+ private static final int EDGE_IMPACT_VIBRATION_PRIMITIVE =
+ Utilities.ATLEAST_R ? VibrationEffect.Composition.PRIMITIVE_TICK : -1;
+ private static final float EDGE_IMPACT_VIBRATION_PRIMITIVE_SCALE = 0.8f;
+ private static final VibrationEffect EDGE_IMPACT_VIBRATION_FALLBACK =
+ VibrationEffect.createPredefined(VibrationEffect.EFFECT_TICK);
+
protected final RecentsOrientedState mOrientationState;
protected final BaseActivityInterface<STATE_TYPE, ACTIVITY_TYPE> mSizeStrategy;
protected RecentsAnimationController mRecentsAnimationController;
@@ -960,6 +973,8 @@
@Override
protected void onPageEndTransition() {
super.onPageEndTransition();
+ VibratorWrapper.INSTANCE.get(mContext).vibrate(SNAP_TO_PAGE_VIBRATION_PRIMITIVE,
+ SNAP_TO_PAGE_VIBRATION_PRIMITIVE_SCALE, SNAP_TO_PAGE_VIBRATION_FALLBACK);
if (isClearAllHidden()) {
mActionsView.updateDisabledFlags(OverviewActionsView.DISABLED_SCROLLING, false);
}
@@ -1063,6 +1078,13 @@
}
@Override
+ protected void onEdgeAbsorbingScroll() {
+ super.onEdgeAbsorbingScroll();
+ VibratorWrapper.INSTANCE.get(mContext).vibrate(EDGE_IMPACT_VIBRATION_PRIMITIVE,
+ EDGE_IMPACT_VIBRATION_PRIMITIVE_SCALE, EDGE_IMPACT_VIBRATION_FALLBACK);
+ }
+
+ @Override
protected void determineScrollingStart(MotionEvent ev, float touchSlopScale) {
// Enables swiping to the left or right only if the task overlay is not modal.
if (!isModal()) {
diff --git a/robolectric_tests/src/com/android/launcher3/widget/picker/util/WidgetsTableUtilsTest.java b/robolectric_tests/src/com/android/launcher3/widget/picker/util/WidgetsTableUtilsTest.java
index e68edd3..56d7d68 100644
--- a/robolectric_tests/src/com/android/launcher3/widget/picker/util/WidgetsTableUtilsTest.java
+++ b/robolectric_tests/src/com/android/launcher3/widget/picker/util/WidgetsTableUtilsTest.java
@@ -96,12 +96,12 @@
List<ArrayList<WidgetItem>> widgetItemInTable = WidgetsTableUtils.groupWidgetItemsIntoTable(
widgetItems, /* maxSpansPerRow= */ 5);
- // Row 0: 1x1, 2x2, 2x3
- // Row 1: 2x4
+ // Row 0: 1x1, 2x2
+ // Row 1: 2x3, 2x4
// Row 2: 4x4
assertThat(widgetItemInTable).hasSize(3);
- assertThat(widgetItemInTable.get(0)).containsExactly(mWidget1x1, mWidget2x2, mWidget2x3);
- assertThat(widgetItemInTable.get(1)).containsExactly(mWidget2x4);
+ assertThat(widgetItemInTable.get(0)).containsExactly(mWidget1x1, mWidget2x2);
+ assertThat(widgetItemInTable.get(1)).containsExactly(mWidget2x3, mWidget2x4);
assertThat(widgetItemInTable.get(2)).containsExactly(mWidget4x4);
}
@@ -114,12 +114,14 @@
widgetItems, /* maxSpansPerRow= */ 4);
// Row 0: 1x1, 2x2
- // Row 1: 2x3, 2x4
- // Row 2: 4x4
- assertThat(widgetItemInTable).hasSize(3);
+ // Row 1: 2x3,
+ // Row 2: 2x4,
+ // Row 3: 4x4
+ assertThat(widgetItemInTable).hasSize(4);
assertThat(widgetItemInTable.get(0)).containsExactly(mWidget1x1, mWidget2x2);
- assertThat(widgetItemInTable.get(1)).containsExactly(mWidget2x3, mWidget2x4);
- assertThat(widgetItemInTable.get(2)).containsExactly(mWidget4x4);
+ assertThat(widgetItemInTable.get(1)).containsExactly(mWidget2x3);
+ assertThat(widgetItemInTable.get(2)).containsExactly(mWidget2x4);
+ assertThat(widgetItemInTable.get(3)).containsExactly(mWidget4x4);
}
@Test
@@ -131,14 +133,16 @@
widgetItems, /* maxSpansPerRow= */ 4);
// Row 0: 1x1, 2x2
- // Row 1: 2x3, 2x4
- // Row 2: 4x4
- // Row 3: shortcut3, shortcut1, shortcut2
- assertThat(widgetItemInTable).hasSize(4);
+ // Row 1: 2x3,
+ // Row 2: 2x4,
+ // Row 3: 4x4
+ // Row 4: shortcut3, shortcut1, shortcut2
+ assertThat(widgetItemInTable).hasSize(5);
assertThat(widgetItemInTable.get(0)).containsExactly(mWidget1x1, mWidget2x2);
- assertThat(widgetItemInTable.get(1)).containsExactly(mWidget2x3, mWidget2x4);
- assertThat(widgetItemInTable.get(2)).containsExactly(mWidget4x4);
- assertThat(widgetItemInTable.get(3)).containsExactly(mShortcut3, mShortcut2, mShortcut1);
+ assertThat(widgetItemInTable.get(1)).containsExactly(mWidget2x3);
+ assertThat(widgetItemInTable.get(2)).containsExactly(mWidget2x4);
+ assertThat(widgetItemInTable.get(3)).containsExactly(mWidget4x4);
+ assertThat(widgetItemInTable.get(4)).containsExactly(mShortcut3, mShortcut2, mShortcut1);
}
private void initTestWidgets() {
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index b26a7ea..9725b06 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -479,9 +479,11 @@
if (newPos < mMinScroll && oldPos >= mMinScroll) {
mEdgeGlowLeft.onAbsorb((int) mScroller.getCurrVelocity());
mScroller.abortAnimation();
+ onEdgeAbsorbingScroll();
} else if (newPos > mMaxScroll && oldPos <= mMaxScroll) {
mEdgeGlowRight.onAbsorb((int) mScroller.getCurrVelocity());
mScroller.abortAnimation();
+ onEdgeAbsorbingScroll();
}
}
@@ -1332,6 +1334,13 @@
protected void onNotSnappingToPageInFreeScroll() { }
+ /**
+ * Called when the view edges absorb part of the scroll. Subclasses can override this
+ * to provide custom behavior during animation.
+ */
+ protected void onEdgeAbsorbingScroll() {
+ }
+
protected boolean shouldFlingForVelocity(int velocity) {
float threshold = mAllowEasyFling ? mEasyFlingThresholdVelocity : mFlingThresholdVelocity;
return Math.abs(velocity) > threshold;
diff --git a/src/com/android/launcher3/util/VibratorWrapper.java b/src/com/android/launcher3/util/VibratorWrapper.java
index b0defd4..14bf6c2 100644
--- a/src/com/android/launcher3/util/VibratorWrapper.java
+++ b/src/com/android/launcher3/util/VibratorWrapper.java
@@ -21,15 +21,19 @@
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
+import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
+import android.media.AudioAttributes;
import android.os.Build;
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.provider.Settings;
+import com.android.launcher3.Utilities;
+
/**
* Wrapper around {@link Vibrator} to easily perform haptic feedback where necessary.
*/
@@ -39,6 +43,11 @@
public static final MainThreadInitializedObject<VibratorWrapper> INSTANCE =
new MainThreadInitializedObject<>(VibratorWrapper::new);
+ public static final AudioAttributes VIBRATION_ATTRS = new AudioAttributes.Builder()
+ .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
+ .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+ .build();
+
public static final VibrationEffect EFFECT_CLICK =
createPredefined(VibrationEffect.EFFECT_CLICK);
@@ -81,4 +90,24 @@
UI_HELPER_EXECUTOR.execute(() -> mVibrator.vibrate(vibrationEffect));
}
}
+
+ /**
+ * Vibrates with a single primitive, if supported, or use a fallback effect instead. This only
+ * vibrates if haptic feedback is available and enabled.
+ */
+ @SuppressLint("NewApi")
+ public void vibrate(int primitiveId, float primitiveScale, VibrationEffect fallbackEffect) {
+ if (mHasVibrator && mIsHapticFeedbackEnabled) {
+ UI_HELPER_EXECUTOR.execute(() -> {
+ if (Utilities.ATLEAST_R && primitiveId >= 0
+ && mVibrator.areAllPrimitivesSupported(primitiveId)) {
+ mVibrator.vibrate(VibrationEffect.startComposition()
+ .addPrimitive(primitiveId, primitiveScale)
+ .compose(), VIBRATION_ATTRS);
+ } else {
+ mVibrator.vibrate(fallbackEffect, VIBRATION_ATTRS);
+ }
+ });
+ }
+ }
}
diff --git a/src/com/android/launcher3/widget/util/WidgetsTableUtils.java b/src/com/android/launcher3/widget/util/WidgetsTableUtils.java
index e73d661..7294a3a 100644
--- a/src/com/android/launcher3/widget/util/WidgetsTableUtils.java
+++ b/src/com/android/launcher3/widget/util/WidgetsTableUtils.java
@@ -52,9 +52,10 @@
* <p>Grouping:
* 1. Widgets and shortcuts never group together in the same row.
* 2. The ordered widgets are grouped together in the same row until their total horizontal
- * spans exceed the {@code maxSpansPerRow}.
+ * spans exceed the {@code maxSpansPerRow} - 1.
* 3. The order shortcuts are grouped together in the same row until their total horizontal
- * spans exceed the {@code maxSpansPerRow}.
+ * spans exceed the {@code maxSpansPerRow} - 1.
+ * 4. If there is only one widget in a row, its width may exceed the {@code maxSpansPerRow}.
*/
public static List<ArrayList<WidgetItem>> groupWidgetItemsIntoTable(
List<WidgetItem> widgetItems, final int maxSpansPerRow) {
@@ -70,10 +71,15 @@
int numOfWidgetItems = widgetItemsAtRow.size();
int totalHorizontalSpan = widgetItemsAtRow.stream().map(item -> item.spanX)
.reduce(/* default= */ 0, Integer::sum);
+ int totalHorizontalSpanAfterAddingWidget = widgetItem.spanX + totalHorizontalSpan;
if (numOfWidgetItems == 0) {
widgetItemsAtRow.add(widgetItem);
- } else if (widgetItem.spanX + totalHorizontalSpan <= maxSpansPerRow
- && widgetItem.hasSameType(widgetItemsAtRow.get(numOfWidgetItems - 1))) {
+ } else if (
+ // The max spans per row is reduced by 1 to ensure we don't pack too many
+ // 1xn widgets on the same row, which may reduce the space for rendering a
+ // widget's description.
+ totalHorizontalSpanAfterAddingWidget <= maxSpansPerRow - 1
+ && widgetItem.hasSameType(widgetItemsAtRow.get(numOfWidgetItems - 1))) {
// Group items in the same row if
// 1. they are with the same type, i.e. a row can only have widgets or shortcuts but
// never a mix of both.