Implementing available part of UX spec for DW toast

See https://docs.google.com/presentation/d/1AepsnLeKcRhjMW35SkB5yMKO3u6waigug8Tyfe0LO5o/edit#slide=id.g4c5ab81849_0_0

Also using time formatting code copy-pasted from Google DWB app.

Bug: 118319143
Tests: Manual
Change-Id: I84392d7655f402e38cf4c46ae530d06f755a7df8
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 ("&lt;" is the
+     escaped form of '<'). [CHAR LIMIT=10] -->
+    <string name="shorter_duration_less_than_one_minute">&lt; 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/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>