Merge RQ2A.210305.007

Bug: 180401296
Merged-In: I160364715a474d221b0607d92fa2e62b2e087bfe
Change-Id: I40368e570def13905a50d0fb3e9b1a2d60627c25
diff --git a/res/layout/basic_headsup_notification_template.xml b/res/layout/basic_headsup_notification_template.xml
index f2c2fa5..10c775b 100644
--- a/res/layout/basic_headsup_notification_template.xml
+++ b/res/layout/basic_headsup_notification_template.xml
@@ -14,10 +14,12 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-             xmlns:app="http://schemas.android.com/apk/res-auto"
-             android:layout_width="match_parent"
-             android:layout_height="wrap_content">
+<com.android.car.ui.FocusArea
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    app:defaultFocus="@+id/action_1">
 
     <androidx.cardview.widget.CardView
         android:id="@+id/card_view"
@@ -76,4 +78,4 @@
 
         </RelativeLayout>
     </androidx.cardview.widget.CardView>
-</FrameLayout>
+</com.android.car.ui.FocusArea>
diff --git a/res/layout/call_headsup_notification_template.xml b/res/layout/call_headsup_notification_template.xml
index c9ec748..3a59f26 100644
--- a/res/layout/call_headsup_notification_template.xml
+++ b/res/layout/call_headsup_notification_template.xml
@@ -15,11 +15,12 @@
     limitations under the License.
 -->
 
-<FrameLayout
+<com.android.car.ui.FocusArea
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
-    android:layout_height="wrap_content">
+    android:layout_height="wrap_content"
+    app:defaultFocus="@+id/action_1">
 
     <androidx.cardview.widget.CardView
         android:id="@+id/card_view"
@@ -78,4 +79,4 @@
             </FrameLayout>
         </RelativeLayout>
     </androidx.cardview.widget.CardView>
-</FrameLayout>
+</com.android.car.ui.FocusArea>
diff --git a/res/layout/car_emergency_headsup_notification_template.xml b/res/layout/car_emergency_headsup_notification_template.xml
index 725f110..7e3b968 100644
--- a/res/layout/car_emergency_headsup_notification_template.xml
+++ b/res/layout/car_emergency_headsup_notification_template.xml
@@ -15,11 +15,12 @@
     limitations under the License.
 -->
 
-<FrameLayout
+<com.android.car.ui.FocusArea
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
-    android:layout_height="wrap_content">
+    android:layout_height="wrap_content"
+    app:defaultFocus="@+id/action_1">
 
     <androidx.cardview.widget.CardView
         android:id="@+id/card_view"
@@ -86,4 +87,4 @@
             </RelativeLayout>
         </FrameLayout>
     </androidx.cardview.widget.CardView>
-</FrameLayout>
+</com.android.car.ui.FocusArea>
diff --git a/res/layout/car_information_headsup_notification_template.xml b/res/layout/car_information_headsup_notification_template.xml
index d588864..09138f9 100644
--- a/res/layout/car_information_headsup_notification_template.xml
+++ b/res/layout/car_information_headsup_notification_template.xml
@@ -15,11 +15,12 @@
     limitations under the License.
 -->
 
-<FrameLayout
+<com.android.car.ui.FocusArea
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
-    android:layout_height="wrap_content">
+    android:layout_height="wrap_content"
+    app:defaultFocus="@+id/action_1">
 
     <androidx.cardview.widget.CardView
         android:id="@+id/card_view"
@@ -88,4 +89,4 @@
             </RelativeLayout>
         </FrameLayout>
     </androidx.cardview.widget.CardView>
-</FrameLayout>
+</com.android.car.ui.FocusArea>
diff --git a/res/layout/car_warning_headsup_notification_template.xml b/res/layout/car_warning_headsup_notification_template.xml
index d588864..09138f9 100644
--- a/res/layout/car_warning_headsup_notification_template.xml
+++ b/res/layout/car_warning_headsup_notification_template.xml
@@ -15,11 +15,12 @@
     limitations under the License.
 -->
 
-<FrameLayout
+<com.android.car.ui.FocusArea
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
-    android:layout_height="wrap_content">
+    android:layout_height="wrap_content"
+    app:defaultFocus="@+id/action_1">
 
     <androidx.cardview.widget.CardView
         android:id="@+id/card_view"
