Merge "Add more diags for b/117332845" into ub-launcher3-master
diff --git a/quickstep/res/drawable/bg_wellbeing_toast.xml b/quickstep/res/drawable/bg_wellbeing_toast.xml
new file mode 100644
index 0000000..22d6f8a
--- /dev/null
+++ b/quickstep/res/drawable/bg_wellbeing_toast.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 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.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
+ <solid android:color="#E61A73E8" />
+ <corners android:radius="@dimen/task_corner_radius" />
+</shape>
\ No newline at end of file
diff --git a/quickstep/res/layout/task.xml b/quickstep/res/layout/task.xml
index 8f43192..4cfefb8 100644
--- a/quickstep/res/layout/task.xml
+++ b/quickstep/res/layout/task.xml
@@ -38,9 +38,11 @@
<com.android.quickstep.views.DigitalWellBeingToast
android:id="@+id/digital_well_being_toast"
android:layout_width="match_parent"
- android:layout_height="100dp"
+ android:layout_height="48dp"
android:importantForAccessibility="noHideDescendants"
- android:background="#800000FF"
+ android:fontFamily="sans-serif"
+ android:textSize="14sp"
+ android:background="@drawable/bg_wellbeing_toast"
android:layout_gravity="bottom"
android:gravity="center"
android:textColor="@android:color/white"
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index 08132aa..7c47956 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -16,7 +16,7 @@
* limitations under the License.
*/
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- Application name -->
<string name="derived_app_name" translatable="false">Quickstep</string>
@@ -46,4 +46,24 @@
<!-- Accessibility title for the list of recent apps [CHAR_LIMIT=none] -->
<string name="accessibility_recent_apps">Recent apps</string>
+
+ <!-- Accessibility title for an app card in Recents for apps that have time limit set
+ [CHAR_LIMIT=none] -->
+ <string name="task_contents_description_with_remaining_time"><xliff:g id="task_description" example="GMail">%1$s</xliff:g>, <xliff:g id="remaining_time" example="7 minutes left today">%2$s</xliff:g></string>
+
+ <!-- Text to show total app usage per day if it is less than 1 minute ("<" is the
+ escaped form of '<'). [CHAR LIMIT=10] -->
+ <string name="shorter_duration_less_than_one_minute">< 1 minute</string>
+
+ <!-- Annotation shown on an app card in Recents, telling that the app was switched to a
+ grayscale because it ran over its time limit [CHAR LIMIT=25] -->
+ <string name="app_in_grayscale">App in grayscale</string>
+
+ <!-- Annotation shown on an app card in Recents, telling that the app has a usage limit set by
+ the user, and a given time is left for it today [CHAR LIMIT=20] -->
+ <string name="time_left_for_app"><xliff:g id="time" example="7 minutes">%1$s</xliff:g> left today</string>
+
+ <!-- Annotation shown on an app card in Recents, telling that the app is in a group that has a
+ usage limit set by the user, and a given time is left for the group today [CHAR LIMIT=20] -->
+ <string name="time_left_for_group"><xliff:g id="time" example="1 hour">%1$s</xliff:g> left for group</string>
</resources>
\ No newline at end of file
diff --git a/quickstep/src/com/android/quickstep/ActivityControlHelper.java b/quickstep/src/com/android/quickstep/ActivityControlHelper.java
index 1678f06..c3df9c7 100644
--- a/quickstep/src/com/android/quickstep/ActivityControlHelper.java
+++ b/quickstep/src/com/android/quickstep/ActivityControlHelper.java
@@ -21,6 +21,7 @@
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
import static com.android.launcher3.LauncherState.FAST_OVERVIEW;
import static com.android.launcher3.LauncherState.OVERVIEW;
+import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PROGRESS_SPRING;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.states.RotationHelper.REQUEST_LOCK;
import static com.android.quickstep.TouchConsumer.INTERACTION_NORMAL;
@@ -295,7 +296,8 @@
AnimatorSet anim = new AnimatorSet();
if (!activity.getDeviceProfile().isVerticalBarLayout()) {
- Animator shiftAnim = new SpringObjectAnimator(activity.getAllAppsController(),
+ Animator shiftAnim = new SpringObjectAnimator<>(activity.getAllAppsController(),
+ ALL_APPS_PROGRESS_SPRING, "allAppsSpringFromACH",
activity.getAllAppsController().getShiftRange(),
fromState.getVerticalProgress(activity),
endState.getVerticalProgress(activity));
diff --git a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
index b34d2bf..cc10009 100644
--- a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
+++ b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
@@ -20,17 +20,27 @@
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
+import android.content.res.Resources;
+import android.icu.text.MeasureFormat;
+import android.icu.text.MeasureFormat.FormatWidth;
+import android.icu.util.Measure;
+import android.icu.util.MeasureUnit;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
+import androidx.annotation.StringRes;
+
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.systemui.shared.recents.model.Task;
+import java.time.Duration;
+import java.util.Locale;
+
public final class DigitalWellBeingToast extends TextView {
public interface InitializeCallback {
@@ -65,16 +75,78 @@
callback.call(
appUsageLimitTimeMs >= 0 && appRemainingTimeMs < 0 ? 0 : 1,
- getContentDescriptionForTask(task, appRemainingTimeMs, isGroupLimit));
+ getContentDescriptionForTask(
+ task, appUsageLimitTimeMs, appRemainingTimeMs, isGroupLimit));
});
});
}
- public static String getText(long remainingTime, boolean isGroupLimit) {
- return remainingTime < 0 ?
- "Grayed" :
- "Remaining time:" + (remainingTime + 59999) / 60000
- + " min " + (isGroupLimit ? "for group" : "for the app");
+ private String getReadableDuration(
+ Duration duration,
+ FormatWidth formatWidthHourAndMinute,
+ @StringRes int durationLessThanOneMinuteStringId,
+ boolean forceFormatWidth) {
+ int hours = Math.toIntExact(duration.toHours());
+ int minutes = Math.toIntExact(duration.minusHours(hours).toMinutes());
+
+ // Apply formatWidthHourAndMinute if both the hour part and the minute part are non-zero.
+ if (hours > 0 && minutes > 0) {
+ return MeasureFormat.getInstance(Locale.getDefault(), formatWidthHourAndMinute)
+ .formatMeasures(
+ new Measure(hours, MeasureUnit.HOUR),
+ new Measure(minutes, MeasureUnit.MINUTE));
+ }
+
+ // Apply formatWidthHourOrMinute if only the hour part is non-zero (unless forced).
+ if (hours > 0) {
+ return MeasureFormat.getInstance(
+ Locale.getDefault(),
+ forceFormatWidth ? formatWidthHourAndMinute : FormatWidth.WIDE)
+ .formatMeasures(new Measure(hours, MeasureUnit.HOUR));
+ }
+
+ // Apply formatWidthHourOrMinute if only the minute part is non-zero (unless forced).
+ if (minutes > 0) {
+ return MeasureFormat.getInstance(
+ Locale.getDefault()
+ , forceFormatWidth ? formatWidthHourAndMinute : FormatWidth.WIDE)
+ .formatMeasures(new Measure(minutes, MeasureUnit.MINUTE));
+ }
+
+ // Use a specific string for usage less than one minute but non-zero.
+ if (duration.compareTo(Duration.ZERO) > 0) {
+ return getResources().getString(durationLessThanOneMinuteStringId);
+ }
+
+ // Otherwise, return 0-minute string.
+ return MeasureFormat.getInstance(
+ Locale.getDefault(), forceFormatWidth ? formatWidthHourAndMinute : FormatWidth.WIDE)
+ .formatMeasures(new Measure(0, MeasureUnit.MINUTE));
+ }
+
+ private String getReadableDuration(
+ Duration duration,
+ FormatWidth formatWidthHourAndMinute,
+ @StringRes int durationLessThanOneMinuteStringId) {
+ return getReadableDuration(
+ duration,
+ formatWidthHourAndMinute,
+ durationLessThanOneMinuteStringId,
+ /* forceFormatWidth= */ false);
+ }
+
+ private String getShorterReadableDuration(Duration duration) {
+ return getReadableDuration(
+ duration, FormatWidth.NARROW, R.string.shorter_duration_less_than_one_minute);
+ }
+
+ private String getText(long remainingTime, boolean isGroupLimit) {
+ final Resources resources = getResources();
+ return (remainingTime < 0) ?
+ resources.getString(R.string.app_in_grayscale) :
+ resources.getString(
+ isGroupLimit ? R.string.time_left_for_group : R.string.time_left_for_app,
+ getShorterReadableDuration(Duration.ofMillis(remainingTime)));
}
public void openAppUsageSettings() {
@@ -97,8 +169,8 @@
}
private String getContentDescriptionForTask(
- Task task, long appRemainingTimeMs, boolean isGroupLimit) {
- return appRemainingTimeMs > 0 ?
+ Task task, long appUsageLimitTimeMs, long appRemainingTimeMs, boolean isGroupLimit) {
+ return appUsageLimitTimeMs > 0 ?
getResources().getString(
R.string.task_contents_description_with_remaining_time,
task.titleDescription,
diff --git a/res/values/strings.xml b/res/values/strings.xml
index a1089c6..51350c0 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -336,6 +336,4 @@
<!-- Failed action error message: e.g. Failed: Pause -->
<string name="remote_action_failed">Failed: <xliff:g id="what" example="Pause">%1$s</xliff:g></string>
-
- <string name="task_contents_description_with_remaining_time" translatable="false"><xliff:g id="task_description" example="GMail">%1$s</xliff:g>, <xliff:g id="remaining_time" example="7 minutes">%2$s</xliff:g></string>
</resources>
diff --git a/src/com/android/launcher3/ProgressInterface.java b/src/com/android/launcher3/ProgressInterface.java
new file mode 100644
index 0000000..663d8ba
--- /dev/null
+++ b/src/com/android/launcher3/ProgressInterface.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2019 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;
+
+/**
+ * Progress is defined as a value with range [0, 1], and is specific to each implementor.
+ * It is used when there is a transition from one state of the UI to another.
+ */
+public interface ProgressInterface {
+ void setProgress(float progress);
+ float getProgress();
+}
\ No newline at end of file
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 962c25b..e8e93fe 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -23,17 +23,16 @@
import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherStateManager.AnimationConfig;
import com.android.launcher3.LauncherStateManager.StateHandler;
+import com.android.launcher3.ProgressInterface;
import com.android.launcher3.R;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.anim.SpringObjectAnimator;
import com.android.launcher3.anim.PropertySetter;
-import com.android.launcher3.anim.SpringObjectAnimator.SpringProperty;
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.ScrimView;
import androidx.dynamicanimation.animation.FloatPropertyCompat;
-import androidx.dynamicanimation.animation.SpringAnimation;
/**
* Handles AllApps view transition.
@@ -45,7 +44,8 @@
* If release velocity < THRES1, snap according to either top or bottom depending on whether it's
* closer to top or closer to the page indicator.
*/
-public class AllAppsTransitionController implements StateHandler, OnDeviceProfileChangeListener {
+public class AllAppsTransitionController implements StateHandler, OnDeviceProfileChangeListener,
+ ProgressInterface {
public static final Property<AllAppsTransitionController, Float> ALL_APPS_PROGRESS =
new Property<AllAppsTransitionController, Float>(Float.class, "allAppsProgress") {
@@ -74,40 +74,6 @@
}
};
- /**
- * Property that either sets the progress directly or animates the progress via a spring.
- */
- public static class AllAppsSpringProperty extends
- SpringProperty<AllAppsTransitionController, Float> {
-
- SpringAnimation mSpring;
- boolean useSpring = false;
-
- public AllAppsSpringProperty(SpringAnimation spring) {
- super(Float.class, "allAppsSpringProperty");
- mSpring = spring;
- }
-
- @Override
- public Float get(AllAppsTransitionController controller) {
- return controller.getProgress();
- }
-
- @Override
- public void set(AllAppsTransitionController controller, Float progress) {
- if (useSpring) {
- mSpring.animateToFinalPosition(progress);
- } else {
- controller.setProgress(progress);
- }
- }
-
- @Override
- public void switchToSpring() {
- useSpring = true;
- }
- }
-
private AllAppsContainerView mAppsView;
private ScrimView mScrimView;
@@ -161,6 +127,7 @@
* @see #setState(LauncherState)
* @see #setStateWithAnimation(LauncherState, AnimatorSetBuilder, AnimationConfig)
*/
+ @Override
public void setProgress(float progress) {
mProgress = progress;
mScrimView.setProgress(progress);
@@ -185,6 +152,7 @@
}
}
+ @Override
public float getProgress() {
return mProgress;
}
@@ -223,8 +191,8 @@
Interpolator interpolator = config.userControlled ? LINEAR : toState == OVERVIEW
? builder.getInterpolator(ANIM_OVERVIEW_SCALE, FAST_OUT_SLOW_IN)
: FAST_OUT_SLOW_IN;
- Animator anim = new SpringObjectAnimator(this, 1f / mShiftRange, mProgress,
- targetProgress);
+ Animator anim = new SpringObjectAnimator<>(this, ALL_APPS_PROGRESS_SPRING,
+ "allAppsSpringFromAATC", 1f / mShiftRange, mProgress, targetProgress);
anim.setDuration(config.duration);
anim.setInterpolator(builder.getInterpolator(ANIM_VERTICAL_PROGRESS, interpolator));
anim.addListener(getProgressAnimatorListener());
diff --git a/src/com/android/launcher3/anim/SpringObjectAnimator.java b/src/com/android/launcher3/anim/SpringObjectAnimator.java
index 4f037ef..4ece909 100644
--- a/src/com/android/launcher3/anim/SpringObjectAnimator.java
+++ b/src/com/android/launcher3/anim/SpringObjectAnimator.java
@@ -23,12 +23,12 @@
import android.util.Log;
import android.util.Property;
-import com.android.launcher3.allapps.AllAppsTransitionController;
-import com.android.launcher3.allapps.AllAppsTransitionController.AllAppsSpringProperty;
+import com.android.launcher3.ProgressInterface;
import java.util.ArrayList;
import androidx.dynamicanimation.animation.DynamicAnimation.OnAnimationEndListener;
+import androidx.dynamicanimation.animation.FloatPropertyCompat;
import androidx.dynamicanimation.animation.SpringAnimation;
import androidx.dynamicanimation.animation.SpringForce;
@@ -38,17 +38,17 @@
* This animator allows for an object's property to be be controlled by an {@link ObjectAnimator} or
* a {@link SpringAnimation}. It extends ValueAnimator so it can be used in an AnimatorSet.
*/
-public class SpringObjectAnimator extends ValueAnimator {
+public class SpringObjectAnimator<T extends ProgressInterface> extends ValueAnimator {
private static final String TAG = "SpringObjectAnimator";
private static boolean DEBUG = false;
- private AllAppsTransitionController mObject;
+ private T mObject;
private ObjectAnimator mObjectAnimator;
private float[] mValues;
private SpringAnimation mSpring;
- private AllAppsSpringProperty mProperty;
+ private SpringProperty<T> mProperty;
private ArrayList<AnimatorListener> mListeners;
private boolean mSpringEnded = false;
@@ -58,16 +58,16 @@
private static final float SPRING_DAMPING_RATIO = 0.9f;
private static final float SPRING_STIFFNESS = 600f;
- public SpringObjectAnimator(AllAppsTransitionController object, float minimumVisibleChange,
- float... values) {
+ public SpringObjectAnimator(T object, FloatPropertyCompat<T> floatProperty,
+ String name, float minimumVisibleChange, float... values) {
mObject = object;
- mSpring = new SpringAnimation(object, AllAppsTransitionController.ALL_APPS_PROGRESS_SPRING);
+ mSpring = new SpringAnimation(object, floatProperty);
mSpring.setMinimumVisibleChange(minimumVisibleChange);
mSpring.setSpring(new SpringForce(0)
.setDampingRatio(SPRING_DAMPING_RATIO)
.setStiffness(SPRING_STIFFNESS));
mSpring.setStartVelocity(0.01f);
- mProperty = new AllAppsSpringProperty(mSpring);
+ mProperty = new SpringProperty<T>(name, mSpring);
mObjectAnimator = ObjectAnimator.ofFloat(object, mProperty, values);
mValues = values;
mListeners = new ArrayList<>();
@@ -261,13 +261,32 @@
mObjectAnimator.setCurrentPlayTime(playTime);
}
- public static abstract class SpringProperty<T, V> extends Property<T, V> {
+ public static class SpringProperty<T extends ProgressInterface> extends Property<T, Float> {
- public SpringProperty(Class<V> type, String name) {
- super(type, name);
+ boolean useSpring = false;
+ final SpringAnimation mSpring;
+
+ public SpringProperty(String name, SpringAnimation spring) {
+ super(Float.class, name);
+ mSpring = spring;
}
- abstract public void switchToSpring();
- }
+ public void switchToSpring() {
+ useSpring = true;
+ }
+ @Override
+ public Float get(T object) {
+ return object.getProgress();
+ }
+
+ @Override
+ public void set(T object, Float progress) {
+ if (useSpring) {
+ mSpring.animateToFinalPosition(progress);
+ } else {
+ object.setProgress(progress);
+ }
+ }
+ }
}
diff --git a/src/com/android/launcher3/compat/AlphabeticIndexCompat.java b/src/com/android/launcher3/compat/AlphabeticIndexCompat.java
index 84e82e3..a7c0a47 100644
--- a/src/com/android/launcher3/compat/AlphabeticIndexCompat.java
+++ b/src/com/android/launcher3/compat/AlphabeticIndexCompat.java
@@ -12,6 +12,8 @@
import java.lang.reflect.Method;
import java.util.Locale;
+import androidx.annotation.NonNull;
+
public class AlphabeticIndexCompat {
private static final String TAG = "AlphabeticIndexCompat";
@@ -53,7 +55,7 @@
/**
* Computes the section name for an given string {@param s}.
*/
- public String computeSectionName(CharSequence cs) {
+ public String computeSectionName(@NonNull CharSequence cs) {
String s = Utilities.trim(cs);
String sectionName = mBaseIndex.getBucketLabel(mBaseIndex.getBucketIndex(s));
if (Utilities.trim(sectionName).isEmpty() && s.length() > 0) {
@@ -89,7 +91,7 @@
/**
* Returns the index of the bucket in which the given string should appear.
*/
- protected int getBucketIndex(String s) {
+ protected int getBucketIndex(@NonNull String s) {
if (s.isEmpty()) {
return UNKNOWN_BUCKET_INDEX;
}
diff --git a/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java b/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java
index 9a17ec6..7a7f828 100644
--- a/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java
+++ b/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java
@@ -69,7 +69,8 @@
WidgetItemComparator widgetComparator = new WidgetItemComparator();
for (Map.Entry<PackageItemInfo, ArrayList<WidgetItem>> entry : mWidgetsList.entrySet()) {
WidgetListRowEntry row = new WidgetListRowEntry(entry.getKey(), entry.getValue());
- row.titleSectionName = indexer.computeSectionName(row.pkgItem.title);
+ row.titleSectionName = (row.pkgItem.title == null) ? "" :
+ indexer.computeSectionName(row.pkgItem.title);
Collections.sort(row.widgets, widgetComparator);
result.add(row);
}
diff --git a/tests/tapl/com/android/launcher3/tapl/Background.java b/tests/tapl/com/android/launcher3/tapl/Background.java
index 27e0954..08d2889 100644
--- a/tests/tapl/com/android/launcher3/tapl/Background.java
+++ b/tests/tapl/com/android/launcher3/tapl/Background.java
@@ -64,7 +64,7 @@
mLauncher.swipe(
navBar.getVisibleBounds().centerX(), navBar.getVisibleBounds().centerY(),
- navBar.getVisibleBounds().centerX(), height - 300);
+ navBar.getVisibleBounds().centerX(), height - 400);
} else {
mLauncher.getSystemUiObject("recent_apps").click();
}