@@ -88,4 +89,4 @@
             </RelativeLayout>
         </FrameLayout>
     </androidx.cardview.widget.CardView>
-</FrameLayout>
+</com.android.car.ui.FocusArea>
diff --git a/res/layout/dismiss_button.xml b/res/layout/dismiss_button.xml
index d47bc01..b24e070 100644
--- a/res/layout/dismiss_button.xml
+++ b/res/layout/dismiss_button.xml
@@ -23,7 +23,8 @@
             android:id="@+id/dismiss_button"
             android:layout_width="@dimen/dismiss_button_diameter"
             android:layout_height="@dimen/dismiss_button_diameter"
-            android:layout_marginRight="@dimen/dismiss_button_right_margin"
+            android:layout_marginLeft="@dimen/dismiss_button_horizontal_margin"
+            android:layout_marginRight="@dimen/dismiss_button_horizontal_margin"
             android:layout_marginBottom="@dimen/card_min_bottom_padding"
             android:background="@drawable/dismiss_button_background"
             android:scaleType="center"
diff --git a/res/layout/headsup_container.xml b/res/layout/headsup_container.xml
index db649b7..9eec539 100644
--- a/res/layout/headsup_container.xml
+++ b/res/layout/headsup_container.xml
@@ -45,14 +45,13 @@
         app:layout_constraintBottom_toBottomOf="@+id/gradient_edge"
         app:layout_constraintTop_toTopOf="parent"/>
 
-    <FrameLayout
+    <com.android.car.notification.headsup.HeadsUpContainerView
         android:id="@+id/headsup_content"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_marginTop="@dimen/headsup_notification_top_margin"
         app:layout_constraintEnd_toStartOf="parent"
         app:layout_constraintStart_toEndOf="parent"
-        app:layout_constraintTop_toTopOf="parent"
-    />
+        app:layout_constraintTop_toTopOf="parent"/>
 
 </androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/res/layout/inbox_headsup_notification_template.xml b/res/layout/inbox_headsup_notification_template.xml
index 6f58bef..2d4e723 100644
--- a/res/layout/inbox_headsup_notification_template.xml
+++ b/res/layout/inbox_headsup_notification_template.xml
@@ -15,11 +15,12 @@
     limitations under the License.
 -->
 
-<FrameLayout
+<com.android.car.ui.FocusArea
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
-    android:layout_height="wrap_content">
+    android:layout_height="wrap_content"
+    app:defaultFocus="@+id/action_1">
 
     <androidx.cardview.widget.CardView
         android:id="@+id/card_view"
@@ -78,4 +79,4 @@
             </FrameLayout>
         </RelativeLayout>
     </androidx.cardview.widget.CardView>
-</FrameLayout>
+</com.android.car.ui.FocusArea>
diff --git a/res/layout/message_headsup_notification_template.xml b/res/layout/message_headsup_notification_template.xml
index abe2f6f..ca5f19b 100644
--- a/res/layout/message_headsup_notification_template.xml
+++ b/res/layout/message_headsup_notification_template.xml
@@ -15,11 +15,12 @@
     limitations under the License.
 -->
 
-<FrameLayout
+<com.android.car.ui.FocusArea
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
-    android:layout_height="wrap_content">
+    android:layout_height="wrap_content"
+    app:defaultFocus="@+id/action_1">
 
     <androidx.cardview.widget.CardView
         android:id="@+id/card_view"
@@ -88,4 +89,4 @@
             </FrameLayout>
         </RelativeLayout>
     </androidx.cardview.widget.CardView>
-</FrameLayout>
+</com.android.car.ui.FocusArea>
diff --git a/res/layout/navigation_headsup_notification_template.xml b/res/layout/navigation_headsup_notification_template.xml
index 4268905..4e4c432 100644
--- a/res/layout/navigation_headsup_notification_template.xml
+++ b/res/layout/navigation_headsup_notification_template.xml
@@ -14,10 +14,12 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-             xmlns:app="http://schemas.android.com/apk/res-auto"
-             android:layout_width="match_parent"
-             android:layout_height="wrap_content">
+<com.android.car.ui.FocusArea
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    app:defaultFocus="@+id/action_1">
 
     <androidx.cardview.widget.CardView
         android:id="@+id/card_view"
@@ -75,4 +77,4 @@
             </FrameLayout>
         </RelativeLayout>
     </androidx.cardview.widget.CardView>
-</FrameLayout>
+</com.android.car.ui.FocusArea>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index e687e90..d06de6d 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -19,7 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="assist_action_play_label" msgid="6278705468288338172">"Wiedergeben"</string>
     <string name="action_mute_short" msgid="5239851786101022633">"Stummschalten"</string>
-    <string name="action_mute_long" msgid="6846675719189989477">"Unterhaltung ignorieren"</string>
+    <string name="action_mute_long" msgid="6846675719189989477">"Unterhaltung stummschalten"</string>
     <string name="action_unmute_short" msgid="7157822835069715986">"Stummschaltung aufheben"</string>
     <string name="action_unmute_long" msgid="22482625837159466">"Unterhaltung nicht mehr stummschalten"</string>
     <string name="action_canned_reply" msgid="4045960823021872834">"\"Ich fahre gerade.\""</string>
diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml
index 53339ed..9cd514d 100644
--- a/res/values-hy/strings.xml
+++ b/res/values-hy/strings.xml
@@ -29,10 +29,10 @@
     <string name="notifications" msgid="2865534625906329283">"Ծանուցումների կենտրոն"</string>
     <string name="clear_all" msgid="1845314281571237722">"Ջնջել բոլորը"</string>
     <string name="ellipsized_string" msgid="6993649229498857557">"…"</string>
-    <string name="show_more" msgid="7291378544926443344">"Ցույց տալ ավելին"</string>
+    <string name="show_more" msgid="7291378544926443344">"Ցուցադրել ավելի շատ"</string>
     <string name="notification_header" msgid="324550431063568049">"Ծանուցումներ"</string>
     <string name="empty_notification_header" msgid="4928379791607839720">"Ծանուցումներ չկան"</string>
-    <string name="show_less" msgid="7342677676229302829">"Ցույց տալ ավելի քիչ"</string>
+    <string name="show_less" msgid="7342677676229302829">"Ցուցադրել ավելի քիչ"</string>
     <string name="show_count_more" msgid="480555295700318609">"Ցուցադրել ևս <xliff:g id="COUNT">%d</xliff:g>"</string>
     <string name="message_unshown_count" msgid="2234421277246741233">" Եվս <xliff:g id="COUNT">%d</xliff:g>"</string>
     <plurals name="restricted_message_text" formatted="false" msgid="507312322886633308">
diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml
index 35abdf2..a327a7b 100644
--- a/res/values-mn/strings.xml
+++ b/res/values-mn/strings.xml
@@ -36,7 +36,7 @@
     <string name="show_count_more" msgid="480555295700318609">"<xliff:g id="COUNT">%d</xliff:g>-г дэлгэрэнгүй харуулах"</string>
     <string name="message_unshown_count" msgid="2234421277246741233">" +<xliff:g id="COUNT">%d</xliff:g> бусад"</string>
     <plurals name="restricted_message_text" formatted="false" msgid="507312322886633308">
-      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> шинэ мессеж</item>
-      <item quantity="one">1 шинэ мессеж</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> шинэ зурвас</item>
+      <item quantity="one">1 шинэ зурвас</item>
     </plurals>
 </resources>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index fb3895d..d82d53e 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -27,7 +27,7 @@
     <string name="toast_message_sent_success" msgid="1159956191974273064">"Mensagem enviada."</string>
     <string name="notification_service_label" msgid="7512186049723777468">"Serviço de escuta de notificações do carro"</string>
     <string name="notifications" msgid="2865534625906329283">"Central de notificações"</string>
-    <string name="clear_all" msgid="1845314281571237722">"Excluir tudo"</string>
+    <string name="clear_all" msgid="1845314281571237722">"Limpar tudo"</string>
     <string name="ellipsized_string" msgid="6993649229498857557">"…"</string>
     <string name="show_more" msgid="7291378544926443344">"Mostrar mais"</string>
     <string name="notification_header" msgid="324550431063568049">"Notificações"</string>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 8887249..9f7ae23 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -59,6 +59,9 @@
     <dimen name="action_button_spacing_start">@*android:dimen/car_padding_4</dimen>
     <dimen name="action_button_padding_top">10dp</dimen>
     <dimen name="action_button_padding_bottom">10dp</dimen>
+    <!-- This value is recommended to be greater than or equal to
+         @dimen/dismiss_button_diameter + 2 * @dimen/dismiss_button_horizontal_margin -->
+    <dimen name="action_view_right_margin">120dp</dimen>
 
     <!-- Icons -->
     <dimen name="notification_primary_icon_size">@*android:dimen/car_primary_icon_size</dimen>
@@ -79,7 +82,7 @@
 
     <!-- Dismiss button -->
     <dimen name="dismiss_button_diameter">@*android:dimen/car_button_height</dimen>
-    <dimen name="dismiss_button_right_margin">32dp</dimen>
+    <dimen name="dismiss_button_horizontal_margin">@*android:dimen/car_padding_4</dimen>
 
     <!-- Clear all button -->
     <dimen name="clear_all_button_margin">@*android:dimen/car_padding_3</dimen>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index c4d7474..cd9f61c 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -55,6 +55,7 @@
         <item name="android:layout_gravity">left</item>
         <item name="android:minHeight">@dimen/card_min_bottom_padding</item>
         <item name="android:layout_marginLeft">@dimen/action_view_left_margin</item>
+        <item name="android:layout_marginRight">@dimen/action_view_right_margin</item>
     </style>
 
     <style name="NotificationActionButtonBase" parent="@android:Widget.DeviceDefault.Button.Borderless.Colored">
diff --git a/src/com/android/car/notification/headsup/HeadsUpContainerView.java b/src/com/android/car/notification/headsup/HeadsUpContainerView.java
new file mode 100644
index 0000000..44fbec3
--- /dev/null
+++ b/src/com/android/car/notification/headsup/HeadsUpContainerView.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2020 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.car.notification.headsup;
+
+import static android.view.accessibility.AccessibilityNodeInfo.ACTION_FOCUS;
+
+import static com.android.car.ui.utils.RotaryConstants.ROTARY_FOCUS_DELEGATING_CONTAINER;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.os.Handler;
+import android.os.Looper;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.FrameLayout;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.car.notification.R;
+import com.android.car.ui.FocusArea;
+
+/**
+ * Container that is used to present heads-up notifications. It is responsible for delegating the
+ * focus to the topmost notification and ensuring that new HUNs gains focus automatically when
+ * one of the existing HUNs already has focus.
+ */
+public class HeadsUpContainerView extends FrameLayout {
+
+    private Handler mHandler;
+    private int mAnimationDuration;
+
+    public HeadsUpContainerView(@NonNull Context context) {
+        super(context);
+        init();
+    }
+
+    public HeadsUpContainerView(@NonNull Context context,
+            @Nullable AttributeSet attrs) {
+        super(context, attrs);
+        init();
+    }
+
+    public HeadsUpContainerView(@NonNull Context context, @Nullable AttributeSet attrs,
+            int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        init();
+    }
+
+    public HeadsUpContainerView(@NonNull Context context, @Nullable AttributeSet attrs,
+            int defStyleAttr,
+            int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        init();
+    }
+
+    private void init() {
+        mHandler = new Handler(Looper.getMainLooper());
+        mAnimationDuration = getResources().getInteger(R.integer.headsup_total_enter_duration_ms);
+
+        // This tag is required to make this container receive the focus request in order to
+        // delegate focus to its children, even though the container itself isn't focusable.
+        setContentDescription(ROTARY_FOCUS_DELEGATING_CONTAINER);
+        setClickable(false);
+    }
+
+    @Override
+    protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
+        if (isInTouchMode()) {
+            return super.onRequestFocusInDescendants(direction, previouslyFocusedRect);
+        }
+        return focusTopmostChild();
+    }
+
+    @Override
+    public void addView(View child) {
+        super.addView(child);
+
+        if (!isInTouchMode() && getFocusedChild() != null) {
+            // Request focus for the topmost child if one of the children is already focused.
+            // Wait for the duration of the heads-up animation for a smoother UI experience.
+            mHandler.postDelayed(() -> focusTopmostChild(), mAnimationDuration);
+        }
+    }
+
+    private boolean focusTopmostChild() {
+        int childCount = getChildCount();
+        if (childCount <= 0) {
+            return false;
+        }
+
+        View topMostChild = getChildAt(childCount - 1);
+        if (!(topMostChild instanceof FocusArea)) {
+            return false;
+        }
+
+        return topMostChild.performAccessibilityAction(ACTION_FOCUS, /* arguments= */ null);
+    }
+}