Merge "Allow showing tabs while in subpages" into pi-car-dev am: 535364d1d9 am: 1f04b55b8b am: c87f697238 am: 061a87c154
Change-Id: I21de1c8504a7905a59f6b08719408fe72039e58e
diff --git a/car-apps-common/res/values-af/strings.xml b/car-apps-common/res/values-af/strings.xml
index bea072f..0771610 100644
--- a/car-apps-common/res/values-af/strings.xml
+++ b/car-apps-common/res/values-af/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"Vou knoppie in of uit"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"Maak laai oop"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"Maak laai toe"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"Kenmerk is nie beskikbaar terwyl jy bestuur nie."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"Rollees af"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"Rollees op"</string>
</resources>
diff --git a/car-apps-common/res/values-am/strings.xml b/car-apps-common/res/values-am/strings.xml
index 6adcf20..c3c5933 100644
--- a/car-apps-common/res/values-am/strings.xml
+++ b/car-apps-common/res/values-am/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"አዝራርን ዘርጋ/ሰብስብ"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"መሳቢያን ክፈት"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"መሳቢያን ዝጋ"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"እየነዱ ሳለ ባህሪ አይገኝም።"</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"ወደ ታች ይሸብልሉ"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"ወደ ላይ ይሸብልሉ"</string>
</resources>
diff --git a/car-apps-common/res/values-ar/strings.xml b/car-apps-common/res/values-ar/strings.xml
index 735997e..c16969b 100644
--- a/car-apps-common/res/values-ar/strings.xml
+++ b/car-apps-common/res/values-ar/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"زر التوسيع/التصغير"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"فتح الدُرج"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"إغلاق الدُرج"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"لا تتوفَّر الميزة أثناء القيادة."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"التمرير للأسفل"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"التمرير للأعلى"</string>
</resources>
diff --git a/car-apps-common/res/values-as/strings.xml b/car-apps-common/res/values-as/strings.xml
index e5480aa..bdb14e9 100644
--- a/car-apps-common/res/values-as/strings.xml
+++ b/car-apps-common/res/values-as/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"সম্প্ৰসাৰণ/সংকোচন বুটাম"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"ড্ৰৱাৰ খোলক"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"ড্ৰৱাৰ বন্ধ কৰক"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"গাড়ী চলোৱাৰ সময়ত এই সুবিধাটো উপলব্ধ নহয়।"</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"তললৈ স্ক্ৰল কৰক"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"ওপৰলৈ স্ক্ৰল কৰক"</string>
</resources>
diff --git a/car-apps-common/res/values-az/strings.xml b/car-apps-common/res/values-az/strings.xml
index bcc20d0..7a705ca 100644
--- a/car-apps-common/res/values-az/strings.xml
+++ b/car-apps-common/res/values-az/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"Düyməni genişləndirin/yığcamlaşdırın"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"Çəkməcəni açın"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"Çəkməcəni bağlayın"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"Xüsusiyyət avtomobil idarə edərkən əlçatan deyil."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"Aşağı sürüşdürün"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"Yuxarı sürüşdürün"</string>
</resources>
diff --git a/car-apps-common/res/values-b+sr+Latn/strings.xml b/car-apps-common/res/values-b+sr+Latn/strings.xml
index 90e7cbb..4b64909 100644
--- a/car-apps-common/res/values-b+sr+Latn/strings.xml
+++ b/car-apps-common/res/values-b+sr+Latn/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"Dugme Proširi/skupi"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"Otvori fioku"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"Zatvori fioku"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"Funkcija nije dostupna tokom vožnje."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"Pomerite nadole"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"Pomerite nagore"</string>
</resources>
diff --git a/car-apps-common/res/values-be/strings.xml b/car-apps-common/res/values-be/strings.xml
index 10acc73..8c0ae61 100644
--- a/car-apps-common/res/values-be/strings.xml
+++ b/car-apps-common/res/values-be/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"Кнопка \"Разгарнуць/згарнуць\""</string>
<string name="car_drawer_open" msgid="2676372472514742324">"Адкрыць высоўнае меню"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"Закрыць высоўнае меню"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"Функцыя недаступная, калі вы за рулём."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"Прагартаць уніз"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"Прагартаць уверх"</string>
</resources>
diff --git a/car-apps-common/res/values-bg/strings.xml b/car-apps-common/res/values-bg/strings.xml
index 9762b33..4c8dfad 100644
--- a/car-apps-common/res/values-bg/strings.xml
+++ b/car-apps-common/res/values-bg/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"Бутон за разгъване/свиване"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"Отваряне на слоя"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"Затваряне на слоя"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"Функцията не е налице по време на шофиране."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"Превъртане надолу"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"Превъртане нагоре"</string>
</resources>
diff --git a/car-apps-common/res/values-bn/strings.xml b/car-apps-common/res/values-bn/strings.xml
index 937834b..8c8f5eb 100644
--- a/car-apps-common/res/values-bn/strings.xml
+++ b/car-apps-common/res/values-bn/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"বড় করা/আড়াল করার বোতাম"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"ড্রয়ার খুলুন"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"ড্রয়ার বন্ধ করুন"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"ড্রাইভ করার সময় এই ফিচার কাজ করবে না।"</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"নিচে স্ক্রল করুন"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"উপরে স্ক্রল করুন"</string>
</resources>
diff --git a/car-apps-common/res/values-bs/strings.xml b/car-apps-common/res/values-bs/strings.xml
index 299c4e1..0d3bcc9 100644
--- a/car-apps-common/res/values-bs/strings.xml
+++ b/car-apps-common/res/values-bs/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"Dugme proširi/suzi"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"Otvori ladicu"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"Zatvori ladicu"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"Funkcija nije dostupna tokom vožnje."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"Klizni prema dolje"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"Klizni prema gore"</string>
</resources>
diff --git a/car-apps-common/res/values-ca/strings.xml b/car-apps-common/res/values-ca/strings.xml
index 48d7ba8..df3b477 100644
--- a/car-apps-common/res/values-ca/strings.xml
+++ b/car-apps-common/res/values-ca/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"Botó per desplegar o replegar"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"Obre el tauler"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"Tanca el tauler"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"Aquesta funció no està disponible mentre condueixes."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"Desplaça cap avall"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"Desplaça cap amunt"</string>
</resources>
diff --git a/car-apps-common/res/values-cs/strings.xml b/car-apps-common/res/values-cs/strings.xml
index db6cedd..6872e31 100644
--- a/car-apps-common/res/values-cs/strings.xml
+++ b/car-apps-common/res/values-cs/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"Tlačítko rozbalení/sbalení"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"Otevřít vysouvací panel"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"Zavřít vysouvací panel"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"Funkce při řízení není dostupná."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"Posunout dolů"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"Posunout nahoru"</string>
</resources>
diff --git a/car-apps-common/res/values-da/strings.xml b/car-apps-common/res/values-da/strings.xml
index cc9a4e7..49b1021 100644
--- a/car-apps-common/res/values-da/strings.xml
+++ b/car-apps-common/res/values-da/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"Knappen Udvid/skjul"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"Åbn skuffen"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"Luk skuffen"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"Funktionen er ikke tilgængelig under kørsel."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"Rul ned"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"Rul op"</string>
</resources>
diff --git a/car-apps-common/res/values-de/strings.xml b/car-apps-common/res/values-de/strings.xml
index 67cea75..25cc654 100644
--- a/car-apps-common/res/values-de/strings.xml
+++ b/car-apps-common/res/values-de/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"Schaltfläche zum Maximieren/Minimieren"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"Leiste öffnen"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"Leiste schließen"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"Funktion während der Fahrt nicht verfügbar."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"Nach unten scrollen"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"Nach oben scrollen"</string>
</resources>
diff --git a/car-apps-common/res/values-el/strings.xml b/car-apps-common/res/values-el/strings.xml
index 39f4206..43bcbda 100644
--- a/car-apps-common/res/values-el/strings.xml
+++ b/car-apps-common/res/values-el/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"Κουμπί ανάπτυξης/σύμπτυξης"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"Άνοιγμα συρταριού"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"Κλείσιμο συρταριού"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"Η λειτουργία δεν διατίθεται κατά τη διάρκεια της οδήγησης."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"Κύλιση προς τα κάτω"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"Κύλιση προς τα επάνω"</string>
</resources>
diff --git a/car-apps-common/res/values-en-rAU/strings.xml b/car-apps-common/res/values-en-rAU/strings.xml
index 1f7e3ee..691ae06 100644
--- a/car-apps-common/res/values-en-rAU/strings.xml
+++ b/car-apps-common/res/values-en-rAU/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"Expand/collapse button"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"Open drawer"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"Close drawer"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"Feature not available while driving."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"Scroll down"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"Scroll up"</string>
</resources>
diff --git a/car-apps-common/res/values-en-rCA/strings.xml b/car-apps-common/res/values-en-rCA/strings.xml
index 1f7e3ee..691ae06 100644
--- a/car-apps-common/res/values-en-rCA/strings.xml
+++ b/car-apps-common/res/values-en-rCA/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"Expand/collapse button"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"Open drawer"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"Close drawer"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"Feature not available while driving."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"Scroll down"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"Scroll up"</string>
</resources>
diff --git a/car-apps-common/res/values-en-rGB/strings.xml b/car-apps-common/res/values-en-rGB/strings.xml
index 1f7e3ee..691ae06 100644
--- a/car-apps-common/res/values-en-rGB/strings.xml
+++ b/car-apps-common/res/values-en-rGB/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"Expand/collapse button"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"Open drawer"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"Close drawer"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"Feature not available while driving."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"Scroll down"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"Scroll up"</string>
</resources>
diff --git a/car-apps-common/res/values-en-rIN/strings.xml b/car-apps-common/res/values-en-rIN/strings.xml
index 1f7e3ee..691ae06 100644
--- a/car-apps-common/res/values-en-rIN/strings.xml
+++ b/car-apps-common/res/values-en-rIN/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"Expand/collapse button"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"Open drawer"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"Close drawer"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"Feature not available while driving."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"Scroll down"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"Scroll up"</string>
</resources>
diff --git a/car-apps-common/res/values-en-rXC/strings.xml b/car-apps-common/res/values-en-rXC/strings.xml
index 84a9342..d9b3382 100644
--- a/car-apps-common/res/values-en-rXC/strings.xml
+++ b/car-apps-common/res/values-en-rXC/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"Expand/collapse button"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"Open drawer"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"Close drawer"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"Feature not available while driving."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"Scroll down"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"Scroll up"</string>
</resources>
diff --git a/car-apps-common/res/values-es-rUS/strings.xml b/car-apps-common/res/values-es-rUS/strings.xml
index 3cb67f5..df2217f 100644
--- a/car-apps-common/res/values-es-rUS/strings.xml
+++ b/car-apps-common/res/values-es-rUS/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"Botón Expandir/contraer"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"Abrir panel lateral"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"Cerrar panel lateral"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"Esta función no está disponible mientras conduces."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"Desplazarse hacia abajo"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"Desplazarse hacia arriba"</string>
</resources>
diff --git a/car-apps-common/res/values-es/strings.xml b/car-apps-common/res/values-es/strings.xml
index af625e4..23fcbc5 100644
--- a/car-apps-common/res/values-es/strings.xml
+++ b/car-apps-common/res/values-es/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"Botón para mostrar u ocultar"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"Abrir panel"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"Cerrar panel"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"Esta función no está disponible mientras conduces."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"Desplazarse hacia abajo"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"Desplazarse hacia arriba"</string>
</resources>
diff --git a/car-apps-common/res/values-et/strings.xml b/car-apps-common/res/values-et/strings.xml
index 67a19a1..7475c1a 100644
--- a/car-apps-common/res/values-et/strings.xml
+++ b/car-apps-common/res/values-et/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"Nupp Laienda/Ahenda"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"Ava sahtel"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"Sule sahtel"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"Funktsioon pole sõidu ajal saadaval."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"Keri alla"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"Keri üles"</string>
</resources>
diff --git a/car-apps-common/res/values-eu/strings.xml b/car-apps-common/res/values-eu/strings.xml
index 5de1636..a974c40 100644
--- a/car-apps-common/res/values-eu/strings.xml
+++ b/car-apps-common/res/values-eu/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"Zabaltzeko/Tolesteko botoia"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"Ireki panel lerrakorra"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"Itxi panel lerrakorra"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"Eginbide hau ezin da erabili gidatu bitartean."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"Egin behera"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"Egin gora"</string>
</resources>
diff --git a/car-apps-common/res/values-fa/strings.xml b/car-apps-common/res/values-fa/strings.xml
index 44bdebc..5586b6d 100644
--- a/car-apps-common/res/values-fa/strings.xml
+++ b/car-apps-common/res/values-fa/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"دکمه بزرگ کردن/کوچک کردن"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"باز کردن کشو"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"بستن کشو"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"هنگام رانندگی، این ویژگی در دسترس نیست."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"پیمایش به پایین"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"پیمایش به بالا"</string>
</resources>
diff --git a/car-apps-common/res/values-fi/strings.xml b/car-apps-common/res/values-fi/strings.xml
index c83f79d..baa420f 100644
--- a/car-apps-common/res/values-fi/strings.xml
+++ b/car-apps-common/res/values-fi/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"Laajennus- ja tiivistyspainike"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"Avaa vetopaneeli"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"Sulje vetopaneeli"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"Ominaisuus ei ole käytettävissä ajon aikana."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"Vieritä alas"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"Vieritä ylös"</string>
</resources>
diff --git a/car-apps-common/res/values-fr-rCA/strings.xml b/car-apps-common/res/values-fr-rCA/strings.xml
index 054a3dd..5876f75 100644
--- a/car-apps-common/res/values-fr-rCA/strings.xml
+++ b/car-apps-common/res/values-fr-rCA/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"Bouton Développer/Réduire"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"Ouvrir le tiroir"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"Fermer le tiroir"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"Cette fonction n\'est pas accessible durant la conduite."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"Faire défiler vers le bas"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"Faire défiler vers le haut"</string>
</resources>
diff --git a/car-apps-common/res/values-fr/strings.xml b/car-apps-common/res/values-fr/strings.xml
index a19a5e9..454c27d 100644
--- a/car-apps-common/res/values-fr/strings.xml
+++ b/car-apps-common/res/values-fr/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"Bouton Développer/Réduire"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"Ouvrir le panneau"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"Fermer le panneau"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"Fonctionnalité non disponible lorsque vous conduisez."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"Faire défiler l\'écran vers le bas"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"Faire défiler l\'écran vers le haut"</string>
</resources>
diff --git a/car-apps-common/res/values-gl/strings.xml b/car-apps-common/res/values-gl/strings.xml
index d4b9015..bd2b8ae 100644
--- a/car-apps-common/res/values-gl/strings.xml
+++ b/car-apps-common/res/values-gl/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"Botón despregar/contraer"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"Abrir panel"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"Pecha panel"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"Esta función non está dispoñible mentres conduces."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"Desprazarse cara abaixo"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"Desprazarse cara arriba"</string>
</resources>
diff --git a/car-apps-common/res/values-gu/strings.xml b/car-apps-common/res/values-gu/strings.xml
index 6156522..ed142d2 100644
--- a/car-apps-common/res/values-gu/strings.xml
+++ b/car-apps-common/res/values-gu/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"મોટું કરો/નાનું કરો બટન"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"ડ્રોઅર ખોલો"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"ડ્રોઅર બંધ કરો"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"ડ્રાઇવિંગ કરતી વખતે આ સુવિધા ઉપલબ્ધ રહેશે નહીં."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"નીચેની તરફ સ્ક્રોલ કરો"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"ઉપરની તરફ સ્ક્રોલ કરો"</string>
</resources>
diff --git a/car-apps-common/res/values-hi/strings.xml b/car-apps-common/res/values-hi/strings.xml
index 1949838..d703af5 100644
--- a/car-apps-common/res/values-hi/strings.xml
+++ b/car-apps-common/res/values-hi/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"बड़ा/छोटा करने वाला बटन"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"दराज खोलें"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"दराज बंद करें"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"गाड़ी चलाते समय इस सुविधा का इस्तेमाल नहीं किया जा सकता."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"नीचे स्क्रोल करें"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"ऊपर स्क्रोल करें"</string>
</resources>
diff --git a/car-apps-common/res/values-hr/strings.xml b/car-apps-common/res/values-hr/strings.xml
index 0f58e0a..d51f1da 100644
--- a/car-apps-common/res/values-hr/strings.xml
+++ b/car-apps-common/res/values-hr/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"Gumb za proširivanje/sažimanje"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"Otvori ladicu"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"Zatvori ladicu"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"Značajka nije dostupna tijekom vožnje."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"Pomakni prema dolje"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"Pomakni prema gore"</string>
</resources>
diff --git a/car-apps-common/res/values-hu/strings.xml b/car-apps-common/res/values-hu/strings.xml
index 33460ab..072f171 100644
--- a/car-apps-common/res/values-hu/strings.xml
+++ b/car-apps-common/res/values-hu/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"Gomb kibontása/összecsukása"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"Fiók megnyitása"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"Fiók bezárása"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"Vezetés közben nem áll rendelkezésre a funkció."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"Görgetés lefelé"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"Görgetés felfelé"</string>
</resources>
diff --git a/car-apps-common/res/values-hy/strings.xml b/car-apps-common/res/values-hy/strings.xml
index ac21642..83ec434 100644
--- a/car-apps-common/res/values-hy/strings.xml
+++ b/car-apps-common/res/values-hy/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"«Ծավալել/ծալել» կոճակ"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"Բացել դարակը"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"Փակել դարակը"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"Վարելու ընթացքում գործառույթը հասանելի չէ:"</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"Ոլորել վար"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"Ոլորել վեր"</string>
</resources>
diff --git a/car-apps-common/res/values-in/strings.xml b/car-apps-common/res/values-in/strings.xml
index 6c47078..bf170e7 100644
--- a/car-apps-common/res/values-in/strings.xml
+++ b/car-apps-common/res/values-in/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"Tombol luaskan/ciutkan"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"Buka panel samping"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"Tutup panel samping"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"Fitur tidak tersedia saat mengemudi."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"Scroll ke bawah"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"Scroll ke atas"</string>
</resources>
diff --git a/car-apps-common/res/values-is/strings.xml b/car-apps-common/res/values-is/strings.xml
index 363679e..2c4c07d 100644
--- a/car-apps-common/res/values-is/strings.xml
+++ b/car-apps-common/res/values-is/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"Hnappur til að stækka/minnka"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"Opna skúffu"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"Loka skúffu"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"Þessi eiginleiki er ekki í boði á meðan þú ekur."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"Fletta niður"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"Fletta upp"</string>
</resources>
diff --git a/car-apps-common/res/values-it/strings.xml b/car-apps-common/res/values-it/strings.xml
index 53b635f..37635fd 100644
--- a/car-apps-common/res/values-it/strings.xml
+++ b/car-apps-common/res/values-it/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"Pulsante Espandi/Comprimi"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"Apri riquadro a scomparsa"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"Chiudi riquadro a scomparsa"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"Funzione non disponibile durante la guida."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"Scorri verso il basso"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"Scorri verso l\'alto"</string>
</resources>
diff --git a/car-apps-common/res/values-iw/strings.xml b/car-apps-common/res/values-iw/strings.xml
index 6ebeda2..417b016 100644
--- a/car-apps-common/res/values-iw/strings.xml
+++ b/car-apps-common/res/values-iw/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"לחצן הרחבה וכיווץ"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"פתיחת חלונית ההזזה"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"סגירת חלונית ההזזה"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"התכונה לא זמינה במהלך הנהיגה."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"גלילה למטה"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"גלילה למעלה"</string>
</resources>
diff --git a/car-apps-common/res/values-ja/strings.xml b/car-apps-common/res/values-ja/strings.xml
index 5ee06b4..6a7ace0 100644
--- a/car-apps-common/res/values-ja/strings.xml
+++ b/car-apps-common/res/values-ja/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"展開 / 折りたたみボタン"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"ドロワーを開く"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"ドロワーを閉じる"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"この機能は運転中は利用できません。"</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"下にスクロール"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"上にスクロール"</string>
</resources>
diff --git a/car-apps-common/res/values-ka/strings.xml b/car-apps-common/res/values-ka/strings.xml
index 17a25b1..d95190b 100644
--- a/car-apps-common/res/values-ka/strings.xml
+++ b/car-apps-common/res/values-ka/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"გაშლის/ჩაკეცვის ღილაკი"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"უჯრის გახსნა"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"უჯრის დახურვა"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"ფუნქცია მიუწვდომელია მანქანის მართვისას."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"ქვემოთ გადაადგილება"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"ზემოთ გადაადგილება"</string>
</resources>
diff --git a/car-apps-common/res/values-kk/strings.xml b/car-apps-common/res/values-kk/strings.xml
index be6baac..1366c3b 100644
--- a/car-apps-common/res/values-kk/strings.xml
+++ b/car-apps-common/res/values-kk/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"\"Жаю/Жию\" түймесі"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"Тартпаны ашу"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"Тартпаны жабу"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"Көлік жүргізу кезінде бұл функция жұмыс істемейді."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"Төмен қарай айналдыру"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"Жоғары қарай айналдыру"</string>
</resources>
diff --git a/car-apps-common/res/values-km/strings.xml b/car-apps-common/res/values-km/strings.xml
index 4c19ca7..4a695e0 100644
--- a/car-apps-common/res/values-km/strings.xml
+++ b/car-apps-common/res/values-km/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"ប៊ូតុងពង្រីក/បង្រួម"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"បើកថត"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"បិទថត"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"មិនអាចប្រើមុខងារនេះបានទេ ខណៈពេលកំពុងបើកបរ។"</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"រំកិលចុះក្រោម"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"រំកិលឡើងលើ"</string>
</resources>
diff --git a/car-apps-common/res/values-kn/strings.xml b/car-apps-common/res/values-kn/strings.xml
index 0cb37ec..f7bdb7f 100644
--- a/car-apps-common/res/values-kn/strings.xml
+++ b/car-apps-common/res/values-kn/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"ವಿಸ್ತರಿಸಿ/ಕುಗ್ಗಿಸಿ ಬಟನ್"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"ಡ್ರಾಯರ್ ತೆರೆಯಿರಿ"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"ಡ್ರಾಯರ್ ಮುಚ್ಚಿರಿ"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"ಡ್ರೈವ್ ಮಾಡುವಾಗ ಈ ವೈಶಿಷ್ಟ್ಯ ಲಭ್ಯವಿಲ್ಲ."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"ಕೆಳಗೆ ಸ್ಕ್ರಾಲ್ ಮಾಡಿ"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"ಮೇಲೆ ಸ್ಕ್ರಾಲ್ ಮಾಡಿ"</string>
</resources>
diff --git a/car-apps-common/res/values-ko/strings.xml b/car-apps-common/res/values-ko/strings.xml
index 3a4a36a..526c776 100644
--- a/car-apps-common/res/values-ko/strings.xml
+++ b/car-apps-common/res/values-ko/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"펼치기/접기 버튼"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"창 열기"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"창 닫기"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"운전 중 기능 사용 불가"</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"아래로 스크롤"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"위로 스크롤"</string>
</resources>
diff --git a/car-apps-common/res/values-ky/strings.xml b/car-apps-common/res/values-ky/strings.xml
index 1ab6f75..23ac2c0 100644
--- a/car-apps-common/res/values-ky/strings.xml
+++ b/car-apps-common/res/values-ky/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"Жайып көрсөтүү/жыйыштыруу баскычы"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"Суурманы ачуу"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"Суурманы жабуу"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"Унаа айдаганда бул функция жеткиликтүү эмес."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"Төмөн сыдыруу"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"Жогору сыдыруу"</string>
</resources>
diff --git a/car-apps-common/res/values-lo/strings.xml b/car-apps-common/res/values-lo/strings.xml
index 55e68ba..d52a414 100644
--- a/car-apps-common/res/values-lo/strings.xml
+++ b/car-apps-common/res/values-lo/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"ປຸ່ມຫຍໍ້/ຂະຫຍາຍ"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"ເປີດລິ້ນຊັກ"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"ປິດລິ້ນຊັກ"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"ຄຸນສົມບັດບໍ່ສາມາດໃຊ້ໄດ້ໃນເວລາຂັບລົດ."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"ເລື່ອນລົງ"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"ເລື່ອນຂຶ້ນ"</string>
</resources>
diff --git a/car-apps-common/res/values-lt/strings.xml b/car-apps-common/res/values-lt/strings.xml
index daf7367..db4a28d 100644
--- a/car-apps-common/res/values-lt/strings.xml
+++ b/car-apps-common/res/values-lt/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"Mygtukas „Išskleisti / sutraukti“"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"Atidaryti skydelį"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"Uždaryti skydelį"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"Funkcija nepasiekiama vairuojant."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"Slinkti žemyn"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"Slinkti aukštyn"</string>
</resources>
diff --git a/car-apps-common/res/values-lv/strings.xml b/car-apps-common/res/values-lv/strings.xml
index df04f11..3b72539 100644
--- a/car-apps-common/res/values-lv/strings.xml
+++ b/car-apps-common/res/values-lv/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"Izvēršanas/sakļaušanas poga"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"Atvērt atvilktni"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"Aizvērt atvilktni"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"Funkcija nav pieejama braukšanas laikā."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"Ritināt uz leju"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"Ritināt uz augšu"</string>
</resources>
diff --git a/car-apps-common/res/values-mk/strings.xml b/car-apps-common/res/values-mk/strings.xml
index 1584020..b43a4d1 100644
--- a/car-apps-common/res/values-mk/strings.xml
+++ b/car-apps-common/res/values-mk/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"Копче за проширување/собирање"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"Отвори ја фиоката"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"Затвори ја фиоката"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"Функцијата не е достапна при возење."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"Оди надолу"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"Оди нагоре"</string>
</resources>
diff --git a/car-apps-common/res/values-ml/strings.xml b/car-apps-common/res/values-ml/strings.xml
index b223e67..6b6c309 100644
--- a/car-apps-common/res/values-ml/strings.xml
+++ b/car-apps-common/res/values-ml/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"വികസിപ്പിക്കുക/ചുരുക്കുക ബട്ടൺ"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"വലിപ്പ് തുറക്കുക"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"വലിപ്പ് അടയ്ക്കുക"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"ഡ്രൈവ് ചെയ്യുമ്പോൾ ഫീച്ചർ ലഭ്യമല്ല."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"താഴോട്ട് സ്ക്രോൾ ചെയ്യുക"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"മുകളിലോട്ട് സ്ക്രോൾ ചെയ്യുക"</string>
</resources>
diff --git a/car-apps-common/res/values-mn/strings.xml b/car-apps-common/res/values-mn/strings.xml
index 4729d39..92a8dae 100644
--- a/car-apps-common/res/values-mn/strings.xml
+++ b/car-apps-common/res/values-mn/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"Дэлгэх/буулгах товчлуур"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"Шургуулгыг нээх"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"Шургуулгыг хаах"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"Жолоо барьж байх үед онцлог боломжгүй."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"Доош гүйлгэх"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"Дээш гүйлгэх"</string>
</resources>
diff --git a/car-apps-common/res/values-mr/strings.xml b/car-apps-common/res/values-mr/strings.xml
index e8077d5..671b387 100644
--- a/car-apps-common/res/values-mr/strings.xml
+++ b/car-apps-common/res/values-mr/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"बटण विस्तृत करा/कोलॅप्स करा"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"ड्रॉवर उघडा"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"ड्रॉवर बंद करा"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"ड्राइव्ह करताना वैशिष्ट्य उपलब्ध नाही."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"खाली स्क्रोल करा"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"वर स्क्रोल करा"</string>
</resources>
diff --git a/car-apps-common/res/values-ms/strings.xml b/car-apps-common/res/values-ms/strings.xml
index 2b59158..4a5c1e6 100644
--- a/car-apps-common/res/values-ms/strings.xml
+++ b/car-apps-common/res/values-ms/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"Butang kembangkan/runtuhkan"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"Buka laci"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"Tutup laci"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"Ciri tidak tersedia semasa anda memandu."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"Tatal ke bawah"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"Tatal ke atas"</string>
</resources>
diff --git a/car-apps-common/res/values-my/strings.xml b/car-apps-common/res/values-my/strings.xml
index 7223458..cf2fcf6 100644
--- a/car-apps-common/res/values-my/strings.xml
+++ b/car-apps-common/res/values-my/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"ချဲ့ရန်/လျှော့ပြရန် ခလုတ်"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"အံဆွဲ ဖွင့်ရန်"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"အံဆွဲ ပိတ်ရန်"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"ကားမောင်းနေစဉ် ဝန်ဆောင်မှု မရနိုင်ပါ။"</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"အောက်သို့ လှိမ့်ရန်"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"အပေါ်သို့ လှိမ့်ရန်"</string>
</resources>
diff --git a/car-apps-common/res/values-nb/strings.xml b/car-apps-common/res/values-nb/strings.xml
index 435f397..0fb9039 100644
--- a/car-apps-common/res/values-nb/strings.xml
+++ b/car-apps-common/res/values-nb/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"Vis/skjul-knapp"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"Åpne uttrekksmenyen"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"Lukk uttrekksmenyen"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"Funksjonen er ikke tilgjengelig når du kjører."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"Rull ned"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"Rull opp"</string>
</resources>
diff --git a/car-apps-common/res/values-ne/strings.xml b/car-apps-common/res/values-ne/strings.xml
index 13e4f75..1599bc8 100644
--- a/car-apps-common/res/values-ne/strings.xml
+++ b/car-apps-common/res/values-ne/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"विस्तृत/संक्षिप्त गर्ने बटन"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"ड्रअर खोल्नुहोस्"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"ड्रअर बन्द गर्नुहोस्"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"सवारी साधन चलाइरहेका बेला यो सुविधा उपलब्ध छैन।"</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"तल स्क्रोल गर्नुहोस्"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"माथितिर स्क्रोल गर्नुहोस्"</string>
</resources>
diff --git a/car-apps-common/res/values-nl/strings.xml b/car-apps-common/res/values-nl/strings.xml
index 749174f..0c7f378 100644
--- a/car-apps-common/res/values-nl/strings.xml
+++ b/car-apps-common/res/values-nl/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"Knop voor uitvouwen/samenvouwen"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"Lade openen"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"Lade sluiten"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"Functie niet beschikbaar tijdens het rijden."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"Omlaag scrollen"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"Omhoog scrollen"</string>
</resources>
diff --git a/car-apps-common/res/values-or/strings.xml b/car-apps-common/res/values-or/strings.xml
index b0dbe9d..b921f45 100644
--- a/car-apps-common/res/values-or/strings.xml
+++ b/car-apps-common/res/values-or/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"ବିସ୍ତାର/ସଂକୋଚନ ବଟନ୍"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"ଡ୍ରୟର୍ ଖୋଲନ୍ତୁ"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"ଡ୍ରୟର୍ ବନ୍ଦ କରନ୍ତୁ"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"ଗାଡ଼ି ଚଲାଇବା ସମୟରେ ଫିଚର୍ ଉପଲବ୍ଧ ହେବ ନାହିଁ।"</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"ତଳକୁ ସ୍କ୍ରୋଲ୍ କରନ୍ତୁ"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"ଉପରକୁ ସ୍କ୍ରୋଲ୍ କରନ୍ତୁ"</string>
</resources>
diff --git a/car-apps-common/res/values-pa/strings.xml b/car-apps-common/res/values-pa/strings.xml
index 3dcd926..f6c1657 100644
--- a/car-apps-common/res/values-pa/strings.xml
+++ b/car-apps-common/res/values-pa/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"ਵਿਸਤਾਰ ਕਰੋ/ਸਮੇਟੋ ਬਟਨ"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"ਦਰਾਜ਼ ਖੋਲ੍ਹੋ"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"ਦਰਾਜ਼ ਬੰਦ ਕਰੋ"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"ਗੱਡੀ ਚਲਾਉਣ ਵੇਲੇ ਵਿਸ਼ੇਸ਼ਤਾ ਉਪਲਬਧ ਨਹੀਂ ਹੈ।"</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"ਹੇਠਾਂ ਵੱਲ ਸਕ੍ਰੋਲ ਕਰੋ"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"ਉੱਪਰ ਵੱਲ ਸਕ੍ਰੋਲ ਕਰੋ"</string>
</resources>
diff --git a/car-apps-common/res/values-pl/strings.xml b/car-apps-common/res/values-pl/strings.xml
index e42a2ee..2ad6309 100644
--- a/car-apps-common/res/values-pl/strings.xml
+++ b/car-apps-common/res/values-pl/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"Przycisk zwijania/rozwijania"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"Otwórz panel"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"Zamknij panel"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"Funkcja niedostępna podczas jazdy."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"Przewiń w dół"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"Przewiń w górę"</string>
</resources>
diff --git a/car-apps-common/res/values-pt-rPT/strings.xml b/car-apps-common/res/values-pt-rPT/strings.xml
index 37114f5..0d461e3 100644
--- a/car-apps-common/res/values-pt-rPT/strings.xml
+++ b/car-apps-common/res/values-pt-rPT/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"Botão Expandir/reduzir"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"Abrir gaveta"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"Fechar gaveta"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"Funcionalidade não disponível durante a condução."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"Deslocar para baixo"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"Deslocar para cima"</string>
</resources>
diff --git a/car-apps-common/res/values-pt/strings.xml b/car-apps-common/res/values-pt/strings.xml
index f38bff3..118bf92 100644
--- a/car-apps-common/res/values-pt/strings.xml
+++ b/car-apps-common/res/values-pt/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"Botão \"Expandir/Recolher\""</string>
<string name="car_drawer_open" msgid="2676372472514742324">"Abrir gaveta"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"Fechar gaveta"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"Recurso não disponível enquanto você dirige."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"Rolar para baixo"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"Rolar para cima"</string>
</resources>
diff --git a/car-apps-common/res/values-ro/strings.xml b/car-apps-common/res/values-ro/strings.xml
index 18d6d2c..6a78b9c 100644
--- a/car-apps-common/res/values-ro/strings.xml
+++ b/car-apps-common/res/values-ro/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"Butonul de extindere/restrângere"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"Deschideți panoul"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"Închideți panoul"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"Funcția nu este disponibilă când conduceți."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"Derulați în jos"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"Derulați în sus"</string>
</resources>
diff --git a/car-apps-common/res/values-ru/strings.xml b/car-apps-common/res/values-ru/strings.xml
index f806465..11e0f3e 100644
--- a/car-apps-common/res/values-ru/strings.xml
+++ b/car-apps-common/res/values-ru/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"Кнопка \"Развернуть/свернуть\""</string>
<string name="car_drawer_open" msgid="2676372472514742324">"Открыть панель"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"Закрыть панель"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"Эта функция недоступна, когда вы за рулем."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"Прокрутить вниз"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"Прокрутить вверх"</string>
</resources>
diff --git a/car-apps-common/res/values-si/strings.xml b/car-apps-common/res/values-si/strings.xml
index 0a90820..8d2f5d6 100644
--- a/car-apps-common/res/values-si/strings.xml
+++ b/car-apps-common/res/values-si/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"දිග හැරීමේ/හැකිළීමේ බොත්තම"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"ලාච්චුව විවෘත කරන්න"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"ලාච්චුව වසන්න"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"විශේෂාංගය රිය පැදවීමේ දී නොමැත."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"පහළට අනුචලනය කරන්න"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"ඉහළට අනුචලනය කරන්න"</string>
</resources>
diff --git a/car-apps-common/res/values-sk/strings.xml b/car-apps-common/res/values-sk/strings.xml
index 42522e1..3159fb6 100644
--- a/car-apps-common/res/values-sk/strings.xml
+++ b/car-apps-common/res/values-sk/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"Tlačidlo rozbalenia/zbalenia"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"Otvoriť vysúvací panel"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"Zavrieť vysúvací panel"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"Funkcia nie je k dispozícii počas jazdy."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"Posunúť nadol"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"Posunúť nahor"</string>
</resources>
diff --git a/car-apps-common/res/values-sl/strings.xml b/car-apps-common/res/values-sl/strings.xml
index fbb4daf..14457c2 100644
--- a/car-apps-common/res/values-sl/strings.xml
+++ b/car-apps-common/res/values-sl/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"Gumb za razširitev/strnitev"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"Odpri predal"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"Zapri predal"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"Funkcija med vožnjo ni na voljo."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"Pomik navzdol"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"Pomik navzgor"</string>
</resources>
diff --git a/car-apps-common/res/values-sq/strings.xml b/car-apps-common/res/values-sq/strings.xml
index 1e92a82..4b980c3 100644
--- a/car-apps-common/res/values-sq/strings.xml
+++ b/car-apps-common/res/values-sq/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"Butoni i zgjerimit/palosjes"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"Hap sirtarin"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"Mbyll sirtarin"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"Funksioni nuk ofrohet gjatë drejtimit të makinës."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"Lëviz poshtë"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"Lëviz lart"</string>
</resources>
diff --git a/car-apps-common/res/values-sr/strings.xml b/car-apps-common/res/values-sr/strings.xml
index 65257dd..60b1615 100644
--- a/car-apps-common/res/values-sr/strings.xml
+++ b/car-apps-common/res/values-sr/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"Дугме Прошири/скупи"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"Отвори фиоку"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"Затвори фиоку"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"Функција није доступна током вожње."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"Померите надоле"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"Померите нагоре"</string>
</resources>
diff --git a/car-apps-common/res/values-sv/strings.xml b/car-apps-common/res/values-sv/strings.xml
index b13c40e..84d19f1 100644
--- a/car-apps-common/res/values-sv/strings.xml
+++ b/car-apps-common/res/values-sv/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"Knappen Utöka/komprimera"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"Öppna utdragbar panel"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"Stäng utdragbar panel"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"Funktionen är inte tillgänglig när du kör."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"Skrolla nedåt"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"Skrolla uppåt"</string>
</resources>
diff --git a/car-apps-common/res/values-sw/strings.xml b/car-apps-common/res/values-sw/strings.xml
index 57bca14..04ccada 100644
--- a/car-apps-common/res/values-sw/strings.xml
+++ b/car-apps-common/res/values-sw/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"Kitufe cha kupanua/kukunja"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"Fungua droo"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"Funga droo"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"Kipengele hakipatikani unapoendesha gari."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"Sogeza chini"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"Sogeza juu"</string>
</resources>
diff --git a/car-apps-common/res/values-ta/strings.xml b/car-apps-common/res/values-ta/strings.xml
index 86ce09b..c88f072 100644
--- a/car-apps-common/res/values-ta/strings.xml
+++ b/car-apps-common/res/values-ta/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"விரிவாக்குவதற்கான/சுருக்குவதற்கான பட்டன்"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"டிராயரைத் திற"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"டிராயரை மூடுக"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"வாகனம் ஓட்டும்போது இந்த அம்சத்தைப் பயன்படுத்த இயலாது."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"கீழே நகர்த்துவதற்கான பட்டன்"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"மேலே நகர்த்துவதற்கான பட்டன்"</string>
</resources>
diff --git a/car-apps-common/res/values-te/strings.xml b/car-apps-common/res/values-te/strings.xml
index 741d734..b2fce0a 100644
--- a/car-apps-common/res/values-te/strings.xml
+++ b/car-apps-common/res/values-te/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"విస్తరించు/కుదించు బటన్"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"డ్రాయర్ని తెరవండి"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"డ్రాయర్ను మూసివేయండి"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"డ్రైవింగ్ చేస్తున్నప్పుడు ఈ ఫీచర్ అందుబాటులో ఉండదు."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"కిందకు స్క్రోల్ చేయి"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"పైకి స్క్రోల్ చేయి"</string>
</resources>
diff --git a/car-apps-common/res/values-th/strings.xml b/car-apps-common/res/values-th/strings.xml
index 06f6ea9..93a7943 100644
--- a/car-apps-common/res/values-th/strings.xml
+++ b/car-apps-common/res/values-th/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"ปุ่มขยาย/ยุบ"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"เปิดลิ้นชัก"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"ปิดลิ้นชัก"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"ฟีเจอร์ไม่พร้อมใช้งานขณะขับรถ"</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"เลื่อนลง"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"เลื่อนขึ้น"</string>
</resources>
diff --git a/car-apps-common/res/values-tl/strings.xml b/car-apps-common/res/values-tl/strings.xml
index ed9e4a3..ef72afb 100644
--- a/car-apps-common/res/values-tl/strings.xml
+++ b/car-apps-common/res/values-tl/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"Button na palawakin/i-collapse"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"Buksan ang drawer"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"Isara ang drawer"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"Hindi available ang feature habang nagmamaneho."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"Mag-scroll pababa"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"Mag-scroll pataas"</string>
</resources>
diff --git a/car-apps-common/res/values-tr/strings.xml b/car-apps-common/res/values-tr/strings.xml
index ffa0541..db95a8b 100644
--- a/car-apps-common/res/values-tr/strings.xml
+++ b/car-apps-common/res/values-tr/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"Genişlet/daralt düğmesi"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"Çekmeceyi aç"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"Çekmeceyi kapat"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"Sürüş sırasında bu özellik kullanılamaz."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"Aşağı kaydır"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"Yukarı kaydır"</string>
</resources>
diff --git a/car-apps-common/res/values-uk/strings.xml b/car-apps-common/res/values-uk/strings.xml
index 56b6f6b..879da02 100644
--- a/car-apps-common/res/values-uk/strings.xml
+++ b/car-apps-common/res/values-uk/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"Кнопка \"Розгорнути\" або \"Згорнути\""</string>
<string name="car_drawer_open" msgid="2676372472514742324">"Відкрити висувну панель"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"Закрити висувну панель"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"Функція недоступна під час руху автомобіля."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"Прокрутити вниз"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"Прокрутити вгору"</string>
</resources>
diff --git a/car-apps-common/res/values-ur/strings.xml b/car-apps-common/res/values-ur/strings.xml
index 23de779..a9ab004 100644
--- a/car-apps-common/res/values-ur/strings.xml
+++ b/car-apps-common/res/values-ur/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"پھیلائیں/سکیڑیں بٹن"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"دراز کھولیں"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"دراز بند کریں"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"ڈرائیونگ کے دوران یہ خصوصیت دستیاب نہیں ہے۔"</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"نیچے اسکرول کریں"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"اوپر اسکرول کریں"</string>
</resources>
diff --git a/car-apps-common/res/values-uz/strings.xml b/car-apps-common/res/values-uz/strings.xml
index 685207c..65d2811 100644
--- a/car-apps-common/res/values-uz/strings.xml
+++ b/car-apps-common/res/values-uz/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"Yoyish/yigʻish tugmasi"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"Panelni ochish"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"Panelni yopish"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"Avtomobilda harakatlanayotganda bu funksiya ishlamaydi."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"Pastga tushish"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"Tepaga chiqish"</string>
</resources>
diff --git a/car-apps-common/res/values-vi/strings.xml b/car-apps-common/res/values-vi/strings.xml
index 58edc17..044b905 100644
--- a/car-apps-common/res/values-vi/strings.xml
+++ b/car-apps-common/res/values-vi/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"Nút mở rộng/thu gọn"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"Mở ngăn"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"Đóng ngăn"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"Bạn không sử dụng được tính năng này khi đang lái xe."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"Cuộn xuống"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"Cuộn lên"</string>
</resources>
diff --git a/car-apps-common/res/values-zh-rCN/strings.xml b/car-apps-common/res/values-zh-rCN/strings.xml
index b1ad3ae..2c14a4d 100644
--- a/car-apps-common/res/values-zh-rCN/strings.xml
+++ b/car-apps-common/res/values-zh-rCN/strings.xml
@@ -16,8 +16,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for control_bar_expand_collapse_button (3420351169078117938) -->
- <skip />
+ <string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"“展开”/“收起”按钮"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"打开抽屉式导航栏"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"关闭抽屉式导航栏"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"驾车时无法使用此功能。"</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"向下滚动"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"向上滚动"</string>
</resources>
diff --git a/car-apps-common/res/values-zh-rHK/strings.xml b/car-apps-common/res/values-zh-rHK/strings.xml
index 5738612..2442206 100644
--- a/car-apps-common/res/values-zh-rHK/strings.xml
+++ b/car-apps-common/res/values-zh-rHK/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"展開/收合按鈕"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"開啟導覽列"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"關閉導覽列"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"無法在駕駛時使用此功能。"</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"向下捲動"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"向上捲動"</string>
</resources>
diff --git a/car-apps-common/res/values-zh-rTW/strings.xml b/car-apps-common/res/values-zh-rTW/strings.xml
index cb21c87..cc45ad1 100644
--- a/car-apps-common/res/values-zh-rTW/strings.xml
+++ b/car-apps-common/res/values-zh-rTW/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"展開/收合按鈕"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"開啟導覽匣"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"關閉導覽匣"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"開車時無法使用這項功能。"</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"向下捲動"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"向上捲動"</string>
</resources>
diff --git a/car-apps-common/res/values-zu/strings.xml b/car-apps-common/res/values-zu/strings.xml
index 18e2e5c..6f616b1 100644
--- a/car-apps-common/res/values-zu/strings.xml
+++ b/car-apps-common/res/values-zu/strings.xml
@@ -19,4 +19,7 @@
<string name="control_bar_expand_collapse_button" msgid="3420351169078117938">"Inkinobho yokunweba/ukugoqa"</string>
<string name="car_drawer_open" msgid="2676372472514742324">"Vula ikhabethe"</string>
<string name="car_drawer_close" msgid="5329374630462464855">"Vala ikhabethe"</string>
+ <string name="restricted_while_driving" msgid="2278031053760704437">"Isici asitholakali ngenkathi ushayela."</string>
+ <string name="scroll_bar_page_down_button" msgid="8633547153186948066">"Skrolela phansi"</string>
+ <string name="scroll_bar_page_up_button" msgid="8306413844913744345">"Skrolela phezulu"</string>
</resources>
diff --git a/car-apps-common/src/com/android/car/apps/common/imaging/LocalImageFetcher.java b/car-apps-common/src/com/android/car/apps/common/imaging/LocalImageFetcher.java
index e8b245e..17f9f50 100644
--- a/car-apps-common/src/com/android/car/apps/common/imaging/LocalImageFetcher.java
+++ b/car-apps-common/src/com/android/car/apps/common/imaging/LocalImageFetcher.java
@@ -19,7 +19,6 @@
import android.annotation.UiThread;
import android.content.ContentResolver;
import android.content.Context;
-import android.content.res.AssetFileDescriptor;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.ImageDecoder;
@@ -36,11 +35,8 @@
import com.android.car.apps.common.UriUtils;
import com.android.car.apps.common.util.CarAppsIOUtils;
-import libcore.io.IoUtils;
-
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
-import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;
@@ -265,18 +261,8 @@
UriUtils.getIconResource(context, imageUri));
} else if (UriUtils.isContentUri(imageUri)) {
ContentResolver resolver = context.getContentResolver();
-
- // TODO(b/140959390): Remove the check once the bug is fixed in framework.
- if (!hasFile(resolver, imageUri)) {
- if (L_WARN) {
- Log.w(TAG, "File not found in uri: " + imageUri);
- }
- return null;
- }
-
ImageDecoder.Source src = ImageDecoder.createSource(resolver, imageUri);
return ImageDecoder.decodeDrawable(src, mOnHeaderDecodedListener);
-
} else if (mFlagRemoteImages) {
mAllocatorMode = ImageDecoder.ALLOCATOR_SOFTWARE; // Needed for canvas drawing.
URL url = new URL(imageUri.toString());
@@ -300,34 +286,6 @@
return null;
}
- private boolean hasFile(ContentResolver resolver, Uri uri) {
- AssetFileDescriptor assetFd = null;
- try {
- if (uri.getScheme() == ContentResolver.SCHEME_CONTENT) {
- assetFd = resolver.openTypedAssetFileDescriptor(uri, "image/*", null);
- } else {
- assetFd = resolver.openAssetFileDescriptor(uri, "r");
- }
- } catch (FileNotFoundException e) {
- // Some images cannot be opened as AssetFileDescriptors (e.g.bmp, ico). Open them
- // as InputStreams.
- try {
- InputStream is = resolver.openInputStream(uri);
- if (is != null) {
- IoUtils.closeQuietly(is);
- return true;
- }
- } catch (IOException exception) {
- return false;
- }
- }
- if (assetFd != null) {
- IoUtils.closeQuietly(assetFd);
- return true;
- }
- return false;
- }
-
@UiThread
@Override
protected void onPostExecute(Drawable drawable) {
diff --git a/car-apps-common/src/com/android/car/apps/common/widget/PagedRecyclerView.java b/car-apps-common/src/com/android/car/apps/common/widget/PagedRecyclerView.java
index 2917967..ca8dfcf 100644
--- a/car-apps-common/src/com/android/car/apps/common/widget/PagedRecyclerView.java
+++ b/car-apps-common/src/com/android/car/apps/common/widget/PagedRecyclerView.java
@@ -340,6 +340,15 @@
}
@Override
+ public void scrollToPosition(int position) {
+ if (mScrollBarEnabled) {
+ mNestedRecyclerView.scrollToPosition(position);
+ } else {
+ super.scrollToPosition(position);
+ }
+ }
+
+ @Override
public void setAdapter(@Nullable Adapter adapter) {
mAdapter = adapter;
if (mScrollBarEnabled) {
diff --git a/car-assist-client-lib/res/values-af/strings.xml b/car-assist-client-lib/res/values-af/strings.xml
index 5566520..d6e54fe 100644
--- a/car-assist-client-lib/res/values-af/strings.xml
+++ b/car-assist-client-lib/res/values-af/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"Kon nie handeling deur Assistent versoek nie!"</string>
+ <string name="says" msgid="8575666015622916107">"sê"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-am/strings.xml b/car-assist-client-lib/res/values-am/strings.xml
index bfed26c..2f0855b 100644
--- a/car-assist-client-lib/res/values-am/strings.xml
+++ b/car-assist-client-lib/res/values-am/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"ከረዳት እርምጃ መጠየቅ አልተቻለም!"</string>
+ <string name="says" msgid="8575666015622916107">"እንዲህ ይላሉ"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-ar/strings.xml b/car-assist-client-lib/res/values-ar/strings.xml
index 18bf092..8252183 100644
--- a/car-assist-client-lib/res/values-ar/strings.xml
+++ b/car-assist-client-lib/res/values-ar/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"تعذَّر طلَب إجراء من \"مساعد Google\"."</string>
+ <string name="says" msgid="8575666015622916107">"يقول"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-as/strings.xml b/car-assist-client-lib/res/values-as/strings.xml
index 182082f..eec6ebd 100644
--- a/car-assist-client-lib/res/values-as/strings.xml
+++ b/car-assist-client-lib/res/values-as/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"Assistantএ কামটো কৰিব নোৱাৰিলে!"</string>
+ <string name="says" msgid="8575666015622916107">"এ কৈছে"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-az/strings.xml b/car-assist-client-lib/res/values-az/strings.xml
index 94e3237..386d253 100644
--- a/car-assist-client-lib/res/values-az/strings.xml
+++ b/car-assist-client-lib/res/values-az/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"Assistentdən əməliyyat sorğulamaq mümkün olmadı!"</string>
+ <string name="says" msgid="8575666015622916107">"deyir"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-b+sr+Latn/strings.xml b/car-assist-client-lib/res/values-b+sr+Latn/strings.xml
index afd3feb..eaa8a69 100644
--- a/car-assist-client-lib/res/values-b+sr+Latn/strings.xml
+++ b/car-assist-client-lib/res/values-b+sr+Latn/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"Slanje zahteva za radnju Pomoćnika nije uspelo!"</string>
+ <string name="says" msgid="8575666015622916107">"kaže"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-be/strings.xml b/car-assist-client-lib/res/values-be/strings.xml
index 474a892..a35d999 100644
--- a/car-assist-client-lib/res/values-be/strings.xml
+++ b/car-assist-client-lib/res/values-be/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"Не ўдалося папрасіць Памочніка выканаць дзеянне."</string>
+ <string name="says" msgid="8575666015622916107">"гаворыць"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-bg/strings.xml b/car-assist-client-lib/res/values-bg/strings.xml
index fe35fbb..26f63a4 100644
--- a/car-assist-client-lib/res/values-bg/strings.xml
+++ b/car-assist-client-lib/res/values-bg/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"Не можа да се заяви действие от Асистент!"</string>
+ <string name="says" msgid="8575666015622916107">"казва"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-bn/strings.xml b/car-assist-client-lib/res/values-bn/strings.xml
index b9c1eac..d9ccd59 100644
--- a/car-assist-client-lib/res/values-bn/strings.xml
+++ b/car-assist-client-lib/res/values-bn/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"নির্দেশ অনুসারে অ্যাসিস্ট্যান্ট কাজ করতে পারেনি!"</string>
+ <string name="says" msgid="8575666015622916107">"বলেছেন"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-bs/strings.xml b/car-assist-client-lib/res/values-bs/strings.xml
index dc156c4..8f87241 100644
--- a/car-assist-client-lib/res/values-bs/strings.xml
+++ b/car-assist-client-lib/res/values-bs/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"Nije zatražena akcija Asistenta!"</string>
+ <string name="says" msgid="8575666015622916107">"kaže"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-ca/strings.xml b/car-assist-client-lib/res/values-ca/strings.xml
index 08322f2..78437cb 100644
--- a/car-assist-client-lib/res/values-ca/strings.xml
+++ b/car-assist-client-lib/res/values-ca/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"No s\'ha pogut sol·licitar l\'acció a l\'Assistent."</string>
+ <string name="says" msgid="8575666015622916107">"diu"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-cs/strings.xml b/car-assist-client-lib/res/values-cs/strings.xml
index 561824d..8f54a84 100644
--- a/car-assist-client-lib/res/values-cs/strings.xml
+++ b/car-assist-client-lib/res/values-cs/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"Nebylo možné požádat Asistenta o akci."</string>
+ <string name="says" msgid="8575666015622916107">"říká"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-da/strings.xml b/car-assist-client-lib/res/values-da/strings.xml
index 58e92b9..38dc862 100644
--- a/car-assist-client-lib/res/values-da/strings.xml
+++ b/car-assist-client-lib/res/values-da/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"Handlingen kunne ikke håndteres af Assistent."</string>
+ <string name="says" msgid="8575666015622916107">"siger"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-de/strings.xml b/car-assist-client-lib/res/values-de/strings.xml
index 24af5a2..8f553cb 100644
--- a/car-assist-client-lib/res/values-de/strings.xml
+++ b/car-assist-client-lib/res/values-de/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"Aktion konnte nicht vom Assistant angefordert werden."</string>
+ <string name="says" msgid="8575666015622916107">"sagt"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-el/strings.xml b/car-assist-client-lib/res/values-el/strings.xml
index b45c040..9bdc6ee 100644
--- a/car-assist-client-lib/res/values-el/strings.xml
+++ b/car-assist-client-lib/res/values-el/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"Δεν ήταν δυνατό το αίτημα για ενέργεια στον Βοηθό!"</string>
+ <string name="says" msgid="8575666015622916107">"λέει"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-en-rAU/strings.xml b/car-assist-client-lib/res/values-en-rAU/strings.xml
index 19b57da..2f5a3b7 100644
--- a/car-assist-client-lib/res/values-en-rAU/strings.xml
+++ b/car-assist-client-lib/res/values-en-rAU/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"Could not request action from Assistant!"</string>
+ <string name="says" msgid="8575666015622916107">"says"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-en-rCA/strings.xml b/car-assist-client-lib/res/values-en-rCA/strings.xml
index 19b57da..2f5a3b7 100644
--- a/car-assist-client-lib/res/values-en-rCA/strings.xml
+++ b/car-assist-client-lib/res/values-en-rCA/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"Could not request action from Assistant!"</string>
+ <string name="says" msgid="8575666015622916107">"says"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-en-rGB/strings.xml b/car-assist-client-lib/res/values-en-rGB/strings.xml
index 19b57da..2f5a3b7 100644
--- a/car-assist-client-lib/res/values-en-rGB/strings.xml
+++ b/car-assist-client-lib/res/values-en-rGB/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"Could not request action from Assistant!"</string>
+ <string name="says" msgid="8575666015622916107">"says"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-en-rIN/strings.xml b/car-assist-client-lib/res/values-en-rIN/strings.xml
index 19b57da..2f5a3b7 100644
--- a/car-assist-client-lib/res/values-en-rIN/strings.xml
+++ b/car-assist-client-lib/res/values-en-rIN/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"Could not request action from Assistant!"</string>
+ <string name="says" msgid="8575666015622916107">"says"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-en-rXC/strings.xml b/car-assist-client-lib/res/values-en-rXC/strings.xml
index 883af6b..d6611c0 100644
--- a/car-assist-client-lib/res/values-en-rXC/strings.xml
+++ b/car-assist-client-lib/res/values-en-rXC/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"Could not request action from Assistant!"</string>
+ <string name="says" msgid="8575666015622916107">"says"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-es-rUS/strings.xml b/car-assist-client-lib/res/values-es-rUS/strings.xml
index a294f2d..307e7ec 100644
--- a/car-assist-client-lib/res/values-es-rUS/strings.xml
+++ b/car-assist-client-lib/res/values-es-rUS/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"No se pudo solicitar la acción del Asistente"</string>
+ <string name="says" msgid="8575666015622916107">"dice"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-es/strings.xml b/car-assist-client-lib/res/values-es/strings.xml
index 4e4cfee..e4e7e97 100644
--- a/car-assist-client-lib/res/values-es/strings.xml
+++ b/car-assist-client-lib/res/values-es/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"No se ha podido solicitar la acción al Asistente."</string>
+ <string name="says" msgid="8575666015622916107">"dice"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-et/strings.xml b/car-assist-client-lib/res/values-et/strings.xml
index 1aecd12..91363e6 100644
--- a/car-assist-client-lib/res/values-et/strings.xml
+++ b/car-assist-client-lib/res/values-et/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"Assistendilt ei õnnestunud toimingut taotleda."</string>
+ <string name="says" msgid="8575666015622916107">"ütleb"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-eu/strings.xml b/car-assist-client-lib/res/values-eu/strings.xml
index ea19d0b..0bc404a 100644
--- a/car-assist-client-lib/res/values-eu/strings.xml
+++ b/car-assist-client-lib/res/values-eu/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"Ezin izan da eskatu Laguntzailea eginbidearen ekintza!"</string>
+ <string name="says" msgid="8575666015622916107">"kontaktuak hau dio:"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-fa/strings.xml b/car-assist-client-lib/res/values-fa/strings.xml
index f2c736b..00c7f18 100644
--- a/car-assist-client-lib/res/values-fa/strings.xml
+++ b/car-assist-client-lib/res/values-fa/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"نمیتوانید از «دستیار» بخواهید کاری انجام دهد!"</string>
+ <string name="says" msgid="8575666015622916107">"میگوید"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-fi/strings.xml b/car-assist-client-lib/res/values-fi/strings.xml
index e3969ee..613428a 100644
--- a/car-assist-client-lib/res/values-fi/strings.xml
+++ b/car-assist-client-lib/res/values-fi/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"Toiminnon pyytäminen Assistantilta epäonnistui."</string>
+ <string name="says" msgid="8575666015622916107">"sanoo"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-fr-rCA/strings.xml b/car-assist-client-lib/res/values-fr-rCA/strings.xml
index f0cebd5..5791a4b 100644
--- a/car-assist-client-lib/res/values-fr-rCA/strings.xml
+++ b/car-assist-client-lib/res/values-fr-rCA/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"Impossible de demander à l\'Assistant Google d\'effectuer une action!"</string>
+ <string name="says" msgid="8575666015622916107">"dit"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-fr/strings.xml b/car-assist-client-lib/res/values-fr/strings.xml
index 79eb92b..7004545 100644
--- a/car-assist-client-lib/res/values-fr/strings.xml
+++ b/car-assist-client-lib/res/values-fr/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"Impossible de demander à l\'Assistant d\'effectuer cette action."</string>
+ <string name="says" msgid="8575666015622916107">"dit"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-gl/strings.xml b/car-assist-client-lib/res/values-gl/strings.xml
index 6c9c331..baec894 100644
--- a/car-assist-client-lib/res/values-gl/strings.xml
+++ b/car-assist-client-lib/res/values-gl/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"Non se puido solicitar a acción ao Asistente."</string>
+ <string name="says" msgid="8575666015622916107">"di"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-gu/strings.xml b/car-assist-client-lib/res/values-gu/strings.xml
index 1f94e89..63e313c 100644
--- a/car-assist-client-lib/res/values-gu/strings.xml
+++ b/car-assist-client-lib/res/values-gu/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"આસિસ્ટંટને ક્રિયાની વિનંતી કરી શક્યાં નથી!"</string>
+ <string name="says" msgid="8575666015622916107">"કહે છે કે"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-hi/strings.xml b/car-assist-client-lib/res/values-hi/strings.xml
index 55706c3..ba7afeb 100644
--- a/car-assist-client-lib/res/values-hi/strings.xml
+++ b/car-assist-client-lib/res/values-hi/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"Assistant से कार्रवाई का अनुरोध नहीं किया जा सका!"</string>
+ <string name="says" msgid="8575666015622916107">"कहा है कि"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-hr/strings.xml b/car-assist-client-lib/res/values-hr/strings.xml
index ec6dfea..2da146b 100644
--- a/car-assist-client-lib/res/values-hr/strings.xml
+++ b/car-assist-client-lib/res/values-hr/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"Nije bilo moguće zatražiti radnju od Asisitenta!"</string>
+ <string name="says" msgid="8575666015622916107">"kaže"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-hu/strings.xml b/car-assist-client-lib/res/values-hu/strings.xml
index a8c0d5b..faa43e0 100644
--- a/car-assist-client-lib/res/values-hu/strings.xml
+++ b/car-assist-client-lib/res/values-hu/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"Nem sikerült a Segéd-művelet kérése!"</string>
+ <string name="says" msgid="8575666015622916107">"azt mondja, hogy"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-hy/strings.xml b/car-assist-client-lib/res/values-hy/strings.xml
index 7c744d6..219b14b 100644
--- a/car-assist-client-lib/res/values-hy/strings.xml
+++ b/car-assist-client-lib/res/values-hy/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"Չհաջողվեց Օգնականին խնդրել գործողություն կատարել"</string>
+ <string name="says" msgid="8575666015622916107">"օգտատերն ասում է."</string>
</resources>
diff --git a/car-assist-client-lib/res/values-in/strings.xml b/car-assist-client-lib/res/values-in/strings.xml
index 9d3c512..cedc390 100644
--- a/car-assist-client-lib/res/values-in/strings.xml
+++ b/car-assist-client-lib/res/values-in/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"Tidak dapat meminta tindakan dari Asisten!"</string>
+ <string name="says" msgid="8575666015622916107">"mengatakan"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-is/strings.xml b/car-assist-client-lib/res/values-is/strings.xml
index 9aa55ff..1162c77 100644
--- a/car-assist-client-lib/res/values-is/strings.xml
+++ b/car-assist-client-lib/res/values-is/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"Ekki tókst að biðja hjálparann um aðgerð!"</string>
+ <string name="says" msgid="8575666015622916107">"segir"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-it/strings.xml b/car-assist-client-lib/res/values-it/strings.xml
index 0e3310b..4bac32b 100644
--- a/car-assist-client-lib/res/values-it/strings.xml
+++ b/car-assist-client-lib/res/values-it/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"Impossibile richiedere l\'azione all\'assistente"</string>
+ <string name="says" msgid="8575666015622916107">"dice"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-iw/strings.xml b/car-assist-client-lib/res/values-iw/strings.xml
index fd3c4de..510432d 100644
--- a/car-assist-client-lib/res/values-iw/strings.xml
+++ b/car-assist-client-lib/res/values-iw/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"לא ניתן לבקש מה-Assistant לבצע פעולה!"</string>
+ <string name="says" msgid="8575666015622916107">"רוצה להודיע כי"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-ja/strings.xml b/car-assist-client-lib/res/values-ja/strings.xml
index 8aa6ba9..2065208 100644
--- a/car-assist-client-lib/res/values-ja/strings.xml
+++ b/car-assist-client-lib/res/values-ja/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"アシスタント アクションをリクエストできませんでした"</string>
+ <string name="says" msgid="8575666015622916107">"さんからのメッセージです"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-ka/strings.xml b/car-assist-client-lib/res/values-ka/strings.xml
index a47c282..8076df9 100644
--- a/car-assist-client-lib/res/values-ka/strings.xml
+++ b/car-assist-client-lib/res/values-ka/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"ასისტენტისგან ქმედების მოთხოვნა ვერ მოხერხდა"</string>
+ <string name="says" msgid="8575666015622916107">"ამბობს"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-kk/strings.xml b/car-assist-client-lib/res/values-kk/strings.xml
index 5f4f986..b96f97f 100644
--- a/car-assist-client-lib/res/values-kk/strings.xml
+++ b/car-assist-client-lib/res/values-kk/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"Assistant әрекетін сұрау мүмкін болмады."</string>
+ <string name="says" msgid="8575666015622916107">"былай дейді:"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-km/strings.xml b/car-assist-client-lib/res/values-km/strings.xml
index 55b985d..64d1004 100644
--- a/car-assist-client-lib/res/values-km/strings.xml
+++ b/car-assist-client-lib/res/values-km/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"មិនអាចស្នើសុំសកម្មភាពពីជំនួយការបានទេ!"</string>
+ <string name="says" msgid="8575666015622916107">"និយាយថា"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-kn/strings.xml b/car-assist-client-lib/res/values-kn/strings.xml
index af1c9e7..187a13a 100644
--- a/car-assist-client-lib/res/values-kn/strings.xml
+++ b/car-assist-client-lib/res/values-kn/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"ಅಸಿಸ್ಟೆಂಟ್ನಿಂದ ಕ್ರಿಯೆಗಾಗಿ ವಿನಂತಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ!"</string>
+ <string name="says" msgid="8575666015622916107">"ಹೇಳುತ್ತಾರೆ"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-ko/strings.xml b/car-assist-client-lib/res/values-ko/strings.xml
index d1ee883..e0bc7e8 100644
--- a/car-assist-client-lib/res/values-ko/strings.xml
+++ b/car-assist-client-lib/res/values-ko/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"어시스턴트에서 요청 작업을 찾을 수 없습니다."</string>
+ <string name="says" msgid="8575666015622916107">"님의 메시지:"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-ky/strings.xml b/car-assist-client-lib/res/values-ky/strings.xml
index f718787..f278353 100644
--- a/car-assist-client-lib/res/values-ky/strings.xml
+++ b/car-assist-client-lib/res/values-ky/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"Жардамчы бул аракетти аткара албайт!"</string>
+ <string name="says" msgid="8575666015622916107">"төмөнкүнү айтты:"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-lo/strings.xml b/car-assist-client-lib/res/values-lo/strings.xml
index 9756d70..80c7d53 100644
--- a/car-assist-client-lib/res/values-lo/strings.xml
+++ b/car-assist-client-lib/res/values-lo/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"ບໍ່ສາມາດຂໍການດຳເນີນການຈາກຜູ້ຊ່ວຍໄດ້!"</string>
+ <string name="says" msgid="8575666015622916107">"ເວົ້າ"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-lt/strings.xml b/car-assist-client-lib/res/values-lt/strings.xml
index 88276c3..87374c1 100644
--- a/car-assist-client-lib/res/values-lt/strings.xml
+++ b/car-assist-client-lib/res/values-lt/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"Nepavyko pateikti Padėjėjui veiksmo užklausos!"</string>
+ <string name="says" msgid="8575666015622916107">"sako"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-lv/strings.xml b/car-assist-client-lib/res/values-lv/strings.xml
index 7da0545..3223c67 100644
--- a/car-assist-client-lib/res/values-lv/strings.xml
+++ b/car-assist-client-lib/res/values-lv/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"Nevarēja pieprasīt darbību no Asistenta."</string>
+ <string name="says" msgid="8575666015622916107">"saka"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-mk/strings.xml b/car-assist-client-lib/res/values-mk/strings.xml
index a6c1bd5..08f56ac 100644
--- a/car-assist-client-lib/res/values-mk/strings.xml
+++ b/car-assist-client-lib/res/values-mk/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"Не може да се побара дејство од „Помошникот“!"</string>
+ <string name="says" msgid="8575666015622916107">"вели"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-ml/strings.xml b/car-assist-client-lib/res/values-ml/strings.xml
index 4e2a1bc..71bc6ad 100644
--- a/car-assist-client-lib/res/values-ml/strings.xml
+++ b/car-assist-client-lib/res/values-ml/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"അസിസ്റ്റന്റിൽ നിന്ന് പ്രവർത്തനം അഭ്യർത്ഥിക്കാനായില്ല!"</string>
+ <string name="says" msgid="8575666015622916107">"പറയുന്നു"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-mn/strings.xml b/car-assist-client-lib/res/values-mn/strings.xml
index 7436099..3050b61 100644
--- a/car-assist-client-lib/res/values-mn/strings.xml
+++ b/car-assist-client-lib/res/values-mn/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"Туслахаас үйлдэл хийхийг хүсэж чадсангүй!"</string>
+ <string name="says" msgid="8575666015622916107">"хэлэхдээ"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-mr/strings.xml b/car-assist-client-lib/res/values-mr/strings.xml
index 0fb9df7..a896ce6 100644
--- a/car-assist-client-lib/res/values-mr/strings.xml
+++ b/car-assist-client-lib/res/values-mr/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"असिस्टंटकडे क्रियेची विनंती करता आली नाही!"</string>
+ <string name="says" msgid="8575666015622916107">"म्हणाले"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-ms/strings.xml b/car-assist-client-lib/res/values-ms/strings.xml
index 576d112..aa8192b 100644
--- a/car-assist-client-lib/res/values-ms/strings.xml
+++ b/car-assist-client-lib/res/values-ms/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"Tidak dapat meminta tindakan daripada Assistant!"</string>
+ <string name="says" msgid="8575666015622916107">"berkata"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-my/strings.xml b/car-assist-client-lib/res/values-my/strings.xml
index 9b83e1f..54ac60f 100644
--- a/car-assist-client-lib/res/values-my/strings.xml
+++ b/car-assist-client-lib/res/values-my/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"Assistant မှ လုပ်ဆောင်ချက်ကို တောင်းဆို၍မရပါ။"</string>
+ <string name="says" msgid="8575666015622916107">"ဆိုထားသည်မှာ"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-nb/strings.xml b/car-assist-client-lib/res/values-nb/strings.xml
index 579abee..279b16b 100644
--- a/car-assist-client-lib/res/values-nb/strings.xml
+++ b/car-assist-client-lib/res/values-nb/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"Kunne ikke forespørre handlinger fra assistenten!"</string>
+ <string name="says" msgid="8575666015622916107">"sier"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-ne/strings.xml b/car-assist-client-lib/res/values-ne/strings.xml
index 79c5aa9..d20a73a 100644
--- a/car-assist-client-lib/res/values-ne/strings.xml
+++ b/car-assist-client-lib/res/values-ne/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"सहायकलाई कारबाही गर्ने अनुरोध गर्न सकिएन!"</string>
+ <string name="says" msgid="8575666015622916107">"भन्नुहुन्छ"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-nl/strings.xml b/car-assist-client-lib/res/values-nl/strings.xml
index cd7f92d..aca2bb7 100644
--- a/car-assist-client-lib/res/values-nl/strings.xml
+++ b/car-assist-client-lib/res/values-nl/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"Kan actie niet aanvragen bij de Assistent."</string>
+ <string name="says" msgid="8575666015622916107">"zegt"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-or/strings.xml b/car-assist-client-lib/res/values-or/strings.xml
index 2dbef39..81480e1 100644
--- a/car-assist-client-lib/res/values-or/strings.xml
+++ b/car-assist-client-lib/res/values-or/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"ଆସିଷ୍ଟାଣ୍ଟ ଠାରୁ କାର୍ଯ୍ୟ ଅନୁରୋଧ କରାଯାଇପାରିଲା ନାହିଁ!"</string>
+ <string name="says" msgid="8575666015622916107">"କୁହେ"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-pa/strings.xml b/car-assist-client-lib/res/values-pa/strings.xml
index 3e51ca7..22fc049 100644
--- a/car-assist-client-lib/res/values-pa/strings.xml
+++ b/car-assist-client-lib/res/values-pa/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"\'ਅਸਿਸਟੈਂਟ\' ਤੋਂ ਕਾਰਵਾਈ ਦੀ ਬੇਨਤੀ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ!"</string>
+ <string name="says" msgid="8575666015622916107">"ਕਿਹਾ"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-pl/strings.xml b/car-assist-client-lib/res/values-pl/strings.xml
index 19f52fb..4ccfa00 100644
--- a/car-assist-client-lib/res/values-pl/strings.xml
+++ b/car-assist-client-lib/res/values-pl/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"Nie udało się wysłać prośby do Asystenta."</string>
+ <string name="says" msgid="8575666015622916107">"mówi"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-pt-rPT/strings.xml b/car-assist-client-lib/res/values-pt-rPT/strings.xml
index ead2bf2..bb902ea 100644
--- a/car-assist-client-lib/res/values-pt-rPT/strings.xml
+++ b/car-assist-client-lib/res/values-pt-rPT/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"Não foi possível solicitar a ação do Assistente."</string>
+ <string name="says" msgid="8575666015622916107">"diz"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-pt/strings.xml b/car-assist-client-lib/res/values-pt/strings.xml
index ead2bf2..bb902ea 100644
--- a/car-assist-client-lib/res/values-pt/strings.xml
+++ b/car-assist-client-lib/res/values-pt/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"Não foi possível solicitar a ação do Assistente."</string>
+ <string name="says" msgid="8575666015622916107">"diz"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-ro/strings.xml b/car-assist-client-lib/res/values-ro/strings.xml
index 9dc0b65..45cfcb6 100644
--- a/car-assist-client-lib/res/values-ro/strings.xml
+++ b/car-assist-client-lib/res/values-ro/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"Nu s-a putut solicita acțiunea de la Asistent!"</string>
+ <string name="says" msgid="8575666015622916107">"spune"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-ru/strings.xml b/car-assist-client-lib/res/values-ru/strings.xml
index e702681..7c668c1 100644
--- a/car-assist-client-lib/res/values-ru/strings.xml
+++ b/car-assist-client-lib/res/values-ru/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"Не удалось выполнить действие с помощью Ассистента"</string>
+ <string name="says" msgid="8575666015622916107">"говорит:"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-si/strings.xml b/car-assist-client-lib/res/values-si/strings.xml
index 40c17bf..0a233a0 100644
--- a/car-assist-client-lib/res/values-si/strings.xml
+++ b/car-assist-client-lib/res/values-si/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"සහායකගෙන් ක්රියාව ඉල්ලීමට නොහැකි විය!"</string>
+ <string name="says" msgid="8575666015622916107">"කියයි"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-sk/strings.xml b/car-assist-client-lib/res/values-sk/strings.xml
index 3bf4414..8043b1e 100644
--- a/car-assist-client-lib/res/values-sk/strings.xml
+++ b/car-assist-client-lib/res/values-sk/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"Vyžiadanie akcie od Asistenta zlyhalo."</string>
+ <string name="says" msgid="8575666015622916107">"hovorí"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-sl/strings.xml b/car-assist-client-lib/res/values-sl/strings.xml
index 178ed8b..ab58a0a 100644
--- a/car-assist-client-lib/res/values-sl/strings.xml
+++ b/car-assist-client-lib/res/values-sl/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"Ni bilo mogoče zahtevati dejanja Pomočnika."</string>
+ <string name="says" msgid="8575666015622916107">"pravi"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-sq/strings.xml b/car-assist-client-lib/res/values-sq/strings.xml
index 856bec2..acc0431 100644
--- a/car-assist-client-lib/res/values-sq/strings.xml
+++ b/car-assist-client-lib/res/values-sq/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"Nuk mund të kërkohet veprim nga \"Asistenti\"!"</string>
+ <string name="says" msgid="8575666015622916107">"thotë"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-sr/strings.xml b/car-assist-client-lib/res/values-sr/strings.xml
index b49c393..7d73ea8 100644
--- a/car-assist-client-lib/res/values-sr/strings.xml
+++ b/car-assist-client-lib/res/values-sr/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"Слање захтева за радњу Помоћника није успело!"</string>
+ <string name="says" msgid="8575666015622916107">"каже"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-sv/strings.xml b/car-assist-client-lib/res/values-sv/strings.xml
index ce2f05d..d22371e 100644
--- a/car-assist-client-lib/res/values-sv/strings.xml
+++ b/car-assist-client-lib/res/values-sv/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"Det gick inte att begära åtgärden från assistenten."</string>
+ <string name="says" msgid="8575666015622916107">"säger"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-sw/strings.xml b/car-assist-client-lib/res/values-sw/strings.xml
index ecc55cf..dcbddff 100644
--- a/car-assist-client-lib/res/values-sw/strings.xml
+++ b/car-assist-client-lib/res/values-sw/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"Imeshndwa kuomba kitendo kutoka kwenye programu ya Mratibu wa Google!"</string>
+ <string name="says" msgid="8575666015622916107">"anasema"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-ta/strings.xml b/car-assist-client-lib/res/values-ta/strings.xml
index b455c71..6128727 100644
--- a/car-assist-client-lib/res/values-ta/strings.xml
+++ b/car-assist-client-lib/res/values-ta/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"அசிஸ்டண்ட்டிடம் இருந்து உதவியைக் கோர இயலவில்லை!"</string>
+ <string name="says" msgid="8575666015622916107">"கூறுகிறார்"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-te/strings.xml b/car-assist-client-lib/res/values-te/strings.xml
index b77329f..222ddf4 100644
--- a/car-assist-client-lib/res/values-te/strings.xml
+++ b/car-assist-client-lib/res/values-te/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"అసిస్టెంట్ నుండి చర్యను అభ్యర్థించడం సాధ్యపడలేదు!"</string>
+ <string name="says" msgid="8575666015622916107">"ఇలా చెప్పారు"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-th/strings.xml b/car-assist-client-lib/res/values-th/strings.xml
index 64ef235..d88bdb1 100644
--- a/car-assist-client-lib/res/values-th/strings.xml
+++ b/car-assist-client-lib/res/values-th/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"การขอให้ Assistant ดำเนินการไม่สำเร็จ"</string>
+ <string name="says" msgid="8575666015622916107">"พูดว่า"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-tl/strings.xml b/car-assist-client-lib/res/values-tl/strings.xml
index 92f559d..2bcb098 100644
--- a/car-assist-client-lib/res/values-tl/strings.xml
+++ b/car-assist-client-lib/res/values-tl/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"Hindi makahiling ng pagkilos mula sa Assistant!"</string>
+ <string name="says" msgid="8575666015622916107">"ay nagsabing"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-tr/strings.xml b/car-assist-client-lib/res/values-tr/strings.xml
index fbea2f9..6ef140b 100644
--- a/car-assist-client-lib/res/values-tr/strings.xml
+++ b/car-assist-client-lib/res/values-tr/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"İşlem Asistan\'dan istenemedi!"</string>
+ <string name="says" msgid="8575666015622916107">"der ki:"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-uk/strings.xml b/car-assist-client-lib/res/values-uk/strings.xml
index 7d82717..8ba7886 100644
--- a/car-assist-client-lib/res/values-uk/strings.xml
+++ b/car-assist-client-lib/res/values-uk/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"Не вдалося надіслати запит на дію Асистента."</string>
+ <string name="says" msgid="8575666015622916107">"говорить"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-ur/strings.xml b/car-assist-client-lib/res/values-ur/strings.xml
index a622777..5e248a8 100644
--- a/car-assist-client-lib/res/values-ur/strings.xml
+++ b/car-assist-client-lib/res/values-ur/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"\'اسسٹنٹ\' کی طرف سے کارروائی کی درخواست نہیں کی جا سکی!"</string>
+ <string name="says" msgid="8575666015622916107">"کہ رہا ہے"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-uz/strings.xml b/car-assist-client-lib/res/values-uz/strings.xml
index 2aa2f1d..3b89e4e 100644
--- a/car-assist-client-lib/res/values-uz/strings.xml
+++ b/car-assist-client-lib/res/values-uz/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"Assistent orqali amal soʻrovi yuborilmadi!"</string>
+ <string name="says" msgid="8575666015622916107">"dedi:"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-vi/strings.xml b/car-assist-client-lib/res/values-vi/strings.xml
index 552f4c4..4832f26 100644
--- a/car-assist-client-lib/res/values-vi/strings.xml
+++ b/car-assist-client-lib/res/values-vi/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"Không thể yêu cầu hành động từ Trợ lý!"</string>
+ <string name="says" msgid="8575666015622916107">"nói"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-zh-rCN/strings.xml b/car-assist-client-lib/res/values-zh-rCN/strings.xml
index 6349a78..637124f 100644
--- a/car-assist-client-lib/res/values-zh-rCN/strings.xml
+++ b/car-assist-client-lib/res/values-zh-rCN/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"无法从 Google 助理请求操作!"</string>
+ <string name="says" msgid="8575666015622916107">"说"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-zh-rHK/strings.xml b/car-assist-client-lib/res/values-zh-rHK/strings.xml
index 0eeee1a..1c22eee 100644
--- a/car-assist-client-lib/res/values-zh-rHK/strings.xml
+++ b/car-assist-client-lib/res/values-zh-rHK/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"「Google 助理」無法執行要求的操作!"</string>
+ <string name="says" msgid="8575666015622916107">"話"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-zh-rTW/strings.xml b/car-assist-client-lib/res/values-zh-rTW/strings.xml
index 71fb62e..2b73ccf 100644
--- a/car-assist-client-lib/res/values-zh-rTW/strings.xml
+++ b/car-assist-client-lib/res/values-zh-rTW/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"無法要求 Google 助理執行動作!"</string>
+ <string name="says" msgid="8575666015622916107">"說"</string>
</resources>
diff --git a/car-assist-client-lib/res/values-zu/strings.xml b/car-assist-client-lib/res/values-zu/strings.xml
index 5011b7a..1fcd4cc 100644
--- a/car-assist-client-lib/res/values-zu/strings.xml
+++ b/car-assist-client-lib/res/values-zu/strings.xml
@@ -17,4 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="assist_action_failed_toast" msgid="3250146468076483714">"Ayikwazanga ukucela isenzo kusuka kumsizi!"</string>
+ <string name="says" msgid="8575666015622916107">"ithi"</string>
</resources>
diff --git a/car-assist-client-lib/src/com/android/car/assist/client/FallbackAssistant.java b/car-assist-client-lib/src/com/android/car/assist/client/FallbackAssistant.java
index ee2aabc..1392a2d 100644
--- a/car-assist-client-lib/src/com/android/car/assist/client/FallbackAssistant.java
+++ b/car-assist-client-lib/src/com/android/car/assist/client/FallbackAssistant.java
@@ -115,20 +115,24 @@
}
List<CharSequence> messages = new ArrayList<>();
-
List<Message> messageList = Message.getMessagesFromBundleArray(messagesBundle);
if (messageList == null || messageList.isEmpty()) {
Log.w(TAG, "No messages could be extracted from the bundle");
listener.onMessageRead(/* hasError= */ true);
return;
}
- // The sender should be the same for all the messages.
- Person sender = messageList.get(0).getSenderPerson();
- if (sender != null) {
- messages.add(sender.getName());
+
+ Person previousSender = messageList.get(0).getSenderPerson();
+ if (previousSender != null) {
+ messages.add(previousSender.getName());
messages.add(mVerbForSays);
}
for (Message message : messageList) {
+ if (message.getSenderPerson() != previousSender) {
+ messages.add(message.getSenderPerson().getName());
+ messages.add(mVerbForSays);
+ previousSender = message.getSenderPerson();
+ }
messages.add(message.getText());
}
diff --git a/car-broadcastradio-support/res/values-af/strings.xml b/car-broadcastradio-support/res/values-af/strings.xml
index 0f5498a..0c08586 100644
--- a/car-broadcastradio-support/res/values-af/strings.xml
+++ b/car-broadcastradio-support/res/values-af/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"Stasies"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"Gunstelinge"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-am/strings.xml b/car-broadcastradio-support/res/values-am/strings.xml
index 34612c1..81b128a 100644
--- a/car-broadcastradio-support/res/values-am/strings.xml
+++ b/car-broadcastradio-support/res/values-am/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"ኤኤም"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"ኤፍኤም"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"ጣቢያዎች"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"ተወዳጆች"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-ar/strings.xml b/car-broadcastradio-support/res/values-ar/strings.xml
index defdd18..129c8c5 100644
--- a/car-broadcastradio-support/res/values-ar/strings.xml
+++ b/car-broadcastradio-support/res/values-ar/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"المحطات"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"المفضّلة"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-as/strings.xml b/car-broadcastradio-support/res/values-as/strings.xml
index 93e669d..862e9bb 100644
--- a/car-broadcastradio-support/res/values-as/strings.xml
+++ b/car-broadcastradio-support/res/values-as/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"কেন্দ্ৰসমূহ"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"প্ৰিয় বস্তুসমূহ"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-az/strings.xml b/car-broadcastradio-support/res/values-az/strings.xml
index 5b3dc13..3b40ff9 100644
--- a/car-broadcastradio-support/res/values-az/strings.xml
+++ b/car-broadcastradio-support/res/values-az/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"Stansiyalar"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"Sevimlilər"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-b+sr+Latn/strings.xml b/car-broadcastradio-support/res/values-b+sr+Latn/strings.xml
index 2b24509..e29e90e 100644
--- a/car-broadcastradio-support/res/values-b+sr+Latn/strings.xml
+++ b/car-broadcastradio-support/res/values-b+sr+Latn/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"Stanice"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"Omiljeno"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-be/strings.xml b/car-broadcastradio-support/res/values-be/strings.xml
index 09b014c..cde54f4 100644
--- a/car-broadcastradio-support/res/values-be/strings.xml
+++ b/car-broadcastradio-support/res/values-be/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"Радыёстанцыі"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"Абранае"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-bg/strings.xml b/car-broadcastradio-support/res/values-bg/strings.xml
index 4dbd256..6d7b2a0 100644
--- a/car-broadcastradio-support/res/values-bg/strings.xml
+++ b/car-broadcastradio-support/res/values-bg/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"Цифрово радиоразпръскване"</string>
<string name="program_list_text" msgid="4414150317304422313">"Станции"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"Любими"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-bn/strings.xml b/car-broadcastradio-support/res/values-bn/strings.xml
index a08a537..245ce98 100644
--- a/car-broadcastradio-support/res/values-bn/strings.xml
+++ b/car-broadcastradio-support/res/values-bn/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"স্টেশন"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"পছন্দসই"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-bs/strings.xml b/car-broadcastradio-support/res/values-bs/strings.xml
index 811f5dd..42ff388 100644
--- a/car-broadcastradio-support/res/values-bs/strings.xml
+++ b/car-broadcastradio-support/res/values-bs/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"Stanice"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"Omiljeni"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-ca/strings.xml b/car-broadcastradio-support/res/values-ca/strings.xml
index 26002e5..3737632 100644
--- a/car-broadcastradio-support/res/values-ca/strings.xml
+++ b/car-broadcastradio-support/res/values-ca/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"Emissores"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"Preferides"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-cs/strings.xml b/car-broadcastradio-support/res/values-cs/strings.xml
index 46d1a91..db20752 100644
--- a/car-broadcastradio-support/res/values-cs/strings.xml
+++ b/car-broadcastradio-support/res/values-cs/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"Stanice"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"Oblíbené"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-da/strings.xml b/car-broadcastradio-support/res/values-da/strings.xml
index b0be180..46d1603 100644
--- a/car-broadcastradio-support/res/values-da/strings.xml
+++ b/car-broadcastradio-support/res/values-da/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"Kanaler"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"Favoritter"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-de/strings.xml b/car-broadcastradio-support/res/values-de/strings.xml
index b9d8476..c6e2e9f 100644
--- a/car-broadcastradio-support/res/values-de/strings.xml
+++ b/car-broadcastradio-support/res/values-de/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"MW"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"UKW"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"Sender"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"Favoriten"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-el/strings.xml b/car-broadcastradio-support/res/values-el/strings.xml
index 5dc5357..f5452ec 100644
--- a/car-broadcastradio-support/res/values-el/strings.xml
+++ b/car-broadcastradio-support/res/values-el/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"Σταθμοί"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"Αγαπημένα"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-en-rAU/strings.xml b/car-broadcastradio-support/res/values-en-rAU/strings.xml
index 07a0c33..806c9c8 100644
--- a/car-broadcastradio-support/res/values-en-rAU/strings.xml
+++ b/car-broadcastradio-support/res/values-en-rAU/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"a.m."</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"Stations"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"Favourites"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-en-rCA/strings.xml b/car-broadcastradio-support/res/values-en-rCA/strings.xml
index 07a0c33..806c9c8 100644
--- a/car-broadcastradio-support/res/values-en-rCA/strings.xml
+++ b/car-broadcastradio-support/res/values-en-rCA/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"a.m."</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"Stations"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"Favourites"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-en-rGB/strings.xml b/car-broadcastradio-support/res/values-en-rGB/strings.xml
index 07a0c33..806c9c8 100644
--- a/car-broadcastradio-support/res/values-en-rGB/strings.xml
+++ b/car-broadcastradio-support/res/values-en-rGB/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"a.m."</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"Stations"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"Favourites"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-en-rIN/strings.xml b/car-broadcastradio-support/res/values-en-rIN/strings.xml
index 07a0c33..806c9c8 100644
--- a/car-broadcastradio-support/res/values-en-rIN/strings.xml
+++ b/car-broadcastradio-support/res/values-en-rIN/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"a.m."</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"Stations"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"Favourites"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-en-rXC/strings.xml b/car-broadcastradio-support/res/values-en-rXC/strings.xml
index 6fd3786..b06db6c 100644
--- a/car-broadcastradio-support/res/values-en-rXC/strings.xml
+++ b/car-broadcastradio-support/res/values-en-rXC/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"Stations"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"Favorites"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-es-rUS/strings.xml b/car-broadcastradio-support/res/values-es-rUS/strings.xml
index 4f8ca47..4862ab2 100644
--- a/car-broadcastradio-support/res/values-es-rUS/strings.xml
+++ b/car-broadcastradio-support/res/values-es-rUS/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"Estaciones"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"Favoritos"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-es/strings.xml b/car-broadcastradio-support/res/values-es/strings.xml
index 941b83f..f0f383e 100644
--- a/car-broadcastradio-support/res/values-es/strings.xml
+++ b/car-broadcastradio-support/res/values-es/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"Emisoras"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"Favoritos"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-et/strings.xml b/car-broadcastradio-support/res/values-et/strings.xml
index 439f156..810c07e 100644
--- a/car-broadcastradio-support/res/values-et/strings.xml
+++ b/car-broadcastradio-support/res/values-et/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"Jaamad"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"Lemmikud"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-eu/strings.xml b/car-broadcastradio-support/res/values-eu/strings.xml
index ec96a52..999d986 100644
--- a/car-broadcastradio-support/res/values-eu/strings.xml
+++ b/car-broadcastradio-support/res/values-eu/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"Kateak"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"Gogokoak"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-fa/strings.xml b/car-broadcastradio-support/res/values-fa/strings.xml
index bc0df94..1828fc3 100644
--- a/car-broadcastradio-support/res/values-fa/strings.xml
+++ b/car-broadcastradio-support/res/values-fa/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"ایستگاهها"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"موارد دلخواه"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-fi/strings.xml b/car-broadcastradio-support/res/values-fi/strings.xml
index afafb89..a1b60db 100644
--- a/car-broadcastradio-support/res/values-fi/strings.xml
+++ b/car-broadcastradio-support/res/values-fi/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"Kanavat"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"Suosikit"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-fr-rCA/strings.xml b/car-broadcastradio-support/res/values-fr-rCA/strings.xml
index 575a008..89bd122 100644
--- a/car-broadcastradio-support/res/values-fr-rCA/strings.xml
+++ b/car-broadcastradio-support/res/values-fr-rCA/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"Stations"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"Favorites"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-fr/strings.xml b/car-broadcastradio-support/res/values-fr/strings.xml
index fcb91c4..f12123f 100644
--- a/car-broadcastradio-support/res/values-fr/strings.xml
+++ b/car-broadcastradio-support/res/values-fr/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"Radios"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"Favoris"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-gl/strings.xml b/car-broadcastradio-support/res/values-gl/strings.xml
index b6cd327..beccab0 100644
--- a/car-broadcastradio-support/res/values-gl/strings.xml
+++ b/car-broadcastradio-support/res/values-gl/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"Emisoras"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"Programas favoritos"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-gu/strings.xml b/car-broadcastradio-support/res/values-gu/strings.xml
index 9bde5f1..8da5f9d 100644
--- a/car-broadcastradio-support/res/values-gu/strings.xml
+++ b/car-broadcastradio-support/res/values-gu/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"સ્ટેશન"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"મનપસંદ"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-hi/strings.xml b/car-broadcastradio-support/res/values-hi/strings.xml
index e946790..230e18b 100644
--- a/car-broadcastradio-support/res/values-hi/strings.xml
+++ b/car-broadcastradio-support/res/values-hi/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"एएम रेडियो"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"एफ़एम रेडियो"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"डीएबी"</string>
<string name="program_list_text" msgid="4414150317304422313">"स्टेशन"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"पसंदीदा"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-hr/strings.xml b/car-broadcastradio-support/res/values-hr/strings.xml
index 498183e..63cc855 100644
--- a/car-broadcastradio-support/res/values-hr/strings.xml
+++ b/car-broadcastradio-support/res/values-hr/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"Postaje"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"Favoriti"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-hu/strings.xml b/car-broadcastradio-support/res/values-hu/strings.xml
index 89d8e19..5a16d62 100644
--- a/car-broadcastradio-support/res/values-hu/strings.xml
+++ b/car-broadcastradio-support/res/values-hu/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"Állomások"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"Kedvencek"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-hy/strings.xml b/car-broadcastradio-support/res/values-hy/strings.xml
index b4fef5d..77efc29 100644
--- a/car-broadcastradio-support/res/values-hy/strings.xml
+++ b/car-broadcastradio-support/res/values-hy/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"Ռադիոկայաններ"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"Ընտրանի"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-in/strings.xml b/car-broadcastradio-support/res/values-in/strings.xml
index 3974b7c..e40e53f 100644
--- a/car-broadcastradio-support/res/values-in/strings.xml
+++ b/car-broadcastradio-support/res/values-in/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"Stasiun"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"Favorit"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-is/strings.xml b/car-broadcastradio-support/res/values-is/strings.xml
index 8c0deab..1a2074a 100644
--- a/car-broadcastradio-support/res/values-is/strings.xml
+++ b/car-broadcastradio-support/res/values-is/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"Stöðvar"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"Eftirlæti"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-it/strings.xml b/car-broadcastradio-support/res/values-it/strings.xml
index 82e211b..eef0a6e 100644
--- a/car-broadcastradio-support/res/values-it/strings.xml
+++ b/car-broadcastradio-support/res/values-it/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"Stazioni"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"Preferiti"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-iw/strings.xml b/car-broadcastradio-support/res/values-iw/strings.xml
index fe609eb..e990b26 100644
--- a/car-broadcastradio-support/res/values-iw/strings.xml
+++ b/car-broadcastradio-support/res/values-iw/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB (Digital Audio Broadcasting)"</string>
<string name="program_list_text" msgid="4414150317304422313">"תחנות"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"מועדפים"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-ja/strings.xml b/car-broadcastradio-support/res/values-ja/strings.xml
index 9a76eb1..21582d0 100644
--- a/car-broadcastradio-support/res/values-ja/strings.xml
+++ b/car-broadcastradio-support/res/values-ja/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"ステーション"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"お気に入り"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-ka/strings.xml b/car-broadcastradio-support/res/values-ka/strings.xml
index 913b7dc..2f26b0a 100644
--- a/car-broadcastradio-support/res/values-ka/strings.xml
+++ b/car-broadcastradio-support/res/values-ka/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"ციფრული აუდიომაუწყებლობა"</string>
<string name="program_list_text" msgid="4414150317304422313">"სადგურები"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"რჩეულები"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-kk/strings.xml b/car-broadcastradio-support/res/values-kk/strings.xml
index bad0bdf..740afce 100644
--- a/car-broadcastradio-support/res/values-kk/strings.xml
+++ b/car-broadcastradio-support/res/values-kk/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"Станциялар"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"Таңдаулылар"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-km/strings.xml b/car-broadcastradio-support/res/values-km/strings.xml
index c2ff14c..be70353 100644
--- a/car-broadcastradio-support/res/values-km/strings.xml
+++ b/car-broadcastradio-support/res/values-km/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"ស្ថានីយ"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"សំណព្វ"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-kn/strings.xml b/car-broadcastradio-support/res/values-kn/strings.xml
index a5b05f8..9dadc54 100644
--- a/car-broadcastradio-support/res/values-kn/strings.xml
+++ b/car-broadcastradio-support/res/values-kn/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"ಬೆಳಿಗ್ಗೆ"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"ಸ್ಟೇಶನ್ಗಳು"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"ಮೆಚ್ಚಿನವುಗಳು"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-ko/strings.xml b/car-broadcastradio-support/res/values-ko/strings.xml
index 2e28882..abebfa4 100644
--- a/car-broadcastradio-support/res/values-ko/strings.xml
+++ b/car-broadcastradio-support/res/values-ko/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"채널"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"즐겨찾기"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-ky/strings.xml b/car-broadcastradio-support/res/values-ky/strings.xml
index f63231d..4640491 100644
--- a/car-broadcastradio-support/res/values-ky/strings.xml
+++ b/car-broadcastradio-support/res/values-ky/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"Станциялар"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"Сүйүктүүлөр"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-lo/strings.xml b/car-broadcastradio-support/res/values-lo/strings.xml
index b23529f..fbfe882 100644
--- a/car-broadcastradio-support/res/values-lo/strings.xml
+++ b/car-broadcastradio-support/res/values-lo/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"ສະຖານີ"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"ລາຍການທີ່ມັກ"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-lt/strings.xml b/car-broadcastradio-support/res/values-lt/strings.xml
index 781b513..6a68328 100644
--- a/car-broadcastradio-support/res/values-lt/strings.xml
+++ b/car-broadcastradio-support/res/values-lt/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"Stotys"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"Mėgstamiausi"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-lv/strings.xml b/car-broadcastradio-support/res/values-lv/strings.xml
index ec95f03..75db93a 100644
--- a/car-broadcastradio-support/res/values-lv/strings.xml
+++ b/car-broadcastradio-support/res/values-lv/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"Programmas"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"Izlase"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-mk/strings.xml b/car-broadcastradio-support/res/values-mk/strings.xml
index cdb6c72..c7410af 100644
--- a/car-broadcastradio-support/res/values-mk/strings.xml
+++ b/car-broadcastradio-support/res/values-mk/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"Станици"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"Омилени"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-ml/strings.xml b/car-broadcastradio-support/res/values-ml/strings.xml
index 7a87940..498bfd7 100644
--- a/car-broadcastradio-support/res/values-ml/strings.xml
+++ b/car-broadcastradio-support/res/values-ml/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"രാവിലെ"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"സ്റ്റേഷനുകള്"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"പ്രിയപ്പെട്ടവ"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-mn/strings.xml b/car-broadcastradio-support/res/values-mn/strings.xml
index f3c9501..3deca28 100644
--- a/car-broadcastradio-support/res/values-mn/strings.xml
+++ b/car-broadcastradio-support/res/values-mn/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"ӨГЛӨӨ"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"Станцууд"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"Дуртай"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-mr/strings.xml b/car-broadcastradio-support/res/values-mr/strings.xml
index ba960ac..0fc95e4 100644
--- a/car-broadcastradio-support/res/values-mr/strings.xml
+++ b/car-broadcastradio-support/res/values-mr/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"स्टेशन"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"आवडीचे"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-ms/strings.xml b/car-broadcastradio-support/res/values-ms/strings.xml
index 30cea70..257cb5e 100644
--- a/car-broadcastradio-support/res/values-ms/strings.xml
+++ b/car-broadcastradio-support/res/values-ms/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"Stesen"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"Kegemaran"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-my/strings.xml b/car-broadcastradio-support/res/values-my/strings.xml
index d0fa5db..692d19d 100644
--- a/car-broadcastradio-support/res/values-my/strings.xml
+++ b/car-broadcastradio-support/res/values-my/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"အသံလွှင့်ရုံများ"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"အသုံးအများဆုံးများ"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-nb/strings.xml b/car-broadcastradio-support/res/values-nb/strings.xml
index cfb84f6..79544cb 100644
--- a/car-broadcastradio-support/res/values-nb/strings.xml
+++ b/car-broadcastradio-support/res/values-nb/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"Stasjoner"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"Favoritter"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-ne/strings.xml b/car-broadcastradio-support/res/values-ne/strings.xml
index d0d05c6..ee1887b 100644
--- a/car-broadcastradio-support/res/values-ne/strings.xml
+++ b/car-broadcastradio-support/res/values-ne/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"पूर्वाह्न"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"एफएम"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"स्टेसनहरू"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"मन पर्ने कार्यक्रमहरू"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-nl/strings.xml b/car-broadcastradio-support/res/values-nl/strings.xml
index 8d63071..2f1a5e1 100644
--- a/car-broadcastradio-support/res/values-nl/strings.xml
+++ b/car-broadcastradio-support/res/values-nl/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"Zenders"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"Favorieten"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-or/strings.xml b/car-broadcastradio-support/res/values-or/strings.xml
index 7aa70d8..ab448c8 100644
--- a/car-broadcastradio-support/res/values-or/strings.xml
+++ b/car-broadcastradio-support/res/values-or/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"ଷ୍ଟେଶନ୍"</string>
- <string name="favorites_list_text" msgid="7829827713977109155">"ପସନ୍ଦଦାର୍"</string>
+ <string name="favorites_list_text" msgid="7829827713977109155">"ପସନ୍ଦର"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-pa/strings.xml b/car-broadcastradio-support/res/values-pa/strings.xml
index 9827f20..5f7ce46 100644
--- a/car-broadcastradio-support/res/values-pa/strings.xml
+++ b/car-broadcastradio-support/res/values-pa/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"ਸਟੇਸ਼ਨ"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"ਮਨਪਸੰਦ"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-pl/strings.xml b/car-broadcastradio-support/res/values-pl/strings.xml
index 5467bbb..1fc4d67 100644
--- a/car-broadcastradio-support/res/values-pl/strings.xml
+++ b/car-broadcastradio-support/res/values-pl/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"Stacje"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"Ulubione"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-pt-rPT/strings.xml b/car-broadcastradio-support/res/values-pt-rPT/strings.xml
index 9363e36..a4b120a 100644
--- a/car-broadcastradio-support/res/values-pt-rPT/strings.xml
+++ b/car-broadcastradio-support/res/values-pt-rPT/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"Estações"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"Favoritas"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-pt/strings.xml b/car-broadcastradio-support/res/values-pt/strings.xml
index 3cfc194..9d72f03 100644
--- a/car-broadcastradio-support/res/values-pt/strings.xml
+++ b/car-broadcastradio-support/res/values-pt/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"Estações"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"Favoritos"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-ro/strings.xml b/car-broadcastradio-support/res/values-ro/strings.xml
index 4b84fba..7ab0b50 100644
--- a/car-broadcastradio-support/res/values-ro/strings.xml
+++ b/car-broadcastradio-support/res/values-ro/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"Posturi"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"Preferate"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-ru/strings.xml b/car-broadcastradio-support/res/values-ru/strings.xml
index 8181729..2fed0f4 100644
--- a/car-broadcastradio-support/res/values-ru/strings.xml
+++ b/car-broadcastradio-support/res/values-ru/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"Цифровое радио"</string>
<string name="program_list_text" msgid="4414150317304422313">"Радиостанции"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"Избранное"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-si/strings.xml b/car-broadcastradio-support/res/values-si/strings.xml
index 3256934..53f72c6 100644
--- a/car-broadcastradio-support/res/values-si/strings.xml
+++ b/car-broadcastradio-support/res/values-si/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"නාලිකා"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"ප්රියතම"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-sk/strings.xml b/car-broadcastradio-support/res/values-sk/strings.xml
index 33da914..fcdab92 100644
--- a/car-broadcastradio-support/res/values-sk/strings.xml
+++ b/car-broadcastradio-support/res/values-sk/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"Stanice"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"Obľúbené"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-sl/strings.xml b/car-broadcastradio-support/res/values-sl/strings.xml
index b1437e1..f0d3770 100644
--- a/car-broadcastradio-support/res/values-sl/strings.xml
+++ b/car-broadcastradio-support/res/values-sl/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"Postaje"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"Priljubljene"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-sq/strings.xml b/car-broadcastradio-support/res/values-sq/strings.xml
index 6b251b7..a4c1c95 100644
--- a/car-broadcastradio-support/res/values-sq/strings.xml
+++ b/car-broadcastradio-support/res/values-sq/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"Stacionet"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"Të preferuarat"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-sr/strings.xml b/car-broadcastradio-support/res/values-sr/strings.xml
index 86adbc5..8321b8c 100644
--- a/car-broadcastradio-support/res/values-sr/strings.xml
+++ b/car-broadcastradio-support/res/values-sr/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"Станице"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"Омиљено"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-sv/strings.xml b/car-broadcastradio-support/res/values-sv/strings.xml
index 0f73e77..5475b03 100644
--- a/car-broadcastradio-support/res/values-sv/strings.xml
+++ b/car-broadcastradio-support/res/values-sv/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"Kanaler"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"Favoriter"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-sw/strings.xml b/car-broadcastradio-support/res/values-sw/strings.xml
index c44c8c7..879df73 100644
--- a/car-broadcastradio-support/res/values-sw/strings.xml
+++ b/car-broadcastradio-support/res/values-sw/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"Stesheni"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"Unavyopenda"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-ta/strings.xml b/car-broadcastradio-support/res/values-ta/strings.xml
index c98ae9f..6b91b37 100644
--- a/car-broadcastradio-support/res/values-ta/strings.xml
+++ b/car-broadcastradio-support/res/values-ta/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"நிலையங்கள்"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"பிடித்தவை"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-te/strings.xml b/car-broadcastradio-support/res/values-te/strings.xml
index 29d59e7..864e222 100644
--- a/car-broadcastradio-support/res/values-te/strings.xml
+++ b/car-broadcastradio-support/res/values-te/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"స్టేషన్లు"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"ఇష్టమైనవి"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-th/strings.xml b/car-broadcastradio-support/res/values-th/strings.xml
index fa486a6..0370e76 100644
--- a/car-broadcastradio-support/res/values-th/strings.xml
+++ b/car-broadcastradio-support/res/values-th/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"สถานี"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"รายการโปรด"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-tl/strings.xml b/car-broadcastradio-support/res/values-tl/strings.xml
index 7ca02db..932e133 100644
--- a/car-broadcastradio-support/res/values-tl/strings.xml
+++ b/car-broadcastradio-support/res/values-tl/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"Mga Istasyon"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"Mga Paborito"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-tr/strings.xml b/car-broadcastradio-support/res/values-tr/strings.xml
index 8dee49d..136387f 100644
--- a/car-broadcastradio-support/res/values-tr/strings.xml
+++ b/car-broadcastradio-support/res/values-tr/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"İstasyonlar"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"Favoriler"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-uk/strings.xml b/car-broadcastradio-support/res/values-uk/strings.xml
index 047f1e6..cdd259a 100644
--- a/car-broadcastradio-support/res/values-uk/strings.xml
+++ b/car-broadcastradio-support/res/values-uk/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"Станції"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"Вибране"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-ur/strings.xml b/car-broadcastradio-support/res/values-ur/strings.xml
index 55a4e0b..a511d89 100644
--- a/car-broadcastradio-support/res/values-ur/strings.xml
+++ b/car-broadcastradio-support/res/values-ur/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"اسٹیشنز"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"پسندیدہ"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-uz/strings.xml b/car-broadcastradio-support/res/values-uz/strings.xml
index 476d5b4..5ff7a60 100644
--- a/car-broadcastradio-support/res/values-uz/strings.xml
+++ b/car-broadcastradio-support/res/values-uz/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"Raqamli radio"</string>
<string name="program_list_text" msgid="4414150317304422313">"Radiostansiyalar"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"Saralanganlar"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-vi/strings.xml b/car-broadcastradio-support/res/values-vi/strings.xml
index 3126047..067c179 100644
--- a/car-broadcastradio-support/res/values-vi/strings.xml
+++ b/car-broadcastradio-support/res/values-vi/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"Phát thanh kỹ thuật số"</string>
<string name="program_list_text" msgid="4414150317304422313">"Đài"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"Đài yêu thích"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-zh-rCN/strings.xml b/car-broadcastradio-support/res/values-zh-rCN/strings.xml
index 14ac643..1789a58 100644
--- a/car-broadcastradio-support/res/values-zh-rCN/strings.xml
+++ b/car-broadcastradio-support/res/values-zh-rCN/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"电台"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"收藏"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-zh-rHK/strings.xml b/car-broadcastradio-support/res/values-zh-rHK/strings.xml
index ae16220..bb596c2 100644
--- a/car-broadcastradio-support/res/values-zh-rHK/strings.xml
+++ b/car-broadcastradio-support/res/values-zh-rHK/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"數碼聲音廣播"</string>
<string name="program_list_text" msgid="4414150317304422313">"電台"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"收藏"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-zh-rTW/strings.xml b/car-broadcastradio-support/res/values-zh-rTW/strings.xml
index ae16220..0ba44bc 100644
--- a/car-broadcastradio-support/res/values-zh-rTW/strings.xml
+++ b/car-broadcastradio-support/res/values-zh-rTW/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"電台"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"收藏"</string>
</resources>
diff --git a/car-broadcastradio-support/res/values-zu/strings.xml b/car-broadcastradio-support/res/values-zu/strings.xml
index e36e1b0..dd5578b 100644
--- a/car-broadcastradio-support/res/values-zu/strings.xml
+++ b/car-broadcastradio-support/res/values-zu/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="radio_am_text" msgid="571324921988967868">"AM"</string>
<string name="radio_fm_text" msgid="1973045042281933494">"FM"</string>
- <!-- no translation found for radio_dab_text (8456449462266648979) -->
- <skip />
+ <string name="radio_dab_text" msgid="8456449462266648979">"I-DAB"</string>
<string name="program_list_text" msgid="4414150317304422313">"Iziteshi"</string>
<string name="favorites_list_text" msgid="7829827713977109155">"Izintandokazi"</string>
</resources>
diff --git a/car-media-common/res/values-af/strings.xml b/car-media-common/res/values-af/strings.xml
index f75b467..c4efced 100644
--- a/car-media-common/res/values-af/strings.xml
+++ b/car-media-common/res/values-af/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"Albumkunswerk"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"Titelloos"</string>
</resources>
diff --git a/car-media-common/res/values-am/strings.xml b/car-media-common/res/values-am/strings.xml
index 607ab45..9888274 100644
--- a/car-media-common/res/values-am/strings.xml
+++ b/car-media-common/res/values-am/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"የአልበም ስነ ጥበብ"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"ርዕስ የለም"</string>
</resources>
diff --git a/car-media-common/res/values-ar/strings.xml b/car-media-common/res/values-ar/strings.xml
index d7a9a2c..609709e 100644
--- a/car-media-common/res/values-ar/strings.xml
+++ b/car-media-common/res/values-ar/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"صورة الألبوم"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"بلا عنوان"</string>
</resources>
diff --git a/car-media-common/res/values-as/strings.xml b/car-media-common/res/values-as/strings.xml
index 3bdbf06..1513a5e 100644
--- a/car-media-common/res/values-as/strings.xml
+++ b/car-media-common/res/values-as/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"এলবাম আৰ্ট"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"কোনো শিৰোনাম নাই"</string>
</resources>
diff --git a/car-media-common/res/values-az/strings.xml b/car-media-common/res/values-az/strings.xml
index 936d945..9e8a836 100644
--- a/car-media-common/res/values-az/strings.xml
+++ b/car-media-common/res/values-az/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"Albom təsviri"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"Başlıq yoxdur"</string>
</resources>
diff --git a/car-media-common/res/values-b+sr+Latn/strings.xml b/car-media-common/res/values-b+sr+Latn/strings.xml
index 95bcfcc..60ea824 100644
--- a/car-media-common/res/values-b+sr+Latn/strings.xml
+++ b/car-media-common/res/values-b+sr+Latn/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"Omot albuma"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"Bez naslova"</string>
</resources>
diff --git a/car-media-common/res/values-be/strings.xml b/car-media-common/res/values-be/strings.xml
index a1ddf1d..4a98eab 100644
--- a/car-media-common/res/values-be/strings.xml
+++ b/car-media-common/res/values-be/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"Вокладка альбома"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"Без назвы"</string>
</resources>
diff --git a/car-media-common/res/values-bg/strings.xml b/car-media-common/res/values-bg/strings.xml
index 3895155..f595ed8 100644
--- a/car-media-common/res/values-bg/strings.xml
+++ b/car-media-common/res/values-bg/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"Обложка на албума"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"Няма заглавие"</string>
</resources>
diff --git a/car-media-common/res/values-bn/strings.xml b/car-media-common/res/values-bn/strings.xml
index 3fbbaa0..c7366d7 100644
--- a/car-media-common/res/values-bn/strings.xml
+++ b/car-media-common/res/values-bn/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"অ্যালবাম আর্ট"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"কোনও শীর্ষক নেই"</string>
</resources>
diff --git a/car-media-common/res/values-bs/strings.xml b/car-media-common/res/values-bs/strings.xml
index 95bcfcc..60ea824 100644
--- a/car-media-common/res/values-bs/strings.xml
+++ b/car-media-common/res/values-bs/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"Omot albuma"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"Bez naslova"</string>
</resources>
diff --git a/car-media-common/res/values-ca/strings.xml b/car-media-common/res/values-ca/strings.xml
index 6f5c30c..c672d9b 100644
--- a/car-media-common/res/values-ca/strings.xml
+++ b/car-media-common/res/values-ca/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"Imatge de l\'àlbum"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"Sense títol"</string>
</resources>
diff --git a/car-media-common/res/values-cs/strings.xml b/car-media-common/res/values-cs/strings.xml
index 9609baf..dfcffe0 100644
--- a/car-media-common/res/values-cs/strings.xml
+++ b/car-media-common/res/values-cs/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"Obal alba"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"Bez názvu"</string>
</resources>
diff --git a/car-media-common/res/values-da/strings.xml b/car-media-common/res/values-da/strings.xml
index e62c850..1640516 100644
--- a/car-media-common/res/values-da/strings.xml
+++ b/car-media-common/res/values-da/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"Albumgrafik"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"Ingen titel"</string>
</resources>
diff --git a/car-media-common/res/values-de/strings.xml b/car-media-common/res/values-de/strings.xml
index abec36e..7bafae6 100644
--- a/car-media-common/res/values-de/strings.xml
+++ b/car-media-common/res/values-de/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"Albumcover"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"Kein Titel"</string>
</resources>
diff --git a/car-media-common/res/values-el/strings.xml b/car-media-common/res/values-el/strings.xml
index 99c9846..0b5de6d 100644
--- a/car-media-common/res/values-el/strings.xml
+++ b/car-media-common/res/values-el/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"Εξώφυλλο άλμπουμ"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"Χωρίς τίτλο"</string>
</resources>
diff --git a/car-media-common/res/values-en-rAU/strings.xml b/car-media-common/res/values-en-rAU/strings.xml
index c2f2ef5..98e3148 100644
--- a/car-media-common/res/values-en-rAU/strings.xml
+++ b/car-media-common/res/values-en-rAU/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"Album Art"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"No title"</string>
</resources>
diff --git a/car-media-common/res/values-en-rCA/strings.xml b/car-media-common/res/values-en-rCA/strings.xml
index c2f2ef5..98e3148 100644
--- a/car-media-common/res/values-en-rCA/strings.xml
+++ b/car-media-common/res/values-en-rCA/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"Album Art"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"No title"</string>
</resources>
diff --git a/car-media-common/res/values-en-rGB/strings.xml b/car-media-common/res/values-en-rGB/strings.xml
index c2f2ef5..98e3148 100644
--- a/car-media-common/res/values-en-rGB/strings.xml
+++ b/car-media-common/res/values-en-rGB/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"Album Art"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"No title"</string>
</resources>
diff --git a/car-media-common/res/values-en-rIN/strings.xml b/car-media-common/res/values-en-rIN/strings.xml
index c2f2ef5..98e3148 100644
--- a/car-media-common/res/values-en-rIN/strings.xml
+++ b/car-media-common/res/values-en-rIN/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"Album Art"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"No title"</string>
</resources>
diff --git a/car-media-common/res/values-en-rXC/strings.xml b/car-media-common/res/values-en-rXC/strings.xml
index 8101b96..ecdf930 100644
--- a/car-media-common/res/values-en-rXC/strings.xml
+++ b/car-media-common/res/values-en-rXC/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"Album Art"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"No Title"</string>
</resources>
diff --git a/car-media-common/res/values-es-rUS/strings.xml b/car-media-common/res/values-es-rUS/strings.xml
index 7faa6a0..18ba657 100644
--- a/car-media-common/res/values-es-rUS/strings.xml
+++ b/car-media-common/res/values-es-rUS/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"Imagen del álbum"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"Sin título"</string>
</resources>
diff --git a/car-media-common/res/values-es/strings.xml b/car-media-common/res/values-es/strings.xml
index 7faa6a0..18ba657 100644
--- a/car-media-common/res/values-es/strings.xml
+++ b/car-media-common/res/values-es/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"Imagen del álbum"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"Sin título"</string>
</resources>
diff --git a/car-media-common/res/values-et/strings.xml b/car-media-common/res/values-et/strings.xml
index e30d919..8ca4cf2 100644
--- a/car-media-common/res/values-et/strings.xml
+++ b/car-media-common/res/values-et/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"Albumi kujundus"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"Pealkiri puudub"</string>
</resources>
diff --git a/car-media-common/res/values-eu/strings.xml b/car-media-common/res/values-eu/strings.xml
index 6d836b1..896aa2c 100644
--- a/car-media-common/res/values-eu/strings.xml
+++ b/car-media-common/res/values-eu/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"Albumaren azala"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"Izenik gabea"</string>
</resources>
diff --git a/car-media-common/res/values-fa/strings.xml b/car-media-common/res/values-fa/strings.xml
index 5daf357..24bac8e 100644
--- a/car-media-common/res/values-fa/strings.xml
+++ b/car-media-common/res/values-fa/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"عکس روی جلد آلبوم"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"بدون عنوان"</string>
</resources>
diff --git a/car-media-common/res/values-fi/strings.xml b/car-media-common/res/values-fi/strings.xml
index 545bb78..0fcaaf5 100644
--- a/car-media-common/res/values-fi/strings.xml
+++ b/car-media-common/res/values-fi/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"Albumin kansitaide"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"Ei nimeä"</string>
</resources>
diff --git a/car-media-common/res/values-fr-rCA/strings.xml b/car-media-common/res/values-fr-rCA/strings.xml
index ac3abaf..66e06e1 100644
--- a/car-media-common/res/values-fr-rCA/strings.xml
+++ b/car-media-common/res/values-fr-rCA/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"Image de l\'album"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"Aucun titre"</string>
</resources>
diff --git a/car-media-common/res/values-fr/strings.xml b/car-media-common/res/values-fr/strings.xml
index ac3abaf..dfbc082 100644
--- a/car-media-common/res/values-fr/strings.xml
+++ b/car-media-common/res/values-fr/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"Image de l\'album"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"Sans titre"</string>
</resources>
diff --git a/car-media-common/res/values-gl/strings.xml b/car-media-common/res/values-gl/strings.xml
index 4e3b599..6971016 100644
--- a/car-media-common/res/values-gl/strings.xml
+++ b/car-media-common/res/values-gl/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"Portada de álbum"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"Sen título"</string>
</resources>
diff --git a/car-media-common/res/values-gu/strings.xml b/car-media-common/res/values-gu/strings.xml
index 48ccea5..569394f 100644
--- a/car-media-common/res/values-gu/strings.xml
+++ b/car-media-common/res/values-gu/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"આલ્બમ આર્ટ"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"કોઈ શીર્ષક નથી"</string>
</resources>
diff --git a/car-media-common/res/values-hi/strings.xml b/car-media-common/res/values-hi/strings.xml
index b4b9a92..f13088f 100644
--- a/car-media-common/res/values-hi/strings.xml
+++ b/car-media-common/res/values-hi/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"एल्बम आर्ट"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"कोई शीर्षक नहीं"</string>
</resources>
diff --git a/car-media-common/res/values-hr/strings.xml b/car-media-common/res/values-hr/strings.xml
index 95065f6..00e19d1 100644
--- a/car-media-common/res/values-hr/strings.xml
+++ b/car-media-common/res/values-hr/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"Slika naslovnice albuma"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"Bez naslova"</string>
</resources>
diff --git a/car-media-common/res/values-hu/strings.xml b/car-media-common/res/values-hu/strings.xml
index e346fe0..8631465 100644
--- a/car-media-common/res/values-hu/strings.xml
+++ b/car-media-common/res/values-hu/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"Lemezborító"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"Nincs cím"</string>
</resources>
diff --git a/car-media-common/res/values-hy/strings.xml b/car-media-common/res/values-hy/strings.xml
index c60039e..197a067 100644
--- a/car-media-common/res/values-hy/strings.xml
+++ b/car-media-common/res/values-hy/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"Ալբոմի շապիկ"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"Անանուն"</string>
</resources>
diff --git a/car-media-common/res/values-in/strings.xml b/car-media-common/res/values-in/strings.xml
index a7193d0..e331c0a 100644
--- a/car-media-common/res/values-in/strings.xml
+++ b/car-media-common/res/values-in/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"Sampul Album"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"Tanpa Judul"</string>
</resources>
diff --git a/car-media-common/res/values-is/strings.xml b/car-media-common/res/values-is/strings.xml
index ea45f41..b26c4c6 100644
--- a/car-media-common/res/values-is/strings.xml
+++ b/car-media-common/res/values-is/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"Plötuumslag"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"Enginn titill"</string>
</resources>
diff --git a/car-media-common/res/values-it/strings.xml b/car-media-common/res/values-it/strings.xml
index b965c9e..bab7f0a 100644
--- a/car-media-common/res/values-it/strings.xml
+++ b/car-media-common/res/values-it/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"Copertina dell\'album"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"Nessun titolo"</string>
</resources>
diff --git a/car-media-common/res/values-iw/strings.xml b/car-media-common/res/values-iw/strings.xml
index be7d68f..9e12f85 100644
--- a/car-media-common/res/values-iw/strings.xml
+++ b/car-media-common/res/values-iw/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"עטיפת אלבום"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"ללא שם"</string>
</resources>
diff --git a/car-media-common/res/values-ja/strings.xml b/car-media-common/res/values-ja/strings.xml
index 44ddb6d..8d46866 100644
--- a/car-media-common/res/values-ja/strings.xml
+++ b/car-media-common/res/values-ja/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"アルバムアート"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"タイトルなし"</string>
</resources>
diff --git a/car-media-common/res/values-ka/strings.xml b/car-media-common/res/values-ka/strings.xml
index 3497af3..1e467fe 100644
--- a/car-media-common/res/values-ka/strings.xml
+++ b/car-media-common/res/values-ka/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"ალბომის გარეკანი"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"უსათაურო"</string>
</resources>
diff --git a/car-media-common/res/values-kk/strings.xml b/car-media-common/res/values-kk/strings.xml
index 1062bd6..ec84f1a 100644
--- a/car-media-common/res/values-kk/strings.xml
+++ b/car-media-common/res/values-kk/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"Альбом мұқабасы"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"Атауы жоқ"</string>
</resources>
diff --git a/car-media-common/res/values-km/strings.xml b/car-media-common/res/values-km/strings.xml
index 2fd01f2..a9320b1 100644
--- a/car-media-common/res/values-km/strings.xml
+++ b/car-media-common/res/values-km/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"ក្របអាល់ប៊ុម"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"គ្មានចំណងជើងទេ"</string>
</resources>
diff --git a/car-media-common/res/values-kn/strings.xml b/car-media-common/res/values-kn/strings.xml
index 0ae31d6..4a02cfd 100644
--- a/car-media-common/res/values-kn/strings.xml
+++ b/car-media-common/res/values-kn/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"ಆಲ್ಬಮ್ ಕಲೆ"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"ಯಾವುದೇ ಶೀರ್ಷಿಕೆಯಿಲ್ಲ"</string>
</resources>
diff --git a/car-media-common/res/values-ko/strings.xml b/car-media-common/res/values-ko/strings.xml
index 4e699e8..568f6de 100644
--- a/car-media-common/res/values-ko/strings.xml
+++ b/car-media-common/res/values-ko/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"앨범아트"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"제목 없음"</string>
</resources>
diff --git a/car-media-common/res/values-ky/strings.xml b/car-media-common/res/values-ky/strings.xml
index 0ff7653..5dd1ccc 100644
--- a/car-media-common/res/values-ky/strings.xml
+++ b/car-media-common/res/values-ky/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"Альбом мукабасы"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"Аталышы жок"</string>
</resources>
diff --git a/car-media-common/res/values-lo/strings.xml b/car-media-common/res/values-lo/strings.xml
index 98d9158..aee4892 100644
--- a/car-media-common/res/values-lo/strings.xml
+++ b/car-media-common/res/values-lo/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"ໜ້າປົກອະລະບ້ຳ"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"ບໍ່ມີຊື່"</string>
</resources>
diff --git a/car-media-common/res/values-lt/strings.xml b/car-media-common/res/values-lt/strings.xml
index f79fe2e..b4f1926 100644
--- a/car-media-common/res/values-lt/strings.xml
+++ b/car-media-common/res/values-lt/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"Albumo viršelis"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"Nėra pavadinimo"</string>
</resources>
diff --git a/car-media-common/res/values-lv/strings.xml b/car-media-common/res/values-lv/strings.xml
index 7250c12..d4b6044 100644
--- a/car-media-common/res/values-lv/strings.xml
+++ b/car-media-common/res/values-lv/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"Albuma noformējums"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"Bez nosaukuma"</string>
</resources>
diff --git a/car-media-common/res/values-mk/strings.xml b/car-media-common/res/values-mk/strings.xml
index d3bd5ec..d46c551 100644
--- a/car-media-common/res/values-mk/strings.xml
+++ b/car-media-common/res/values-mk/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"Корица на албум"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"Без наслов"</string>
</resources>
diff --git a/car-media-common/res/values-ml/strings.xml b/car-media-common/res/values-ml/strings.xml
index 69c6099..cd1743b 100644
--- a/car-media-common/res/values-ml/strings.xml
+++ b/car-media-common/res/values-ml/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"ആൽബം ആർട്ട്"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"പേരില്ല"</string>
</resources>
diff --git a/car-media-common/res/values-mn/strings.xml b/car-media-common/res/values-mn/strings.xml
index 9cb3ef0..0cbec6a 100644
--- a/car-media-common/res/values-mn/strings.xml
+++ b/car-media-common/res/values-mn/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"Цомгийн зураг"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"Гарчиг алга"</string>
</resources>
diff --git a/car-media-common/res/values-mr/strings.xml b/car-media-common/res/values-mr/strings.xml
index 6eb3270..450fddd 100644
--- a/car-media-common/res/values-mr/strings.xml
+++ b/car-media-common/res/values-mr/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"अल्बम कला"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"शीर्षक नाही"</string>
</resources>
diff --git a/car-media-common/res/values-ms/strings.xml b/car-media-common/res/values-ms/strings.xml
index 9fb0d07..f5660bf 100644
--- a/car-media-common/res/values-ms/strings.xml
+++ b/car-media-common/res/values-ms/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"Seni Album"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"Tiada Tajuk"</string>
</resources>
diff --git a/car-media-common/res/values-my/strings.xml b/car-media-common/res/values-my/strings.xml
index 88e294e..e717f45 100644
--- a/car-media-common/res/values-my/strings.xml
+++ b/car-media-common/res/values-my/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"အယ်လ်ဘမ်ပုံ"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"ခေါင်းစဉ် မရှိပါ"</string>
</resources>
diff --git a/car-media-common/res/values-nb/strings.xml b/car-media-common/res/values-nb/strings.xml
index f3f6b18..b01654e 100644
--- a/car-media-common/res/values-nb/strings.xml
+++ b/car-media-common/res/values-nb/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"Albumgrafikk"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"Ingen tittel"</string>
</resources>
diff --git a/car-media-common/res/values-ne/strings.xml b/car-media-common/res/values-ne/strings.xml
index 3e70c34..8e2bf79 100644
--- a/car-media-common/res/values-ne/strings.xml
+++ b/car-media-common/res/values-ne/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"एल्बम आर्ट"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"शीर्षक छैन"</string>
</resources>
diff --git a/car-media-common/res/values-nl/strings.xml b/car-media-common/res/values-nl/strings.xml
index d22668f..8259676 100644
--- a/car-media-common/res/values-nl/strings.xml
+++ b/car-media-common/res/values-nl/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"Albumhoes"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"Geen titel"</string>
</resources>
diff --git a/car-media-common/res/values-or/strings.xml b/car-media-common/res/values-or/strings.xml
index 8be562e..a714293 100644
--- a/car-media-common/res/values-or/strings.xml
+++ b/car-media-common/res/values-or/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"ଆଲବମ୍ ଆର୍ଟ"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"କୌଣସି ଟାଇଟେଲ୍ ନାହିଁ"</string>
</resources>
diff --git a/car-media-common/res/values-pa/strings.xml b/car-media-common/res/values-pa/strings.xml
index d35b304..e3a607b 100644
--- a/car-media-common/res/values-pa/strings.xml
+++ b/car-media-common/res/values-pa/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"ਐਲਬਮ ਕਲਾ"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"ਕੋਈ ਸਿਰਲੇਖ ਨਹੀਂ"</string>
</resources>
diff --git a/car-media-common/res/values-pl/strings.xml b/car-media-common/res/values-pl/strings.xml
index b38f926..fd00ae5 100644
--- a/car-media-common/res/values-pl/strings.xml
+++ b/car-media-common/res/values-pl/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"Okładka albumu"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"Bez tytułu"</string>
</resources>
diff --git a/car-media-common/res/values-pt-rPT/strings.xml b/car-media-common/res/values-pt-rPT/strings.xml
index 1ed6bf3..2ae65bf 100644
--- a/car-media-common/res/values-pt-rPT/strings.xml
+++ b/car-media-common/res/values-pt-rPT/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"Imagem do álbum"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"Sem título"</string>
</resources>
diff --git a/car-media-common/res/values-pt/strings.xml b/car-media-common/res/values-pt/strings.xml
index d0ff223..1b39a7b 100644
--- a/car-media-common/res/values-pt/strings.xml
+++ b/car-media-common/res/values-pt/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"Arte do álbum"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"Sem título"</string>
</resources>
diff --git a/car-media-common/res/values-ro/strings.xml b/car-media-common/res/values-ro/strings.xml
index b667514..38c53cc 100644
--- a/car-media-common/res/values-ro/strings.xml
+++ b/car-media-common/res/values-ro/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"Grafica albumului"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"Fără titlu"</string>
</resources>
diff --git a/car-media-common/res/values-ru/strings.xml b/car-media-common/res/values-ru/strings.xml
index 30d8ce1..990650f 100644
--- a/car-media-common/res/values-ru/strings.xml
+++ b/car-media-common/res/values-ru/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"Обложка альбома"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"Без названия"</string>
</resources>
diff --git a/car-media-common/res/values-si/strings.xml b/car-media-common/res/values-si/strings.xml
index 4ecd5c7..7da552b 100644
--- a/car-media-common/res/values-si/strings.xml
+++ b/car-media-common/res/values-si/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"ඇල්බම කලාව"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"මාතෘකාවක් නැත"</string>
</resources>
diff --git a/car-media-common/res/values-sk/strings.xml b/car-media-common/res/values-sk/strings.xml
index 7c84b8c..d94bac4 100644
--- a/car-media-common/res/values-sk/strings.xml
+++ b/car-media-common/res/values-sk/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"Obrázok albumu"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"Bez názvu"</string>
</resources>
diff --git a/car-media-common/res/values-sl/strings.xml b/car-media-common/res/values-sl/strings.xml
index e5a2fdd..683507c 100644
--- a/car-media-common/res/values-sl/strings.xml
+++ b/car-media-common/res/values-sl/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"Slika albuma"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"Brez naslova"</string>
</resources>
diff --git a/car-media-common/res/values-sq/strings.xml b/car-media-common/res/values-sq/strings.xml
index c27e915..354b5ed 100644
--- a/car-media-common/res/values-sq/strings.xml
+++ b/car-media-common/res/values-sq/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"Kopertina e albumit"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"Pa titull"</string>
</resources>
diff --git a/car-media-common/res/values-sr/strings.xml b/car-media-common/res/values-sr/strings.xml
index b638368..e6173ba 100644
--- a/car-media-common/res/values-sr/strings.xml
+++ b/car-media-common/res/values-sr/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"Омот албума"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"Без наслова"</string>
</resources>
diff --git a/car-media-common/res/values-sv/strings.xml b/car-media-common/res/values-sv/strings.xml
index 111c939..ce52ecf 100644
--- a/car-media-common/res/values-sv/strings.xml
+++ b/car-media-common/res/values-sv/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"Skivomslag"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"Ingen titel"</string>
</resources>
diff --git a/car-media-common/res/values-sw/strings.xml b/car-media-common/res/values-sw/strings.xml
index 6a8da9d..282555c 100644
--- a/car-media-common/res/values-sw/strings.xml
+++ b/car-media-common/res/values-sw/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"Sanaa ya Albamu"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"Hakuna Jina"</string>
</resources>
diff --git a/car-media-common/res/values-ta/strings.xml b/car-media-common/res/values-ta/strings.xml
index ded4c56..dd522b8 100644
--- a/car-media-common/res/values-ta/strings.xml
+++ b/car-media-common/res/values-ta/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"ஆல்பம் ஆர்ட்"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"தலைப்பு இல்லை"</string>
</resources>
diff --git a/car-media-common/res/values-te/strings.xml b/car-media-common/res/values-te/strings.xml
index eb11da8..62a7464 100644
--- a/car-media-common/res/values-te/strings.xml
+++ b/car-media-common/res/values-te/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"ఆల్బమ్ ఆర్ట్"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"శీర్షిక లేదు"</string>
</resources>
diff --git a/car-media-common/res/values-th/strings.xml b/car-media-common/res/values-th/strings.xml
index 34d0ca2..f642719 100644
--- a/car-media-common/res/values-th/strings.xml
+++ b/car-media-common/res/values-th/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"ปกอัลบั้ม"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"ไม่มีชื่อ"</string>
</resources>
diff --git a/car-media-common/res/values-tl/strings.xml b/car-media-common/res/values-tl/strings.xml
index c2f2ef5..a2da896 100644
--- a/car-media-common/res/values-tl/strings.xml
+++ b/car-media-common/res/values-tl/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"Album Art"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"Walang Pamagat"</string>
</resources>
diff --git a/car-media-common/res/values-tr/strings.xml b/car-media-common/res/values-tr/strings.xml
index 98b90d6..6f717ac 100644
--- a/car-media-common/res/values-tr/strings.xml
+++ b/car-media-common/res/values-tr/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"Albüm Kapağı"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"Başlıksız"</string>
</resources>
diff --git a/car-media-common/res/values-uk/strings.xml b/car-media-common/res/values-uk/strings.xml
index 84e09e1..0661490 100644
--- a/car-media-common/res/values-uk/strings.xml
+++ b/car-media-common/res/values-uk/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"Обкладинка альбому"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"Без назви"</string>
</resources>
diff --git a/car-media-common/res/values-ur/strings.xml b/car-media-common/res/values-ur/strings.xml
index e746f3a..ccf505c 100644
--- a/car-media-common/res/values-ur/strings.xml
+++ b/car-media-common/res/values-ur/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"البم آرٹ"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"کوئی عنوان نہیں ہے"</string>
</resources>
diff --git a/car-media-common/res/values-uz/strings.xml b/car-media-common/res/values-uz/strings.xml
index 5c97fc1..f3e8826 100644
--- a/car-media-common/res/values-uz/strings.xml
+++ b/car-media-common/res/values-uz/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"Albom muqovasi"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"Nomsiz"</string>
</resources>
diff --git a/car-media-common/res/values-vi/strings.xml b/car-media-common/res/values-vi/strings.xml
index ba84106..2a99840 100644
--- a/car-media-common/res/values-vi/strings.xml
+++ b/car-media-common/res/values-vi/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"Ảnh bìa album"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"Không có tiêu đề"</string>
</resources>
diff --git a/car-media-common/res/values-zh-rCN/strings.xml b/car-media-common/res/values-zh-rCN/strings.xml
index 3370ca3..b3ddef1 100644
--- a/car-media-common/res/values-zh-rCN/strings.xml
+++ b/car-media-common/res/values-zh-rCN/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"专辑封面"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"无标题"</string>
</resources>
diff --git a/car-media-common/res/values-zh-rHK/strings.xml b/car-media-common/res/values-zh-rHK/strings.xml
index 9376f80..6ce371a 100644
--- a/car-media-common/res/values-zh-rHK/strings.xml
+++ b/car-media-common/res/values-zh-rHK/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"專輯封面"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"無標題"</string>
</resources>
diff --git a/car-media-common/res/values-zh-rTW/strings.xml b/car-media-common/res/values-zh-rTW/strings.xml
index 9376f80..6ce371a 100644
--- a/car-media-common/res/values-zh-rTW/strings.xml
+++ b/car-media-common/res/values-zh-rTW/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"專輯封面"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"無標題"</string>
</resources>
diff --git a/car-media-common/res/values-zu/strings.xml b/car-media-common/res/values-zu/strings.xml
index f2c1a2e..cde3b48 100644
--- a/car-media-common/res/values-zu/strings.xml
+++ b/car-media-common/res/values-zu/strings.xml
@@ -18,4 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="album_art" msgid="3392647029019061691">"Ubuciko be-albhamu"</string>
+ <string name="metadata_default_title" msgid="5902775732281325081">"Asikho isihloko"</string>
</resources>
diff --git a/car-media-common/src/com/android/car/media/common/browse/MediaBrowserViewModel.java b/car-media-common/src/com/android/car/media/common/browse/MediaBrowserViewModel.java
index 5a4626a..a4636c2 100644
--- a/car-media-common/src/com/android/car/media/common/browse/MediaBrowserViewModel.java
+++ b/car-media-common/src/com/android/car/media/common/browse/MediaBrowserViewModel.java
@@ -37,31 +37,11 @@
public interface MediaBrowserViewModel {
/**
- * Possible states of the application UI
- */
- enum BrowseState {
- /** There is no content to show */
- EMPTY,
- /** We are still in the process of obtaining data */
- LOADING,
- /** Data has been loaded */
- LOADED,
- /** The content can't be shown due an error */
- ERROR
- }
-
- /**
* Returns a LiveData that emits the current package name of the browser's service component.
*/
LiveData<String> getPackageName();
/**
- * Returns a LiveData that emits the current {@link BrowseState}
- */
- LiveData<BrowseState> getBrowseState();
-
-
- /**
* Fetches the MediaItemMetadatas for the current browsed id, and the loading status of the
* fetch operation.
*
diff --git a/car-media-common/src/com/android/car/media/common/browse/MediaBrowserViewModelImpl.java b/car-media-common/src/com/android/car/media/common/browse/MediaBrowserViewModelImpl.java
index 7d47ba7..974639d 100644
--- a/car-media-common/src/com/android/car/media/common/browse/MediaBrowserViewModelImpl.java
+++ b/car-media-common/src/com/android/car/media/common/browse/MediaBrowserViewModelImpl.java
@@ -33,7 +33,6 @@
import androidx.annotation.RestrictTo;
import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.LiveData;
-import androidx.lifecycle.MediatorLiveData;
import androidx.lifecycle.MutableLiveData;
import com.android.car.arch.common.FutureData;
@@ -62,9 +61,6 @@
private final LiveData<FutureData<List<MediaItemMetadata>>> mSearchedMediaItems;
private final LiveData<FutureData<List<MediaItemMetadata>>> mBrowsedMediaItems;
-
- private final LiveData<BrowseState> mBrowseState;
-
private final LiveData<String> mPackageName;
MediaBrowserViewModelImpl(@NonNull Application application, boolean isRoot) {
@@ -94,39 +90,6 @@
(mediaBrowser == null || TextUtils.isEmpty(query))
? null
: new SearchedMediaItems(mediaBrowser, query)));
-
- mBrowseState = new MediatorLiveData<BrowseState>() {
- {
- setValue(BrowseState.EMPTY);
- addSource(mBrowsedMediaItems, items -> update());
- }
-
- private void update() {
- setValue(getState());
- }
-
- private BrowseState getState() {
- if (mBrowsedMediaItems.getValue() == null) {
- // Uninitialized
- return BrowseState.EMPTY;
- }
- if (mBrowsedMediaItems.getValue().isLoading()) {
- return BrowseState.LOADING;
- }
- List<MediaItemMetadata> items = mBrowsedMediaItems.getValue().getData();
- if (items == null) {
- // Normally this could be null if it hasn't been initialized, but in that case
- // isLoading would not be false, so this means it must have encountered an
- // error.
- return BrowseState.ERROR;
- }
- if (items.isEmpty()) {
- return BrowseState.EMPTY;
- }
- return BrowseState.LOADED;
- }
- };
-
}
private static MediaBrowserCompat requireConnected(@Nullable MediaBrowserCompat mediaBrowser) {
@@ -155,11 +118,6 @@
}
@Override
- public LiveData<BrowseState> getBrowseState() {
- return mBrowseState;
- }
-
- @Override
public LiveData<FutureData<List<MediaItemMetadata>>> getBrowsedMediaItems() {
return mBrowsedMediaItems;
}
diff --git a/car-settings-lib/Android.bp b/car-messenger-common/Android.bp
similarity index 71%
rename from car-settings-lib/Android.bp
rename to car-messenger-common/Android.bp
index 9c4dbd5..fc93d28 100644
--- a/car-settings-lib/Android.bp
+++ b/car-messenger-common/Android.bp
@@ -1,3 +1,4 @@
+//
// Copyright (C) 2019 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -11,22 +12,28 @@
// 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.
+//
android_library {
- name: "car-settings-lib",
+ name: "car-messenger-common",
srcs: ["src/**/*.java"],
- resource_dirs: ["res"],
-
- static_libs: [
- "androidx.annotation_annotation",
- "androidx.loader_loader",
- ],
-
optimize: {
enabled: false,
},
- min_sdk_version: "24",
+ libs: ["android.car"],
+
+ resource_dirs: ["res"],
+
+ static_libs: [
+ "android.car.userlib",
+ "androidx.legacy_legacy-support-v4",
+ "car-apps-common",
+ "car-messenger-protos",
+ "CompanionDeviceSupport-aidl",
+ "connected-device-lib",
+ "connected-device-protos",
+ ],
}
diff --git a/car-messenger-common/AndroidManifest.xml b/car-messenger-common/AndroidManifest.xml
new file mode 100644
index 0000000..26a8598
--- /dev/null
+++ b/car-messenger-common/AndroidManifest.xml
@@ -0,0 +1,20 @@
+<?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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.car.messenger.common">
+</manifest>
diff --git a/car-settings-lib/Android.bp b/car-messenger-common/proto/Android.bp
similarity index 68%
copy from car-settings-lib/Android.bp
copy to car-messenger-common/proto/Android.bp
index 9c4dbd5..c08e72b 100644
--- a/car-settings-lib/Android.bp
+++ b/car-messenger-common/proto/Android.bp
@@ -1,3 +1,4 @@
+//
// Copyright (C) 2019 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -11,22 +12,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.
+//
-android_library {
- name: "car-settings-lib",
-
- srcs: ["src/**/*.java"],
-
- resource_dirs: ["res"],
-
- static_libs: [
- "androidx.annotation_annotation",
- "androidx.loader_loader",
- ],
-
- optimize: {
- enabled: false,
+java_library_static {
+ name: "car-messenger-protos",
+ host_supported: true,
+ proto: {
+ type: "lite",
},
-
- min_sdk_version: "24",
+ srcs: ["*.proto"],
+ jarjar_rules: "jarjar-rules.txt",
+ sdk_version: "28",
}
diff --git a/car-messenger-common/proto/jarjar-rules.txt b/car-messenger-common/proto/jarjar-rules.txt
new file mode 100644
index 0000000..d27aecb
--- /dev/null
+++ b/car-messenger-common/proto/jarjar-rules.txt
@@ -0,0 +1 @@
+rule com.google.protobuf.** com.android.car.protobuf.@1
diff --git a/car-messenger-common/proto/notification_msg.proto b/car-messenger-common/proto/notification_msg.proto
new file mode 100644
index 0000000..6329d04
--- /dev/null
+++ b/car-messenger-common/proto/notification_msg.proto
@@ -0,0 +1,151 @@
+/*
+ * 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.
+ */
+
+syntax = "proto3";
+
+package com.android.car.messenger.proto;
+
+option java_package = "com.android.car.messenger.NotificationMsgProto";
+
+message PhoneToCarMessage {
+ // The unique key of the message notification, same in phone and car.
+ // This will be the StatusBarNotification id of the original message notification posted on the
+ // phone.
+ string notification_key = 1;
+
+ // Categorizing what type of message this is, so the receiver understands what type of
+ // message_data is being sent, and the purpose of the message. The expected message_type(s) with
+ // their message_data type (for now) are:
+ // "NEW_CONVERSATION" - ConversationNotification expected,
+ // "NEW_MESSAGE" - MessagingStyleMessageProto expected,
+ // "ACTION_STATUS_UPDATE" - ActionStatusUpdate expected,
+ // "OTHER" - metadata expected.
+ //
+ // The message_type field is a string and not an enum so that new message types can be added in a
+ // backwards compatible way. New message types that require a message_data structure that was
+ // introduced in later releases will be put in the metadata field.
+ //
+ // NOTE: while a message type like "NEW_CONVERSATION" is required to have a
+ // ConversationNotification message, it may also have a metadata message as well.
+ string message_type = 2;
+
+ oneof message_data {
+ ConversationNotification conversation = 3;
+ MessagingStyleMessage message = 4;
+ ActionStatusUpdate status_update = 5;
+ }
+
+ // A byte array containing an undefined message. This field may contain supplemental information
+ // for a message_data, or contain all of the data for the PhoneToCarMessage.
+ bytes metadata = 6;
+}
+
+message CarToPhoneMessage {
+ // The unique key of the message notification, same in phone and car.
+ // This will be the StatusBarNotification id of the original message notification posted on the
+ // phone.
+ string notification_key = 1;
+
+ Action action_request = 2;
+
+ bytes metadata = 3;
+}
+
+message ActionStatusUpdate {
+ enum Status {
+ SUCCESSFUL = 0;
+ ERROR = 1;
+ }
+
+ // Unique ID of the action
+ int64 request_id = 1;
+
+ Status status = 2;
+
+ string error_explanation = 3;
+}
+
+// A message notification originating from the user's phone.
+message ConversationNotification {
+
+ // Display name of the application that posted this notification.
+ string messaging_app_display_name = 1;
+
+ // Package name of the application that posted this notification.
+ string messaging_app_package_name = 2;
+
+ MessagingStyle messaging_style = 3;
+
+ // The time, in milliseconds, this message notification was last updated.
+ int64 time_ms = 4;
+
+ bytes app_icon = 5;
+}
+
+message MessagingStyle {
+ repeated MessagingStyleMessage messaging_style_msg = 1;
+
+ string convo_title = 2;
+
+ // String of the user, needed for MessagingStyle
+ string user_display_name = 3;
+
+ bool is_group_convo = 4;
+}
+
+message MessagingStyleMessage {
+ string text_message = 1;
+
+ int64 timestamp = 2;
+
+ Person sender = 3;
+
+ // If the message is read on the phone.
+ bool is_read = 4;
+}
+
+message Person {
+ string name = 1;
+
+ bytes icon = 2;
+}
+
+message Action {
+ enum ActionName {
+ MARK_AS_READ = 0;
+ REPLY = 1;
+ DISMISS = 2;
+ }
+
+ // Same as the PhoneToCar and CarToPhone messages's notification_key.
+ // As mentioned above, this notification id should be the same on the phone and the car.
+ // This will be the StatusBarNotification id of the original message notification posted on the
+ // phone.
+ string notification_key = 1;
+
+ //Optional, used to capture data like the reply string.
+ repeated ActionDataFieldEntry action_data_field = 2;
+
+ ActionName action_name = 3;
+
+ // Unique id of this action.
+ int64 request_id = 4;
+}
+
+message ActionDataFieldEntry {
+ string key = 1;
+ string value = 2;
+}
diff --git a/car-messenger-common/res/drawable/ic_message.xml b/car-messenger-common/res/drawable/ic_message.xml
new file mode 100644
index 0000000..fd6026f
--- /dev/null
+++ b/car-messenger-common/res/drawable/ic_message.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt"
+ android:viewportWidth="48"
+ android:viewportHeight="48"
+ android:width="48dp"
+ android:height="48dp">
+ <path
+ android:pathData="M40 4H8C5.79 4 4.02 5.79 4.02 8L4 44l8 -8h28c2.21 0 4 -1.79 4 -4V8c0 -2.21 -1.79 -4 -4 -4zM12 18h24v4H12v-4zm16 10H12v-4h16v4zm8 -12H12v-4h24v4z"
+ android:fillColor="#FFFFFF" />
+</vector>
diff --git a/car-messenger-common/res/values-af/strings.xml b/car-messenger-common/res/values-af/strings.xml
new file mode 100644
index 0000000..7ffff1f
--- /dev/null
+++ b/car-messenger-common/res/values-af/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="other">%d nuwe boodskappe</item>
+ <item quantity="one">Nuwe boodskap</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"Speel"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"Merk as gelees"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"Herhaal"</string>
+ <string name="action_reply" msgid="564106590567600685">"Antwoord"</string>
+ <string name="action_stop" msgid="6950369080845695405">"Stop"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"Maak toe"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"Kan nie antwoord stuur nie Probeer weer."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"Kan nie antwoord stuur nie Toestel is nie gekoppel nie."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s sê"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"Kan nie boodskap hardop lees nie."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"\"%s\""</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"Antwoord is gestuur na %s"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"Naam is nie beskikbaar nie"</string>
+</resources>
diff --git a/car-messenger-common/res/values-am/strings.xml b/car-messenger-common/res/values-am/strings.xml
new file mode 100644
index 0000000..8d11d19
--- /dev/null
+++ b/car-messenger-common/res/values-am/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="one">%d አዲስ መልዕክቶች</item>
+ <item quantity="other">%d አዲስ መልዕክቶች</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"አጫውት"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"እንደተነበበ ምልክት አድርግ"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"ድገም"</string>
+ <string name="action_reply" msgid="564106590567600685">"ምላሽ ስጥ"</string>
+ <string name="action_stop" msgid="6950369080845695405">"አስቁም"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"ዝጋ"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"ምላሽ መላክ አልተቻለም። እባክዎ እንደገና ይሞክሩ።"</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"ምላሽ መላክ አልተቻለም። መሣሪያ አልተገናኘም።"</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s እንዲህ ይላሉ፦"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"መልዕክቱን ማንበብ አልተቻለም።"</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"«%s»"</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"ምላሽ ለ%s ተልኳል"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"ስም አይገኝም"</string>
+</resources>
diff --git a/car-messenger-common/res/values-ar/strings.xml b/car-messenger-common/res/values-ar/strings.xml
new file mode 100644
index 0000000..c2b2eb2
--- /dev/null
+++ b/car-messenger-common/res/values-ar/strings.xml
@@ -0,0 +1,41 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="zero">%d رسالة جديدة.</item>
+ <item quantity="two">رسالتان جديدتان (%d)</item>
+ <item quantity="few">%d رسائل جديدة</item>
+ <item quantity="many">%d رسالة جديدة</item>
+ <item quantity="other">%d رسالة جديدة</item>
+ <item quantity="one">رسالة واحدة جديدة</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"تشغيل"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"وضع علامة \"مقروءة\""</string>
+ <string name="action_repeat" msgid="8184323082093728957">"تكرار"</string>
+ <string name="action_reply" msgid="564106590567600685">"رد"</string>
+ <string name="action_stop" msgid="6950369080845695405">"إيقاف"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"إغلاق"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"تعذّر إرسال رد. يُرجى إعادة المحاولة."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"تعذّر إرسال رد. الجهاز غير متصل."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"رسالة %s نصها"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"لا يمكن قراءة الرسالة بصوت عالٍ."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"\"%s\""</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"تم إرسال رد إلى %s."</string>
+ <string name="name_not_available" msgid="3800013092212550915">"الاسم غير متاح."</string>
+</resources>
diff --git a/car-messenger-common/res/values-as/strings.xml b/car-messenger-common/res/values-as/strings.xml
new file mode 100644
index 0000000..bbf92d1
--- /dev/null
+++ b/car-messenger-common/res/values-as/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="one">%dটা নতুন বাৰ্তা</item>
+ <item quantity="other">%dটা নতুন বাৰ্তা</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"প্লে’ কৰক"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"পঢ়া হৈছে বুলি চিহ্নিত কৰক"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"পুনৰাই কৰক"</string>
+ <string name="action_reply" msgid="564106590567600685">"প্ৰত্যুত্তৰ দিয়ক"</string>
+ <string name="action_stop" msgid="6950369080845695405">"বন্ধ কৰক"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"বন্ধ কৰক"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"প্ৰত্যুত্তৰ পঠিয়াব নোৱাৰি। অনুগ্ৰহ কৰি পুনৰ চেষ্টা কৰক।"</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"প্ৰত্যুত্তৰ পঠিয়াব নোৱাৰি। ডিভাইচটো সংযুক্ত হৈ নাই।"</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%sএ কৈছে"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"বাৰ্তাটো পঢ়িব নোৱাৰি।"</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"\"%s\""</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"%sলৈ প্রত্যুত্তৰ পঠিওৱা হ’ল"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"নাম উপলব্ধ নহয়"</string>
+</resources>
diff --git a/car-messenger-common/res/values-az/strings.xml b/car-messenger-common/res/values-az/strings.xml
new file mode 100644
index 0000000..b93f53c
--- /dev/null
+++ b/car-messenger-common/res/values-az/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="other">%d yeni mesaj</item>
+ <item quantity="one">Yeni mesaj</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"Oxudun"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"Oxunmuş kimi qeyd edin"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"Təkrarlayın"</string>
+ <string name="action_reply" msgid="564106590567600685">"Cavablayın"</string>
+ <string name="action_stop" msgid="6950369080845695405">"Dayandırın"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"Bağlayın"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"Cavab göndərmək alınmadı. Yenidən cəhd edin."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"Cavab göndərmək alınmadı. Cihaz qoşulmayıb."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s söyləyir:"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"Mesajı oxumaq mümkün deyil."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"\"%s\""</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"Cavab bu ünvana göndərildi: %s"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"Ad əlçatan deyil"</string>
+</resources>
diff --git a/car-messenger-common/res/values-b+sr+Latn/strings.xml b/car-messenger-common/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..8421afb
--- /dev/null
+++ b/car-messenger-common/res/values-b+sr+Latn/strings.xml
@@ -0,0 +1,38 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="one">%d nova poruka</item>
+ <item quantity="few">%d nove poruke</item>
+ <item quantity="other">%d novih poruka</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"Pusti"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"Označi kao pročitano"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"Ponovi"</string>
+ <string name="action_reply" msgid="564106590567600685">"Odgovori"</string>
+ <string name="action_stop" msgid="6950369080845695405">"Zaustavi"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"Zatvori"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"Slanje odgovora nije uspelo. Probajte ponovo."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"Slanje odgovora nije uspelo. Uređaj nije povezan."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s kaže"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"Čitanje poruke naglas nije uspelo."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"„%s“"</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"Odgovor je poslat kontaktu %s"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"Ime nije dostupno"</string>
+</resources>
diff --git a/car-messenger-common/res/values-be/strings.xml b/car-messenger-common/res/values-be/strings.xml
new file mode 100644
index 0000000..fa6e154
--- /dev/null
+++ b/car-messenger-common/res/values-be/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="one">%d новае паведамленне</item>
+ <item quantity="few">%d новыя паведамленні</item>
+ <item quantity="many">%d новых паведамленняў</item>
+ <item quantity="other">%d новага паведамлення</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"Прайграць"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"Пазначыць як прачытанае"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"Паўтараць"</string>
+ <string name="action_reply" msgid="564106590567600685">"Адказаць"</string>
+ <string name="action_stop" msgid="6950369080845695405">"Спыніць"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"Закрыць"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"Не ўдалося адправіць адказ. Паўтарыце спробу."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"Не ўдалося адправіць адказ. Прылада не падключана."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s кажа"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"Не ўдалося зачытаць паведамленне."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"\"%s\""</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"Адказ адпраўлены кантакту %s"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"Імя недаступнае"</string>
+</resources>
diff --git a/car-messenger-common/res/values-bg/strings.xml b/car-messenger-common/res/values-bg/strings.xml
new file mode 100644
index 0000000..911ea86
--- /dev/null
+++ b/car-messenger-common/res/values-bg/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="other">%d нови съобщения</item>
+ <item quantity="one">Ново съобщение</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"Възпроизвеждане"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"Означаване като прочетено"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"Повтаряне"</string>
+ <string name="action_reply" msgid="564106590567600685">"Отговор"</string>
+ <string name="action_stop" msgid="6950369080845695405">"Спиране"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"Затваряне"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"Изпращането на отговора не бе успешно. Моля, опитайте отново."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"Изпращането на отговора не бе успешно. Устройството не е свързано."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s казва"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"Съобщението не може да бъде прочетено."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"„%s“"</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"Отговорът бе изпратен до %s"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"Няма име"</string>
+</resources>
diff --git a/car-messenger-common/res/values-bn/strings.xml b/car-messenger-common/res/values-bn/strings.xml
new file mode 100644
index 0000000..bf17122
--- /dev/null
+++ b/car-messenger-common/res/values-bn/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="one">%dটি নতুন মেসেজ</item>
+ <item quantity="other">%dটি নতুন মেসেজ</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"চালান"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"\'পড়া হয়েছে\' হিসেবে চিহ্নিত করুন"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"পুনরাবৃত্তি করুন"</string>
+ <string name="action_reply" msgid="564106590567600685">"উত্তর"</string>
+ <string name="action_stop" msgid="6950369080845695405">"থামান"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"বন্ধ করুন"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"উত্তর পাঠানো যায়নি। আবার চেষ্টা করুন।"</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"উত্তর পাঠানো যায়নি। ডিভাইস কানেক্ট করা নেই।"</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s বলছে"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"মেসেজ পড়া যাচ্ছে না।"</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"\"%s\""</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"%s-এ উত্তর পাঠানো হয়েছে"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"নাম উপলভ্য নেই"</string>
+</resources>
diff --git a/car-messenger-common/res/values-bs/strings.xml b/car-messenger-common/res/values-bs/strings.xml
new file mode 100644
index 0000000..544296a
--- /dev/null
+++ b/car-messenger-common/res/values-bs/strings.xml
@@ -0,0 +1,38 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="one">%d nova poruka</item>
+ <item quantity="few">%d nove poruke</item>
+ <item quantity="other">%d novih poruka</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"Reproduciraj"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"Označi kao pročitano"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"Ponovi"</string>
+ <string name="action_reply" msgid="564106590567600685">"Odgovori"</string>
+ <string name="action_stop" msgid="6950369080845695405">"Zaustavi"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"Zatvori"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"Nije moguće poslati odgovor. Pokušajte ponovo."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"Nije moguće poslati odgovor. Uređaj nije povezan."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s kaže"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"Nije moguće pročitati poruku naglas."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"\"%s\""</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"Odgovor je poslan kontaktu %s"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"Ime nije dostupno"</string>
+</resources>
diff --git a/car-messenger-common/res/values-ca/strings.xml b/car-messenger-common/res/values-ca/strings.xml
new file mode 100644
index 0000000..09174e7
--- /dev/null
+++ b/car-messenger-common/res/values-ca/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="other">%d missatges nous</item>
+ <item quantity="one">Missatge nou</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"Reprodueix"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"Marca com a llegit"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"Repeteix"</string>
+ <string name="action_reply" msgid="564106590567600685">"Respon"</string>
+ <string name="action_stop" msgid="6950369080845695405">"Atura"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"Tanca"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"No s\'ha pogut enviar la resposta. Torna-ho a provar."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"No s\'ha pogut enviar la resposta. El dispositiu no està connectat."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s diu"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"No es pot llegir el missatge en veu alta."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"\"%s\""</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"S\'ha enviat la resposta a %s"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"Nom no disponible"</string>
+</resources>
diff --git a/car-messenger-common/res/values-cs/strings.xml b/car-messenger-common/res/values-cs/strings.xml
new file mode 100644
index 0000000..bd4c28a
--- /dev/null
+++ b/car-messenger-common/res/values-cs/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="few">%d nové zprávy</item>
+ <item quantity="many">%d nové zprávy</item>
+ <item quantity="other">%d nových zpráv</item>
+ <item quantity="one">Nová zpráva</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"Přehrát"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"Označit jako přečtené"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"Opakování"</string>
+ <string name="action_reply" msgid="564106590567600685">"Odpovědět"</string>
+ <string name="action_stop" msgid="6950369080845695405">"Zastavit"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"Zavřít"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"Odpověď se nepodařilo odeslat. Zkuste to znovu."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"Odpověď se nepodařilo odeslat. Zařízení není připojeno."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s říká"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"Zprávu se nepodařilo přečíst."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"„%s“"</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"Odpověď odeslána příjemci %s"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"Jméno není dostupné"</string>
+</resources>
diff --git a/car-messenger-common/res/values-da/strings.xml b/car-messenger-common/res/values-da/strings.xml
new file mode 100644
index 0000000..f18e544
--- /dev/null
+++ b/car-messenger-common/res/values-da/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="one">%d ny besked</item>
+ <item quantity="other">%d nye beskeder</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"Afspil"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"Markér som læst"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"Gentag"</string>
+ <string name="action_reply" msgid="564106590567600685">"Svar"</string>
+ <string name="action_stop" msgid="6950369080845695405">"Stop"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"Luk"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"Svaret kunne ikke sendes. Prøv igen."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"Svaret kunne ikke sendes. Enheden er ikke tilsluttet."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s siger"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"Beskeden kan ikke læses højt."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"\"%s\""</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"Svaret er sendt til %s"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"Navnet er ikke tilgængeligt"</string>
+</resources>
diff --git a/car-messenger-common/res/values-de/strings.xml b/car-messenger-common/res/values-de/strings.xml
new file mode 100644
index 0000000..274b1f1
--- /dev/null
+++ b/car-messenger-common/res/values-de/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="other">%d neue Nachrichten</item>
+ <item quantity="one">Neue Nachricht</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"Wiedergeben"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"Als gelesen markieren"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"Wiederholen"</string>
+ <string name="action_reply" msgid="564106590567600685">"Antworten"</string>
+ <string name="action_stop" msgid="6950369080845695405">"Abbrechen"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"Schließen"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"Antwort kann nicht gesendet werden. Bitte versuch es noch einmal."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"Antwort kann nicht gesendet werden. Gerät ist nicht verbunden."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s sagt"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"Die Nachricht kann nicht vorgelesen werden."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"\"%s\""</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"Antwort wurde an %s gesendet"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"Name nicht verfügbar"</string>
+</resources>
diff --git a/car-messenger-common/res/values-el/strings.xml b/car-messenger-common/res/values-el/strings.xml
new file mode 100644
index 0000000..1429ba4
--- /dev/null
+++ b/car-messenger-common/res/values-el/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="other">%d νέα μηνύματα</item>
+ <item quantity="one">Νέο μήνυμα</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"Αναπαραγωγή"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"Επισήμανση ως αναγνωσμένο"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"Επανάληψη"</string>
+ <string name="action_reply" msgid="564106590567600685">"Απάντηση"</string>
+ <string name="action_stop" msgid="6950369080845695405">"Διακοπή"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"Κλείσιμο"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"Δεν είναι δυνατή η αποστολή απάντησης. Δοκιμάστε ξανά."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"Δεν είναι δυνατή η αποστολή απάντησης. Η συσκευή δεν είναι συνδεδεμένη."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"Ο χρήστης %s λέει"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"Δεν είναι δυνατή η ανάγνωση του μηνύματος."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"%s"</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"Η απάντηση στάλθηκε στον χρήστη %s."</string>
+ <string name="name_not_available" msgid="3800013092212550915">"Το όνομα δεν είναι διαθέσιμο."</string>
+</resources>
diff --git a/car-messenger-common/res/values-en-rAU/strings.xml b/car-messenger-common/res/values-en-rAU/strings.xml
new file mode 100644
index 0000000..e50266e
--- /dev/null
+++ b/car-messenger-common/res/values-en-rAU/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="other">%d new messages</item>
+ <item quantity="one">New message</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"Play"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"Mark as read"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"Repeat"</string>
+ <string name="action_reply" msgid="564106590567600685">"Reply"</string>
+ <string name="action_stop" msgid="6950369080845695405">"Stop"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"Close"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"Unable to send reply. Please try again."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"Unable to send reply. Device is not connected."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s says"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"Can\'t read out message."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"\'%s\'"</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"Reply sent to %s"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"Name not available"</string>
+</resources>
diff --git a/car-messenger-common/res/values-en-rCA/strings.xml b/car-messenger-common/res/values-en-rCA/strings.xml
new file mode 100644
index 0000000..e50266e
--- /dev/null
+++ b/car-messenger-common/res/values-en-rCA/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="other">%d new messages</item>
+ <item quantity="one">New message</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"Play"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"Mark as read"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"Repeat"</string>
+ <string name="action_reply" msgid="564106590567600685">"Reply"</string>
+ <string name="action_stop" msgid="6950369080845695405">"Stop"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"Close"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"Unable to send reply. Please try again."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"Unable to send reply. Device is not connected."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s says"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"Can\'t read out message."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"\'%s\'"</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"Reply sent to %s"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"Name not available"</string>
+</resources>
diff --git a/car-messenger-common/res/values-en-rGB/strings.xml b/car-messenger-common/res/values-en-rGB/strings.xml
new file mode 100644
index 0000000..e50266e
--- /dev/null
+++ b/car-messenger-common/res/values-en-rGB/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="other">%d new messages</item>
+ <item quantity="one">New message</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"Play"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"Mark as read"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"Repeat"</string>
+ <string name="action_reply" msgid="564106590567600685">"Reply"</string>
+ <string name="action_stop" msgid="6950369080845695405">"Stop"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"Close"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"Unable to send reply. Please try again."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"Unable to send reply. Device is not connected."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s says"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"Can\'t read out message."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"\'%s\'"</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"Reply sent to %s"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"Name not available"</string>
+</resources>
diff --git a/car-messenger-common/res/values-en-rIN/strings.xml b/car-messenger-common/res/values-en-rIN/strings.xml
new file mode 100644
index 0000000..e50266e
--- /dev/null
+++ b/car-messenger-common/res/values-en-rIN/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="other">%d new messages</item>
+ <item quantity="one">New message</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"Play"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"Mark as read"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"Repeat"</string>
+ <string name="action_reply" msgid="564106590567600685">"Reply"</string>
+ <string name="action_stop" msgid="6950369080845695405">"Stop"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"Close"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"Unable to send reply. Please try again."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"Unable to send reply. Device is not connected."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s says"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"Can\'t read out message."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"\'%s\'"</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"Reply sent to %s"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"Name not available"</string>
+</resources>
diff --git a/car-messenger-common/res/values-en-rXC/strings.xml b/car-messenger-common/res/values-en-rXC/strings.xml
new file mode 100644
index 0000000..99a3fb8
--- /dev/null
+++ b/car-messenger-common/res/values-en-rXC/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="other">%d new messages</item>
+ <item quantity="one">New message</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"Play"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"Mark As Read"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"Repeat"</string>
+ <string name="action_reply" msgid="564106590567600685">"Reply"</string>
+ <string name="action_stop" msgid="6950369080845695405">"Stop"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"Close"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"Unable to send reply. Please try again."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"Unable to send reply. Device is not connected."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s says"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"Can\'t read out message."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"\"%s\""</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"Reply sent to %s"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"Name not available"</string>
+</resources>
diff --git a/car-messenger-common/res/values-es-rUS/strings.xml b/car-messenger-common/res/values-es-rUS/strings.xml
new file mode 100644
index 0000000..bfd0c97
--- /dev/null
+++ b/car-messenger-common/res/values-es-rUS/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="other">%d mensajes nuevos</item>
+ <item quantity="one">Mensaje nuevo</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"Reproducir"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"Marcar como leído"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"Repetir"</string>
+ <string name="action_reply" msgid="564106590567600685">"Responder"</string>
+ <string name="action_stop" msgid="6950369080845695405">"Detener"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"Cerrar"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"No se pudo enviar la respuesta. Vuelve a intentarlo."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"No se pudo enviar la respuesta. El dispositivo no está conectado."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s dice"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"No se puede leer en voz alta el mensaje."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"\"%s\""</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"Se envió la respuesta a %s"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"Nombre no disponible"</string>
+</resources>
diff --git a/car-messenger-common/res/values-es/strings.xml b/car-messenger-common/res/values-es/strings.xml
new file mode 100644
index 0000000..0a66752
--- /dev/null
+++ b/car-messenger-common/res/values-es/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="other">%d mensajes nuevos</item>
+ <item quantity="one">Mensaje nuevo</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"Reproducir"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"Marcar como leído"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"Repetir"</string>
+ <string name="action_reply" msgid="564106590567600685">"Responder"</string>
+ <string name="action_stop" msgid="6950369080845695405">"Detener"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"Cerrar"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"No se ha podido enviar la respuesta. Inténtalo de nuevo."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"No se ha podido enviar la respuesta. El dispositivo no está conectado."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s dice"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"No se puede leer el mensaje en voz alta."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"\"%s\""</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"Se ha enviado la respuesta a %s"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"El nombre no está disponible"</string>
+</resources>
diff --git a/car-messenger-common/res/values-et/strings.xml b/car-messenger-common/res/values-et/strings.xml
new file mode 100644
index 0000000..e4167f6
--- /dev/null
+++ b/car-messenger-common/res/values-et/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="other">%d uut sõnumit</item>
+ <item quantity="one">Uus sõnum</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"Esita"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"Märgi loetuks"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"Korda"</string>
+ <string name="action_reply" msgid="564106590567600685">"Vasta"</string>
+ <string name="action_stop" msgid="6950369080845695405">"Peata"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"Sule"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"Vastust ei saa saata. Proovige uuesti."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"Vastust ei saa saata. Seade pole ühendatud."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s ütleb"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"Sõnumit ei saa ette lugeda."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"„%s”"</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"Vastus saadeti üksusele %s"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"Nimi pole saadaval"</string>
+</resources>
diff --git a/car-messenger-common/res/values-eu/strings.xml b/car-messenger-common/res/values-eu/strings.xml
new file mode 100644
index 0000000..7a5c20e
--- /dev/null
+++ b/car-messenger-common/res/values-eu/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="other">%d mezu berri</item>
+ <item quantity="one">Mezu berria</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"Erreproduzitu"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"Markatu irakurritako gisa"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"Errepikatu"</string>
+ <string name="action_reply" msgid="564106590567600685">"Erantzun"</string>
+ <string name="action_stop" msgid="6950369080845695405">"Gelditu"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"Itxi"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"Ezin da bidali erantzuna. Saiatu berriro."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"Ezin da bidali erantzuna. Gailua ez dago konektatuta."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s erabiltzaileak hau dio:"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"Ezin da irakurri ozen mezua."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"\"%s\""</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"Erantzuna bidali zaio %s erabiltzaileari"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"Izena ez dago erabilgarri"</string>
+</resources>
diff --git a/car-messenger-common/res/values-fa/strings.xml b/car-messenger-common/res/values-fa/strings.xml
new file mode 100644
index 0000000..71fc229
--- /dev/null
+++ b/car-messenger-common/res/values-fa/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="one">%d پیام جدید</item>
+ <item quantity="other">%d پیام جدید</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"پخش"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"علامتگذاری بهعنوان خواندهشده"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"تکرار"</string>
+ <string name="action_reply" msgid="564106590567600685">"پاسخ"</string>
+ <string name="action_stop" msgid="6950369080845695405">"توقف"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"بستن"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"پاسخ ارسال نشد. لطفاً دوباره امتحان کنید."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"پاسخ ارسال نشد. دستگاه متصل نشده است."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s میگوید"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"خواندن پیام ممکن نیست."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"«%s»"</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"پاسخ برای %s ارسال شد"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"نام در دسترس نیست"</string>
+</resources>
diff --git a/car-messenger-common/res/values-fi/strings.xml b/car-messenger-common/res/values-fi/strings.xml
new file mode 100644
index 0000000..4e905c2
--- /dev/null
+++ b/car-messenger-common/res/values-fi/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="other">%d uutta viestiä</item>
+ <item quantity="one">Uusi viesti</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"Toista"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"Merkitse luetuksi"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"Toista uudelleen"</string>
+ <string name="action_reply" msgid="564106590567600685">"Vastaa"</string>
+ <string name="action_stop" msgid="6950369080845695405">"Lopeta"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"Sulje"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"Vastaaminen ei onnistunut. Yritä uudelleen."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"Vastaaminen ei onnistunut. Laite ei saa yhteyttä."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s sanoo"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"Viestiä ei voi lukea."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"\"%s\""</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"Vastaus lähetetty: %s"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"Nimi ei ole saatavilla"</string>
+</resources>
diff --git a/car-messenger-common/res/values-fr-rCA/strings.xml b/car-messenger-common/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000..56086e6
--- /dev/null
+++ b/car-messenger-common/res/values-fr-rCA/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="one">%d nouveau message</item>
+ <item quantity="other">%d nouveaux messages</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"Faire jouer"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"Marquer comme lu"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"Répéter"</string>
+ <string name="action_reply" msgid="564106590567600685">"Répondre"</string>
+ <string name="action_stop" msgid="6950369080845695405">"Arrêter"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"Fermer"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"Impossible d\'envoyer la réponse. Veuillez réessayer."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"Impossible d\'envoyer la réponse. L\'appareil n\'est pas connecté."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s dit"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"Impossible de lire le message."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"« %s »"</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"Réponse envoyée à %s"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"Nom indisponible"</string>
+</resources>
diff --git a/car-messenger-common/res/values-fr/strings.xml b/car-messenger-common/res/values-fr/strings.xml
new file mode 100644
index 0000000..a96b14f
--- /dev/null
+++ b/car-messenger-common/res/values-fr/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="one">%d nouveau message</item>
+ <item quantity="other">%d nouveaux messages</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"Lire"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"Marquer comme lu"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"Répéter"</string>
+ <string name="action_reply" msgid="564106590567600685">"Répondre"</string>
+ <string name="action_stop" msgid="6950369080845695405">"Arrêter"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"Fermer"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"Impossible d\'envoyer la réponse. Veuillez réessayer."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"Impossible d\'envoyer la réponse. L\'appareil n\'est pas connecté."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s dit"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"Impossible de lire le message à haute voix."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"\"%s\""</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"Réponse envoyée à %s"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"Nom indisponible"</string>
+</resources>
diff --git a/car-messenger-common/res/values-gl/strings.xml b/car-messenger-common/res/values-gl/strings.xml
new file mode 100644
index 0000000..b81c8e7
--- /dev/null
+++ b/car-messenger-common/res/values-gl/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="other">%d mensaxes novas</item>
+ <item quantity="one">Mensaxe nova</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"Reproducir"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"Marcar como lido"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"Repetir"</string>
+ <string name="action_reply" msgid="564106590567600685">"Responder"</string>
+ <string name="action_stop" msgid="6950369080845695405">"Deter"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"Pechar"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"Non se puido enviar a resposta. Téntao de novo."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"Non se puido enviar a resposta. O dispositivo non está conectado."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s di"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"Non se puido ler a mensaxe."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"\"%s\""</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"Enviouse a resposta a %s"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"O nome non está dispoñible"</string>
+</resources>
diff --git a/car-messenger-common/res/values-gu/strings.xml b/car-messenger-common/res/values-gu/strings.xml
new file mode 100644
index 0000000..3871966
--- /dev/null
+++ b/car-messenger-common/res/values-gu/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="one">%d નવો સંદેશ</item>
+ <item quantity="other">%d નવા સંદેશા</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"ચલાવો"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"વાંચેલાં તરીકે ચિહ્નિત કરો"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"પુનરાવર્તન"</string>
+ <string name="action_reply" msgid="564106590567600685">"જવાબ આપો"</string>
+ <string name="action_stop" msgid="6950369080845695405">"રોકો"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"બંધ કરો"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"જવાબ મોકલી શકતા નથી. કૃપા કરી ફરી પ્રયાસ કરો."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"જવાબ મોકલી શકતા નથી. ડિવાઇસ કનેક્ટ થયું નથી."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s કહે છે"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"સંદેશ વાંચી શકાતો નથી."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"\"%s\""</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"%s પર જવાબ મોકલ્યો છે"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"નામ ઉપલબ્ધ નથી"</string>
+</resources>
diff --git a/car-messenger-common/res/values-hi/strings.xml b/car-messenger-common/res/values-hi/strings.xml
new file mode 100644
index 0000000..74a5693
--- /dev/null
+++ b/car-messenger-common/res/values-hi/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="one">%d नए मैसेज</item>
+ <item quantity="other">%d नए मैसेज</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"चलाएं"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"\'पढ़ा गया\' का निशान लगाएं"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"दोहराएं"</string>
+ <string name="action_reply" msgid="564106590567600685">"जवाब दें"</string>
+ <string name="action_stop" msgid="6950369080845695405">"रोकें"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"बंद करें"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"जवाब नहीं भेजा जा सका. कृपया फिर से कोशिश करें."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"जवाब नहीं भेजा जा सका. डिवाइस कनेक्ट नहीं है."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s का मैसेज यह है"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"मैसेज पढ़ा नहीं जा सकता."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"\"%s\""</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"%s को जवाब भेजा गया"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"नाम उपलब्ध नहीं है"</string>
+</resources>
diff --git a/car-messenger-common/res/values-hr/strings.xml b/car-messenger-common/res/values-hr/strings.xml
new file mode 100644
index 0000000..8a46b5d
--- /dev/null
+++ b/car-messenger-common/res/values-hr/strings.xml
@@ -0,0 +1,38 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="one">%d nova poruka</item>
+ <item quantity="few">%d nove poruke</item>
+ <item quantity="other">%d novih poruka</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"Pokreni"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"Označi kao pročitano"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"Ponovi"</string>
+ <string name="action_reply" msgid="564106590567600685">"Odgovori"</string>
+ <string name="action_stop" msgid="6950369080845695405">"Zaustavi"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"Zatvori"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"Slanje odgovora nije uspjelo. Pokušajte ponovo."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"Slanje odgovora nije uspjelo. Uređaj nije povezan."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s kaže"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"Nije moguće pročitati poruku naglas."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"\"%s\""</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"Odgovor je poslan kontaktu %s"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"Ime nije dostupno"</string>
+</resources>
diff --git a/car-messenger-common/res/values-hu/strings.xml b/car-messenger-common/res/values-hu/strings.xml
new file mode 100644
index 0000000..c6d7693
--- /dev/null
+++ b/car-messenger-common/res/values-hu/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="other">%d új üzenet</item>
+ <item quantity="one">Új üzenet</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"Lejátszás"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"Megjelölés olvasottként"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"Ismétlés"</string>
+ <string name="action_reply" msgid="564106590567600685">"Válasz"</string>
+ <string name="action_stop" msgid="6950369080845695405">"Leállítás"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"Bezárás"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"Nem sikerült a válasz elküldése. Próbálja újra."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"Nem sikerült a válasz elküldése. Az eszköz nincs csatlakoztatva."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s a következőt küldte:"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"Az üzenet felolvasása nem sikerült."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"„%s”"</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"Válasz elküldve a következőnek: %s"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"A név nem használható"</string>
+</resources>
diff --git a/car-messenger-common/res/values-hy/strings.xml b/car-messenger-common/res/values-hy/strings.xml
new file mode 100644
index 0000000..c6faa75
--- /dev/null
+++ b/car-messenger-common/res/values-hy/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="one">%d նոր հաղորդագրություն</item>
+ <item quantity="other">%d նոր հաղորդագրություն</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"Նվագարկել"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"Նշել որպես կարդացված"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"Կրկնել"</string>
+ <string name="action_reply" msgid="564106590567600685">"Պատասխանել"</string>
+ <string name="action_stop" msgid="6950369080845695405">"Դադարեցնել"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"Փակել"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"Չհաջողվեց ուղարկել պատասխանը։ Նորից փորձեք:"</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"Չհաջողվեց ուղարկել պատասխանը։ Սարքը միացված չէ։"</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"Հաղորդագրություն %s-ից․"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"Չհաջողվեց ընթերցել հաղորդագրությունը։"</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"«%s»"</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"Պատասխանն ուղարկվեց %s-ին"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"Անունը հասանելի չէ"</string>
+</resources>
diff --git a/car-messenger-common/res/values-in/strings.xml b/car-messenger-common/res/values-in/strings.xml
new file mode 100644
index 0000000..12182d4
--- /dev/null
+++ b/car-messenger-common/res/values-in/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="other">%d pesan baru</item>
+ <item quantity="one">Pesan baru</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"Putar"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"Tandai Telah Dibaca"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"Ulangi"</string>
+ <string name="action_reply" msgid="564106590567600685">"Balas"</string>
+ <string name="action_stop" msgid="6950369080845695405">"Berhenti"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"Tutup"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"Tidak dapat mengirim balasan. Coba lagi."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"Tidak dapat mengirim balasan. Perangkat tidak terhubung"</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s mengatakan"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"Tidak dapat membacakan pesan."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"\"%s\""</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"Jawaban dikirim ke %s"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"Nama tidak tersedia"</string>
+</resources>
diff --git a/car-messenger-common/res/values-is/strings.xml b/car-messenger-common/res/values-is/strings.xml
new file mode 100644
index 0000000..079b6d5
--- /dev/null
+++ b/car-messenger-common/res/values-is/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="one">%d ný skilaboð</item>
+ <item quantity="other">%d ný skilaboð</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"Spila"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"Merkja sem lesið"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"Endurtaka"</string>
+ <string name="action_reply" msgid="564106590567600685">"Svara"</string>
+ <string name="action_stop" msgid="6950369080845695405">"Stöðva"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"Loka"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"Ekki tókst að senda svar. Reyndu aftur."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"Ekki tókst að senda svar. Tækið er ekki tengt."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s segir"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"Ekki er hægt að lesa upp skilaboð."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"„%s“"</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"Svar sent til %s"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"Nafnið er ekki tiltækt"</string>
+</resources>
diff --git a/car-messenger-common/res/values-it/strings.xml b/car-messenger-common/res/values-it/strings.xml
new file mode 100644
index 0000000..a1f750d
--- /dev/null
+++ b/car-messenger-common/res/values-it/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="other">%d nuovi messaggi</item>
+ <item quantity="one">Nuovo messaggio</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"Riproduci"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"Segna come letto"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"Ripeti"</string>
+ <string name="action_reply" msgid="564106590567600685">"Rispondi"</string>
+ <string name="action_stop" msgid="6950369080845695405">"Interrompi"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"Chiudi"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"Impossibile inviare la risposta. Riprova."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"Impossibile inviare la risposta. Il dispositivo non è collegato."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s dice"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"Impossibile leggere il messaggio ad alta voce."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"\"%s\""</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"Risposta inviata a %s"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"Nome non disponibile"</string>
+</resources>
diff --git a/car-messenger-common/res/values-iw/strings.xml b/car-messenger-common/res/values-iw/strings.xml
new file mode 100644
index 0000000..c28823d
--- /dev/null
+++ b/car-messenger-common/res/values-iw/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="two">%d הודעות חדשות</item>
+ <item quantity="many">%d הודעות חדשות</item>
+ <item quantity="other">%d הודעות חדשות</item>
+ <item quantity="one">הודעה חדשה</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"הפעלה"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"סימון כפריט שנקרא"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"חזרה"</string>
+ <string name="action_reply" msgid="564106590567600685">"שליחת תשובה"</string>
+ <string name="action_stop" msgid="6950369080845695405">"עצירה"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"סגירה"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"לא ניתן לשלוח תשובה. יש לנסות שוב."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"לא ניתן לשלוח תשובה. המכשיר לא מחובר."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s אומר/ת"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"לא ניתן להקריא את ההודעה."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"\"%s\""</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"התשובה נשלחה אל %s"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"השם לא זמין"</string>
+</resources>
diff --git a/car-messenger-common/res/values-ja/strings.xml b/car-messenger-common/res/values-ja/strings.xml
new file mode 100644
index 0000000..6393b4f
--- /dev/null
+++ b/car-messenger-common/res/values-ja/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="other">%d 件の新着メッセージ</item>
+ <item quantity="one">新着メッセージ</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"再生"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"既読にする"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"繰り返し"</string>
+ <string name="action_reply" msgid="564106590567600685">"返信"</string>
+ <string name="action_stop" msgid="6950369080845695405">"停止"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"閉じる"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"返信できませんでした。もう一度お試しください。"</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"返信できませんでした。デバイスが接続されていません。"</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s さんからのメッセージです"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"メッセージを読み上げられません。"</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"「%s」"</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"%s さんに返信しました"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"名前がありません"</string>
+</resources>
diff --git a/car-messenger-common/res/values-ka/strings.xml b/car-messenger-common/res/values-ka/strings.xml
new file mode 100644
index 0000000..29c46f3
--- /dev/null
+++ b/car-messenger-common/res/values-ka/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="other">%d ახალი შეტყობინება</item>
+ <item quantity="one">ახალი შეტყობინება</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"დაკვრა"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"წაკითხულად მონიშვნა"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"გამეორება"</string>
+ <string name="action_reply" msgid="564106590567600685">"პასუხი"</string>
+ <string name="action_stop" msgid="6950369080845695405">"შეწყვეტა"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"დახურვა"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"პასუხის გაგზავნა ვერ მოხერხდა. გთხოვთ, ცადოთ ხელახლა."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"პასუხის გაგზავნა ვერ მოხერხდა. მოწყობილობა დაკავშირებული არ არის."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s ამბობს"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"შეტყობინების ხმამაღლა წაკითხვა ვერ ხერხდება."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"„%s“"</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"პასუხი გაეგზავნა %s-ს"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"სახელი მიუწვდომელია"</string>
+</resources>
diff --git a/car-messenger-common/res/values-kk/strings.xml b/car-messenger-common/res/values-kk/strings.xml
new file mode 100644
index 0000000..9132ef2
--- /dev/null
+++ b/car-messenger-common/res/values-kk/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="other">%d жаңа хабар</item>
+ <item quantity="one">Жаңа хабар</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"Ойнату"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"Оқылды деп белгілеу"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"Қайталау"</string>
+ <string name="action_reply" msgid="564106590567600685">"Жауап беру"</string>
+ <string name="action_stop" msgid="6950369080845695405">"Тоқтату"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"Жабу"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"Жауап жіберілмеді. Қайталап көріңіз."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"Жауап жіберілмеді. Құрылғы жалғанбаған."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s дейді"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"Хабар оқылмады."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"\"%s\""</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"Жауап %s атты пайдаланушыға жіберілді."</string>
+ <string name="name_not_available" msgid="3800013092212550915">"Атауы жоқ"</string>
+</resources>
diff --git a/car-messenger-common/res/values-km/strings.xml b/car-messenger-common/res/values-km/strings.xml
new file mode 100644
index 0000000..b060c99
--- /dev/null
+++ b/car-messenger-common/res/values-km/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="other">សារថ្មី %d</item>
+ <item quantity="one">សារថ្មី</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"ចាក់"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"សម្គាល់ថាបានអានហើយ"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"ធ្វើឡើងវិញ"</string>
+ <string name="action_reply" msgid="564106590567600685">"ឆ្លើយតប"</string>
+ <string name="action_stop" msgid="6950369080845695405">"ឈប់"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"បិទ"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"មិនអាចផ្ញើការឆ្លើយតបបានទេ។ សូមព្យាយាមម្ដងទៀត។"</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"មិនអាចផ្ញើការឆ្លើយតបបានទេ។ មិនបានភ្ជាប់ឧបករណ៍ទេ។"</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s និយាយថា"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"មិនអាចអានសារឱ្យឮៗបានទេ។"</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"\"%s\""</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"ការឆ្លើយតបដែលបានផ្ញើទៅ %s"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"មិនមានឈ្មោះទេ"</string>
+</resources>
diff --git a/car-messenger-common/res/values-kn/strings.xml b/car-messenger-common/res/values-kn/strings.xml
new file mode 100644
index 0000000..4b89c85
--- /dev/null
+++ b/car-messenger-common/res/values-kn/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="one">%d ಹೊಸ ಸಂದೇಶಗಳು</item>
+ <item quantity="other">%d ಹೊಸ ಸಂದೇಶಗಳು</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"ಪ್ಲೇ"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"ಓದಲಾಗಿದೆ ಎಂದು ಗುರುತಿಸಿ"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"ಪುನರಾವರ್ತನೆ"</string>
+ <string name="action_reply" msgid="564106590567600685">"ಪ್ರತ್ಯುತ್ತರಿಸಿ"</string>
+ <string name="action_stop" msgid="6950369080845695405">"ನಿಲ್ಲಿಸಿ"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"ಮುಚ್ಚಿರಿ"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"ಪ್ರತ್ಯುತ್ತರ ಕಳುಹಿಸಲು ವಿಫಲವಾಗಿದೆ. ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"ಪ್ರತ್ಯುತ್ತರ ಕಳುಹಿಸಲು ವಿಫಲವಾಗಿದೆ. ಸಾಧನವು ಕನೆಕ್ಟ್ ಆಗಿಲ್ಲ."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s ಹೇಳುತ್ತದೆ"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"ಸಂದೇಶವನ್ನು ಓದಲು ಸಾಧ್ಯವಿಲ್ಲ."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"\"%s\""</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"%s ಗೆ ಪ್ರತ್ಯುತ್ತರ ಕಳುಹಿಸಲಾಗಿದೆ"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"ಹೆಸರು ಲಭ್ಯವಿಲ್ಲ"</string>
+</resources>
diff --git a/car-messenger-common/res/values-ko/strings.xml b/car-messenger-common/res/values-ko/strings.xml
new file mode 100644
index 0000000..1264304
--- /dev/null
+++ b/car-messenger-common/res/values-ko/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="other">새 메시지 %d개</item>
+ <item quantity="one">새 메시지</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"재생"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"읽은 상태로 표시"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"반복"</string>
+ <string name="action_reply" msgid="564106590567600685">"답장"</string>
+ <string name="action_stop" msgid="6950369080845695405">"중지"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"닫기"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"답장을 보낼 수 없습니다. 다시 시도해 보세요."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"답장을 보낼 수 없습니다. 기기가 연결되어 있지 않습니다."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s님의 말입니다"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"메시지를 소리 내어 읽을 수 없습니다."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"’%s’"</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"%s님에게 답장을 전송했습니다."</string>
+ <string name="name_not_available" msgid="3800013092212550915">"이름을 사용할 수 없습니다."</string>
+</resources>
diff --git a/car-messenger-common/res/values-ky/strings.xml b/car-messenger-common/res/values-ky/strings.xml
new file mode 100644
index 0000000..34061ab
--- /dev/null
+++ b/car-messenger-common/res/values-ky/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="other">%d жаңы билдирүү</item>
+ <item quantity="one">Жаңы билдирүү</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"Ойнотуу"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"Окулду деп белгилөө"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"Кайталоо"</string>
+ <string name="action_reply" msgid="564106590567600685">"Жооп берүү"</string>
+ <string name="action_stop" msgid="6950369080845695405">"Токтотуу"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"Жабуу"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"Жооп жөнөтүлгөн жок. Кайра аракет кылыңыз."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"Жооп жөнөтүлгөн жок. Түзмөк туташкан жок."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s төмөнкүнү айтты:"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"Билдирүү окулбай жатат."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"\"%s\""</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"Жооп төмөнкүгө жөнөтүлдү: %s"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"Аты-жөнү жеткиликсиз"</string>
+</resources>
diff --git a/car-messenger-common/res/values-lo/strings.xml b/car-messenger-common/res/values-lo/strings.xml
new file mode 100644
index 0000000..db6627d
--- /dev/null
+++ b/car-messenger-common/res/values-lo/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="other">%d ຂໍ້ຄວາມໃໝ່</item>
+ <item quantity="one">ຂໍ້ຄວາມໃໝ່</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"ຫຼິ້ນ"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"ໝາຍວ່າອ່ານແລ້ວ"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"ເຮັດຊໍ້າຄືນ"</string>
+ <string name="action_reply" msgid="564106590567600685">"ຕອບກັບ"</string>
+ <string name="action_stop" msgid="6950369080845695405">"ຢຸດ"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"ປິດ"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"ບໍ່ສາມາດສົ່ງການຕອບກັບໄດ້. ກະລຸນາລອງໃໝ່."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"ບໍ່ສາມາດສົ່ງການຕອບກັບໄດ້. ອຸປະກອນບໍ່ໄດ້ເຊື່ອມຕໍ່."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s ເວົ້າວ່າ"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"ບໍ່ສາມາດອ່ານອອກສຽງຂໍ້ຄວາມໄດ້."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"\"%s\""</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"ສົ່ງການຕອບກັບຫາ %s ແລ້ວ"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"ຊື່ບໍ່ສາມາດໃຊ້ໄດ້"</string>
+</resources>
diff --git a/car-messenger-common/res/values-lt/strings.xml b/car-messenger-common/res/values-lt/strings.xml
new file mode 100644
index 0000000..e9ba6cb
--- /dev/null
+++ b/car-messenger-common/res/values-lt/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="one">%d naujas pranešimas</item>
+ <item quantity="few">%d nauji pranešimai</item>
+ <item quantity="many">%d naujo pranešimo</item>
+ <item quantity="other">%d naujų pranešimų</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"Leisti"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"Pažymėti kaip skaitytą"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"Kartoti"</string>
+ <string name="action_reply" msgid="564106590567600685">"Atsakyti"</string>
+ <string name="action_stop" msgid="6950369080845695405">"Sustabdyti"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"Uždaryti"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"Nepavyko išsiųsti atsakymo. Bandykite dar kartą."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"Nepavyko išsiųsti atsakymo. Įrenginys neprijungtas."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s sako"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"Nepavyksta perskaityti pranešimo."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"„%s“"</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"Atsakymas išsiųstas %s"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"Vardas nepasiekiamas"</string>
+</resources>
diff --git a/car-messenger-common/res/values-lv/strings.xml b/car-messenger-common/res/values-lv/strings.xml
new file mode 100644
index 0000000..c6990ec
--- /dev/null
+++ b/car-messenger-common/res/values-lv/strings.xml
@@ -0,0 +1,38 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="zero">%d jauni ziņojumi</item>
+ <item quantity="one">%d jauns ziņojums</item>
+ <item quantity="other">%d jauni ziņojumi</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"Atskaņot"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"Atzīmēt kā izlasītu"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"Atkārtot"</string>
+ <string name="action_reply" msgid="564106590567600685">"Atbildēt"</string>
+ <string name="action_stop" msgid="6950369080845695405">"Apturēt"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"Aizvērt"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"Nevar nosūtīt atbildi. Mēģiniet vēlreiz."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"Nevar nosūtīt atbildi. Ierīce nav pievienota."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s saka"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"Nevar nolasīt ziņojumu."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"“%s”"</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"Atbilde nosūtīta lietotājam %s"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"Vārds nav pieejams."</string>
+</resources>
diff --git a/car-messenger-common/res/values-mk/strings.xml b/car-messenger-common/res/values-mk/strings.xml
new file mode 100644
index 0000000..12da0be
--- /dev/null
+++ b/car-messenger-common/res/values-mk/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="one">%d нова порака</item>
+ <item quantity="other">%d нови пораки</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"Пушти"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"Означи како прочитано"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"Повтори"</string>
+ <string name="action_reply" msgid="564106590567600685">"Одговори"</string>
+ <string name="action_stop" msgid="6950369080845695405">"Сопри"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"Затвори"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"Не може да се испрати одговор. Обидете се повторно."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"Не може да се испрати одговор. Уредот не е поврзан."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s вели"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"Не може да се прочита пораката на глас."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"„%s“"</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"Одговорот е испратен до %s"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"Името не е достапно"</string>
+</resources>
diff --git a/car-messenger-common/res/values-ml/strings.xml b/car-messenger-common/res/values-ml/strings.xml
new file mode 100644
index 0000000..d154f97
--- /dev/null
+++ b/car-messenger-common/res/values-ml/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="other">%d പുതിയ സന്ദേശങ്ങൾ</item>
+ <item quantity="one">പുതിയ സന്ദേശം</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"പ്ലേ ചെയ്യുക"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"വായിച്ചതായി അടയാളപ്പെടുത്തുക"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"ആവർത്തിക്കുക"</string>
+ <string name="action_reply" msgid="564106590567600685">"മറുപടി നൽകുക"</string>
+ <string name="action_stop" msgid="6950369080845695405">"നിർത്തുക"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"അടയ്ക്കുക"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"മറുപടി അയയ്ക്കാനാവുന്നില്ല. വീണ്ടും ശ്രമിക്കുക."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"മറുപടി അയയ്ക്കാനാവുന്നില്ല. ഉപകരണം കണക്റ്റ് ചെയ്തിട്ടില്ല."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s പറയുന്നു"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"സന്ദേശം ഉറക്കെ വായിക്കാനാവില്ല."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"\"%s\""</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"%s എന്നതിലേക്ക് മറുപടി അയച്ചു"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"പേര് ലഭ്യമല്ല"</string>
+</resources>
diff --git a/car-messenger-common/res/values-mn/strings.xml b/car-messenger-common/res/values-mn/strings.xml
new file mode 100644
index 0000000..d47453b
--- /dev/null
+++ b/car-messenger-common/res/values-mn/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="other">%d шинэ зурвас</item>
+ <item quantity="one">Шинэ зурвас</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"Тоглуулах"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"Уншсан гэж тэмдэглэх"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"Давтах"</string>
+ <string name="action_reply" msgid="564106590567600685">"Хариу бичих"</string>
+ <string name="action_stop" msgid="6950369080845695405">"Зогсоох"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"Хаах"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"Хариу илгээх боломжгүй байна. Дахин оролдоно уу."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"Хариу илгээх боломжгүй байна. Төхөөрөмж холбогдоогүй байна."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s хэлж байна"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"Зурвасыг унших боломжгүй байна."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"\"%s\""</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"%s-д хариу илгээсэн"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"Нэр ашиглалтад алга"</string>
+</resources>
diff --git a/car-messenger-common/res/values-mr/strings.xml b/car-messenger-common/res/values-mr/strings.xml
new file mode 100644
index 0000000..d81f6e9
--- /dev/null
+++ b/car-messenger-common/res/values-mr/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="other">%d नवीन मेसेज</item>
+ <item quantity="one">नवीन मेसेज</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"प्ले करा"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"वाचलेले म्हणून खूण करा"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"रिपीट करा"</string>
+ <string name="action_reply" msgid="564106590567600685">"उतर द्या"</string>
+ <string name="action_stop" msgid="6950369080845695405">"थांबा"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"बंद करा"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"उत्तर पाठवता आले नाही. कृपया पुन्हा प्रयत्न करा."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"उत्तर पाठवता आले नाही. डिव्हाइस कनेक्ट केलेले नाही."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s म्हणतात"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"मेसेज वाचू शकत नाही."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"\"%s\""</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"उत्तर %s ला पाठवले"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"नाव उपलब्ध नाही"</string>
+</resources>
diff --git a/car-messenger-common/res/values-ms/strings.xml b/car-messenger-common/res/values-ms/strings.xml
new file mode 100644
index 0000000..ff4041c
--- /dev/null
+++ b/car-messenger-common/res/values-ms/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="other">%d mesej baharu</item>
+ <item quantity="one">Mesej baharu</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"Main"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"Tandai Sebagai Dibaca"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"Ulang"</string>
+ <string name="action_reply" msgid="564106590567600685">"Balas"</string>
+ <string name="action_stop" msgid="6950369080845695405">"Berhenti"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"Tutup"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"Tidak dapat menghantar balasan. Sila cuba lagi."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"Tidak dapat menghantar balasan. Peranti tidak disambungkan."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s mengatakan"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"Tidak dapat membaca mesej dengan kuat."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"\"%s\""</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"Balasan dihantar kepada %s"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"Nama tidak tersedia"</string>
+</resources>
diff --git a/car-messenger-common/res/values-my/strings.xml b/car-messenger-common/res/values-my/strings.xml
new file mode 100644
index 0000000..9604313
--- /dev/null
+++ b/car-messenger-common/res/values-my/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="other">မက်ဆေ့ဂျ်အသစ် %d စောင်</item>
+ <item quantity="one">မက်ဆေ့ဂျ်အသစ်</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"ဖွင့်ရန်"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"ဖတ်ပြီးဟု မှတ်သားရန်"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"ထပ်လုပ်ရန်"</string>
+ <string name="action_reply" msgid="564106590567600685">"စာပြန်ရန်"</string>
+ <string name="action_stop" msgid="6950369080845695405">"ရပ်ရန်"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"ပိတ်ရန်"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"ပြန်စာကို ပို့၍မရပါ။ ထပ်စမ်းကြည့်ပါ။"</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"ပြန်စာကို ပို့၍မရပါ။ စက်ကို ကွန်ရက်ချိတ်မထားပါ။"</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s ကပြောသည်မှာ"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"မက်ဆေ့ဂျ်ကို အသံထွက်ဖတ်၍မရပါ။"</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"\"%s\""</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"ပြန်စာကို %s သို့ ပို့လိုက်ပါပြီ"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"အမည် မရနိုင်ပါ"</string>
+</resources>
diff --git a/car-messenger-common/res/values-nb/strings.xml b/car-messenger-common/res/values-nb/strings.xml
new file mode 100644
index 0000000..70be831
--- /dev/null
+++ b/car-messenger-common/res/values-nb/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="other">%d nye meldinger</item>
+ <item quantity="one">Ny melding</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"Spill av"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"Merk som lest"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"Gjenta"</string>
+ <string name="action_reply" msgid="564106590567600685">"Svar"</string>
+ <string name="action_stop" msgid="6950369080845695405">"Stopp"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"Lukk"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"Kan ikke sende svaret. Prøv på nytt."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"Kan ikke sende svaret. Enheten er ikke tilkoblet."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s sier"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"Kan ikke lese opp meldingen."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"«%s»"</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"Svaret er sendt til %s"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"Navnet er ikke tilgjengelig"</string>
+</resources>
diff --git a/car-messenger-common/res/values-ne/strings.xml b/car-messenger-common/res/values-ne/strings.xml
new file mode 100644
index 0000000..26e1e7c
--- /dev/null
+++ b/car-messenger-common/res/values-ne/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="other">%d नयाँ सन्देशहरू</item>
+ <item quantity="one">नयाँ सन्देश</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"प्ले गर्नुहोस्"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"पढिसकिएको भनी चिन्ह लगाउनुहोस्"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"दोहोर्याउनुहोस्"</string>
+ <string name="action_reply" msgid="564106590567600685">"जवाफ पठाउनुहोस्"</string>
+ <string name="action_stop" msgid="6950369080845695405">"रोक्नुहोस्"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"बन्द गर्नुहोस्"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"जवाफ पठाउन सकिएन। कृपया फेरि प्रयास गर्नुहोस्।"</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"जवाफ पठाउन सकिएन। यन्त्र जोडिएको छैन।"</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s निम्न कुरा भन्नुहुन्छ:"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"सन्देशहरू पढ्न सकिँदैन।"</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"\"%s\""</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"%s मा जवाफ पठाइयो"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"नाम उपलब्ध छैन"</string>
+</resources>
diff --git a/car-messenger-common/res/values-nl/strings.xml b/car-messenger-common/res/values-nl/strings.xml
new file mode 100644
index 0000000..42aff7a
--- /dev/null
+++ b/car-messenger-common/res/values-nl/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="other">%d nieuwe berichten</item>
+ <item quantity="one">Nieuw bericht</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"Afspelen"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"Markeren als gelezen"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"Herhalen"</string>
+ <string name="action_reply" msgid="564106590567600685">"Beantwoorden"</string>
+ <string name="action_stop" msgid="6950369080845695405">"Stoppen"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"Sluiten"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"Antwoord kan niet worden verstuurd. Probeer het opnieuw."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"Antwoord kan niet worden verstuurd. Apparaat is niet verbonden."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s zegt"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"Kan bericht niet voorlezen."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"\'%s\'"</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"Antwoord naar %s gestuurd"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"Naam niet beschikbaar"</string>
+</resources>
diff --git a/car-messenger-common/res/values-or/strings.xml b/car-messenger-common/res/values-or/strings.xml
new file mode 100644
index 0000000..168f3ae
--- /dev/null
+++ b/car-messenger-common/res/values-or/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="other">%dଟି ନୂଆ ମେସେଜ୍</item>
+ <item quantity="one">ନୂଆ ମେସେଜ୍</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"ଚଲାନ୍ତୁ"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"ପଠିତ ଭାବେ ଚିହ୍ନଟ କରନ୍ତୁ"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"ପୁନରାବୃତ୍ତି କରନ୍ତୁ"</string>
+ <string name="action_reply" msgid="564106590567600685">"ପ୍ରତ୍ୟୁତ୍ତର କରନ୍ତୁ"</string>
+ <string name="action_stop" msgid="6950369080845695405">"ବନ୍ଦ କରନ୍ତୁ"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"ବନ୍ଦ କରନ୍ତୁ"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"ପ୍ରତ୍ୟୁତ୍ତର ପଠାଇବାକୁ ଅସମର୍ଥ। ଦୟାକରି ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"ପ୍ରତ୍ୟୁତ୍ତର ପଠାଇବାକୁ ଅସମର୍ଥ। ଡିଭାଇସ୍ ସଂଯୋଗ ହୋଇନାହିଁ।"</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s କୁହେ"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"ମେସେଜ୍ ପଢ଼ାଯାଇପାରିବ ନାହିଁ।"</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"\"%s\""</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"%sକୁ ପ୍ରତ୍ୟୁତ୍ତର ପଠାଯାଇଛି"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"ନାମ ଉପଲବ୍ଧ ନାହିଁ"</string>
+</resources>
diff --git a/car-messenger-common/res/values-pa/strings.xml b/car-messenger-common/res/values-pa/strings.xml
new file mode 100644
index 0000000..96799b9
--- /dev/null
+++ b/car-messenger-common/res/values-pa/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="one">%d ਨਵਾਂ ਸੁਨੇਹਾ</item>
+ <item quantity="other">%d ਨਵੇਂ ਸੁਨੇਹੇ</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"ਚਲਾਓ"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"ਪੜ੍ਹੇ ਵਜੋਂ ਨਿਸ਼ਾਨਦੇਹੀ ਕਰੋ"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"ਦੁਹਰਾਓ"</string>
+ <string name="action_reply" msgid="564106590567600685">"ਜਵਾਬ ਦਿਓ"</string>
+ <string name="action_stop" msgid="6950369080845695405">"ਬੰਦ ਕਰੋ"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"ਬੰਦ ਕਰੋ"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"ਜਵਾਬ ਭੇਜਿਆ ਨਹੀਂ ਜਾ ਸਕਿਆ। ਕਿਰਪਾ ਕਰਕੇ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"ਜਵਾਬ ਭੇਜਿਆ ਨਹੀਂ ਜਾ ਸਕਿਆ। ਡੀਵਾਈਸ ਕਨੈਕਟ ਨਹੀਂ ਹੈ।"</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s ਕਹਿੰਦਾ ਹੈ"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"ਸੁਨੇਹਾ ਪੜ੍ਹਿਆ ਨਹੀਂ ਜਾ ਸਕਦਾ।"</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"\"%s\""</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"%s ਨੂੰ ਜਵਾਬ ਭੇਜਿਆ ਗਿਆ"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"ਨਾਮ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
+</resources>
diff --git a/car-messenger-common/res/values-pl/strings.xml b/car-messenger-common/res/values-pl/strings.xml
new file mode 100644
index 0000000..b8df4ec
--- /dev/null
+++ b/car-messenger-common/res/values-pl/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="few">%d nowe wiadomości</item>
+ <item quantity="many">%d nowych wiadomości</item>
+ <item quantity="other">%d nowej wiadomości</item>
+ <item quantity="one">Nowa wiadomość</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"Odtwórz"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"Oznacz jako przeczytane"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"Powtórz"</string>
+ <string name="action_reply" msgid="564106590567600685">"Odpowiedz"</string>
+ <string name="action_stop" msgid="6950369080845695405">"Zatrzymaj"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"Zamknij"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"Nie udało się wysłać odpowiedzi. Spróbuj ponownie."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"Nie udało się wysłać odpowiedzi. Urządzenie nie ma połączenia."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s mówi"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"Nie mogę odczytać wiadomości."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"„%s”"</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"Wysłano odpowiedź do: %s"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"Nazwa niedostępna"</string>
+</resources>
diff --git a/car-messenger-common/res/values-pt-rPT/strings.xml b/car-messenger-common/res/values-pt-rPT/strings.xml
new file mode 100644
index 0000000..b0da748
--- /dev/null
+++ b/car-messenger-common/res/values-pt-rPT/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="other">%d novas mensagens</item>
+ <item quantity="one">Nova mensagem</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"Reproduzir"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"Marcar como lida"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"Repetir"</string>
+ <string name="action_reply" msgid="564106590567600685">"Responder"</string>
+ <string name="action_stop" msgid="6950369080845695405">"Parar"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"Fechar"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"Não foi possível enviar a resposta. Tente novamente."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"Não foi possível enviar a resposta. O dispositivo não está ligado."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s diz"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"Não é possível ler a mensagem em voz alta."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"\"%s\""</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"Resposta enviada para %s."</string>
+ <string name="name_not_available" msgid="3800013092212550915">"Nome não disponível."</string>
+</resources>
diff --git a/car-messenger-common/res/values-pt/strings.xml b/car-messenger-common/res/values-pt/strings.xml
new file mode 100644
index 0000000..90d2171
--- /dev/null
+++ b/car-messenger-common/res/values-pt/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="one">%d nova mensagem</item>
+ <item quantity="other">%d novas mensagens</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"Ouvir"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"Marcar como lida"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"Repetir"</string>
+ <string name="action_reply" msgid="564106590567600685">"Responder"</string>
+ <string name="action_stop" msgid="6950369080845695405">"Parar"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"Fechar"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"Não foi possível enviar a resposta. Tente novamente."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"Não foi possível enviar a resposta. Dispositivo não conectado."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s disse"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"Não é possível ler a mensagem em voz alta."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"\"%s\""</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"Resposta enviada para %s"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"Nome indisponível"</string>
+</resources>
diff --git a/car-messenger-common/res/values-ro/strings.xml b/car-messenger-common/res/values-ro/strings.xml
new file mode 100644
index 0000000..87fe506
--- /dev/null
+++ b/car-messenger-common/res/values-ro/strings.xml
@@ -0,0 +1,38 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="few">%d mesaje noi</item>
+ <item quantity="other">%d de mesaje noi</item>
+ <item quantity="one">Mesaj nou</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"Redați"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"Marcați mesajul drept citit"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"Repetați"</string>
+ <string name="action_reply" msgid="564106590567600685">"Răspundeți"</string>
+ <string name="action_stop" msgid="6950369080845695405">"Opriți"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"Închideți"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"Nu se poate trimite răspunsul. Încercați din nou."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"Nu se poate trimite răspunsul. Dispozitivul nu este conectat."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s spune"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"Nu se poate citi mesajul."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"„%s”"</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"Răspuns trimis la %s"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"Numele nu este disponibil"</string>
+</resources>
diff --git a/car-messenger-common/res/values-ru/strings.xml b/car-messenger-common/res/values-ru/strings.xml
new file mode 100644
index 0000000..bfa047d
--- /dev/null
+++ b/car-messenger-common/res/values-ru/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="one">%d новое сообщение</item>
+ <item quantity="few">%d новых сообщения</item>
+ <item quantity="many">%d новых сообщений</item>
+ <item quantity="other">%d новых сообщения</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"Воспроизвести"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"Прочитано"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"Повторить"</string>
+ <string name="action_reply" msgid="564106590567600685">"Ответить"</string>
+ <string name="action_stop" msgid="6950369080845695405">"Остановить"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"Закрыть"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"Не удалось отправить ответ. Повторите попытку."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"Не удалось отправить ответ. Устройство не подключено."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s говорит"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"Не удалось прочитать сообщение."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"\"%s\""</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"Ответ отправлен пользователю %s."</string>
+ <string name="name_not_available" msgid="3800013092212550915">"Имя недоступно"</string>
+</resources>
diff --git a/car-messenger-common/res/values-si/strings.xml b/car-messenger-common/res/values-si/strings.xml
new file mode 100644
index 0000000..fdab619
--- /dev/null
+++ b/car-messenger-common/res/values-si/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="one">නව පණිවුඩ %d ක්</item>
+ <item quantity="other">නව පණිවුඩ %d ක්</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"ධාවනය"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"කියවූ ලෙස ලකුණු කරන්න"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"නැවත කරන්න"</string>
+ <string name="action_reply" msgid="564106590567600685">"පිළිතුරු දෙන්න"</string>
+ <string name="action_stop" msgid="6950369080845695405">"නවත්වන්න"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"වසන්න"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"පිළිතුර යැවිය නොහැක. නැවත උත්සාහ කරන්න."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"පිළිතුර යැවිය නොහැක. උපාංගය සම්බන්ධ කර නැත."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s කියන්නේ"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"පණිවිඩය කියවිය නොහැක."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"\"%s\""</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"පිළිතුර %s වෙත යැවුවා"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"නම නොලැබේ"</string>
+</resources>
diff --git a/car-messenger-common/res/values-sk/strings.xml b/car-messenger-common/res/values-sk/strings.xml
new file mode 100644
index 0000000..7053f2c
--- /dev/null
+++ b/car-messenger-common/res/values-sk/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="few">%d nové správy</item>
+ <item quantity="many">%d new messages</item>
+ <item quantity="other">%d nových správ</item>
+ <item quantity="one">Nová správa</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"Prehrať"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"Označiť ako prečítané"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"Opakovať"</string>
+ <string name="action_reply" msgid="564106590567600685">"Odpovedať"</string>
+ <string name="action_stop" msgid="6950369080845695405">"Zastaviť"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"Zavrieť"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"Odpoveď sa nedá odoslať. Skúste to znova."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"Odpoveď sa nedá odoslať. Zariadenie nie je pripojené."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s hovorí"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"Správu sa nepodarilo prečítať."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"%s"</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"Odpoveď bola odoslaná do systému %s"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"Meno nie je k dispozícii"</string>
+</resources>
diff --git a/car-messenger-common/res/values-sl/strings.xml b/car-messenger-common/res/values-sl/strings.xml
new file mode 100644
index 0000000..8dab1c4
--- /dev/null
+++ b/car-messenger-common/res/values-sl/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="one">%d novo sporočilo</item>
+ <item quantity="two">%d novi sporočili</item>
+ <item quantity="few">%d nova sporočila</item>
+ <item quantity="other">%d novih sporočil</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"Predvajaj"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"Označi kot prebrano"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"Ponovi"</string>
+ <string name="action_reply" msgid="564106590567600685">"Odgovori"</string>
+ <string name="action_stop" msgid="6950369080845695405">"Ustavi"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"Zapri"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"Odgovora ni mogoče poslati. Poskusite znova."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"Odgovora ni mogoče poslati. Naprava ni povezana."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s pravi"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"Sporočila ni mogoče prebrati na glas."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"»%s«"</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"Odgovor poslan osebi %s"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"Ime ni na voljo"</string>
+</resources>
diff --git a/car-messenger-common/res/values-sq/strings.xml b/car-messenger-common/res/values-sq/strings.xml
new file mode 100644
index 0000000..eb33473
--- /dev/null
+++ b/car-messenger-common/res/values-sq/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="other">%d mesazhe të reja</item>
+ <item quantity="one">Mesazh i ri</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"Luaj"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"Shëno si të lexuar"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"Përsërit"</string>
+ <string name="action_reply" msgid="564106590567600685">"Përgjigju"</string>
+ <string name="action_stop" msgid="6950369080845695405">"Ndalo"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"Mbyll"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"Nuk mund të dërgohet. Provo përsëri."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"Nuk mund të dërgohet. Pajisja nuk është e lidhur."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s thotë"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"Mesazhi nuk mund të lexohet me zë."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"\"%s\""</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"Përgjigjja u dërgua te %s"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"Emri nuk ofrohet"</string>
+</resources>
diff --git a/car-messenger-common/res/values-sr/strings.xml b/car-messenger-common/res/values-sr/strings.xml
new file mode 100644
index 0000000..19601c9
--- /dev/null
+++ b/car-messenger-common/res/values-sr/strings.xml
@@ -0,0 +1,38 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="one">%d нова порука</item>
+ <item quantity="few">%d нове поруке</item>
+ <item quantity="other">%d нових порука</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"Пусти"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"Означи као прочитано"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"Понови"</string>
+ <string name="action_reply" msgid="564106590567600685">"Одговори"</string>
+ <string name="action_stop" msgid="6950369080845695405">"Заустави"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"Затвори"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"Слање одговора није успело. Пробајте поново."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"Слање одговора није успело. Уређај није повезан."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s каже"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"Читање поруке наглас није успело."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"„%s“"</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"Одговор је послат контакту %s"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"Име није доступно"</string>
+</resources>
diff --git a/car-messenger-common/res/values-sv/strings.xml b/car-messenger-common/res/values-sv/strings.xml
new file mode 100644
index 0000000..ef6dd39
--- /dev/null
+++ b/car-messenger-common/res/values-sv/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="other">%d nya meddelanden</item>
+ <item quantity="one">Nytt meddelande</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"Spela upp"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"Markera som läst"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"Upprepa"</string>
+ <string name="action_reply" msgid="564106590567600685">"Svara"</string>
+ <string name="action_stop" msgid="6950369080845695405">"Stopp"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"Stäng"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"Det gick inte att skicka svaret. Försök igen."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"Det gick inte att skicka svaret. Enheten är inte ansluten."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s säger"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"Det går inte att läsa upp meddelandet."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"%s"</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"Svaret har skickats till %s"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"Namnet är inte tillgängligt"</string>
+</resources>
diff --git a/car-messenger-common/res/values-sw/strings.xml b/car-messenger-common/res/values-sw/strings.xml
new file mode 100644
index 0000000..4edf7cd
--- /dev/null
+++ b/car-messenger-common/res/values-sw/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="other">Ujumbe %d mpya</item>
+ <item quantity="one">Ujumbe mpya</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"Cheza"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"Tia Alama Kuwa Umesomwa"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"Rudia"</string>
+ <string name="action_reply" msgid="564106590567600685">"Jibu"</string>
+ <string name="action_stop" msgid="6950369080845695405">"Komesha"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"Funga"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"Imeshindwa kutuma jibu. Tafadhali jaribu tena."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"Imeshindwa kutuma jibu. Kifaa hakijaunganishwa."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s anasema"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"Imeshindwa kusoma ujumbe."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"\"%s\""</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"Jibu limetumwa kwa %s"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"Jina halipatikani"</string>
+</resources>
diff --git a/car-messenger-common/res/values-ta/strings.xml b/car-messenger-common/res/values-ta/strings.xml
new file mode 100644
index 0000000..2bd1e27
--- /dev/null
+++ b/car-messenger-common/res/values-ta/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="other">%d புதிய மெசேஜ்கள்</item>
+ <item quantity="one">புதிய மெசேஜ்</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"பிளே செய்"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"படித்ததாகக் குறி"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"மீண்டும்"</string>
+ <string name="action_reply" msgid="564106590567600685">"பதிலளி"</string>
+ <string name="action_stop" msgid="6950369080845695405">"நிறுத்து"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"மூடுக"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"பதிலை அனுப்ப முடியவில்லை. மீண்டும் முயலவும்."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"பதிலை அனுப்ப முடியவில்லை. சாதனம் இணைக்கப்படவில்லை."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s மெசேஜ்"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"மெசேஜைப் படிக்க முடியவில்லை."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"\"%s\""</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"%sக்கு பதில் அனுப்பப்பட்டது"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"பெயர் கிடைக்கவில்லை"</string>
+</resources>
diff --git a/car-messenger-common/res/values-te/strings.xml b/car-messenger-common/res/values-te/strings.xml
new file mode 100644
index 0000000..9dfa1ab
--- /dev/null
+++ b/car-messenger-common/res/values-te/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="other">%d కొత్త సందేశాలు</item>
+ <item quantity="one">కొత్త సందేశం</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"ప్లే చేయి"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"చదివినట్లు గుర్తు పెట్టు"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"పునరావృతం చేయి"</string>
+ <string name="action_reply" msgid="564106590567600685">"ప్రత్యుత్తరమివ్వు"</string>
+ <string name="action_stop" msgid="6950369080845695405">"ఆపివేయి"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"మూసివేయి"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"ప్రత్యుత్తరం పంపడం సాధ్యం కాలేదు. దయచేసి మళ్లీ ప్రయత్నించండి."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"ప్రత్యుత్తరం పంపడం సాధ్యం కాలేదు. పరికరం కనెక్ట్ కాలేదు."</string>
+ <!-- String.format failed for translation -->
+ <!-- no translation found for tts_sender_says (5352698006545359668) -->
+ <skip />
+ <string name="tts_failed_toast" msgid="1483313550894086353">"సందేశాన్ని చదవడం సాధ్యం కాలేదు."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"\"%s\""</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"%s కు ప్రత్యుత్తరం పంపబడింది"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"పేరు అందుబాటులో లేదు"</string>
+</resources>
diff --git a/car-messenger-common/res/values-th/strings.xml b/car-messenger-common/res/values-th/strings.xml
new file mode 100644
index 0000000..b6cfc1e
--- /dev/null
+++ b/car-messenger-common/res/values-th/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="other">ข้อความใหม่ %d ข้อความ</item>
+ <item quantity="one">ข้อความใหม่</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"เล่น"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"ทำเครื่องหมายว่าอ่านแล้ว"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"เล่นซ้ำ"</string>
+ <string name="action_reply" msgid="564106590567600685">"ตอบ"</string>
+ <string name="action_stop" msgid="6950369080845695405">"หยุด"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"ปิด"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"ส่งการตอบกลับไม่ได้ โปรดลองอีกครั้ง"</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"ส่งการตอบกลับไม่ได้ อุปกรณ์ไม่ได้เชื่อมต่ออยู่"</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s บอกว่า"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"อ่านออกเสียงข้อความไม่ได้"</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"\"%s\""</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"ส่งการตอบกลับถึง %s แล้ว"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"ไม่มีชื่อ"</string>
+</resources>
diff --git a/car-messenger-common/res/values-tl/strings.xml b/car-messenger-common/res/values-tl/strings.xml
new file mode 100644
index 0000000..0a09495
--- /dev/null
+++ b/car-messenger-common/res/values-tl/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="one">%d bagong mensahe</item>
+ <item quantity="other">%d na bagong mensahe</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"I-play"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"Markahan Bilang Nabasa Na"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"Ulitin"</string>
+ <string name="action_reply" msgid="564106590567600685">"Sumagot"</string>
+ <string name="action_stop" msgid="6950369080845695405">"Ihinto"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"Isara"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"Hindi maipadala ang sagot. Pakisubukan ulit."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"Hindi maipadala ang sagot. Hindi nakakonekta ang device."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"Sabi ni %s,"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"Hindi mabasa ang mensahe."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"\"%s\""</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"Naipadala ang sagot kay %s"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"Hindi available ang pangalan"</string>
+</resources>
diff --git a/car-messenger-common/res/values-tr/strings.xml b/car-messenger-common/res/values-tr/strings.xml
new file mode 100644
index 0000000..8c8126c
--- /dev/null
+++ b/car-messenger-common/res/values-tr/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="other">%d yeni mesaj</item>
+ <item quantity="one">Yeni mesaj</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"Oynat"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"Okundu Olarak İşaretle"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"Tekrar"</string>
+ <string name="action_reply" msgid="564106590567600685">"Yanıtla"</string>
+ <string name="action_stop" msgid="6950369080845695405">"Durdur"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"Kapat"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"Yanıt gönderilemedi. Lütfen tekrar deneyin."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"Yanıt gönderilemedi. Cihaz bağlı değil."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s diyor ki"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"Mesaj sesli okunamıyor."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"\"%s\""</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"%s adlı kişiye yanıt gönderilemedi"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"Ad gösterilemiyor"</string>
+</resources>
diff --git a/car-messenger-common/res/values-uk/strings.xml b/car-messenger-common/res/values-uk/strings.xml
new file mode 100644
index 0000000..0b46853
--- /dev/null
+++ b/car-messenger-common/res/values-uk/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="one">%d нове повідомлення</item>
+ <item quantity="few">%d нові повідомлення</item>
+ <item quantity="many">%d нових повідомлень</item>
+ <item quantity="other">%d нового повідомлення</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"Відтворити"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"Позначити як прочитане"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"Повторити"</string>
+ <string name="action_reply" msgid="564106590567600685">"Відповісти"</string>
+ <string name="action_stop" msgid="6950369080845695405">"Зупинити"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"Закрити"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"Неможливо надіслати відповідь. Повторіть спробу."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"Неможливо надіслати відповідь. Пристрій не підключено."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"Повідомлення від користувача %s"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"Не вдалося озвучити повідомлення."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"\"%s\""</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"Відповідь, надіслана користувачу %s"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"Назва недоступна"</string>
+</resources>
diff --git a/car-messenger-common/res/values-ur/strings.xml b/car-messenger-common/res/values-ur/strings.xml
new file mode 100644
index 0000000..542b43c
--- /dev/null
+++ b/car-messenger-common/res/values-ur/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="other">%d نئے پیغامات</item>
+ <item quantity="one">نیا پیغام</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"چلائیں"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"پڑھا ہوا کے بطور نشان زد کریں"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"مکرر"</string>
+ <string name="action_reply" msgid="564106590567600685">"جواب دیں"</string>
+ <string name="action_stop" msgid="6950369080845695405">"روکیں"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"بند کریں"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"جواب بھیجنے سے قاصر۔ براہ کرم دوبارہ کوشش کریں۔"</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"جواب بھیجنے سے قاصر۔ آلہ منسلک نہیں ہے۔"</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s کا کہنا ہے"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"پیغام نہیں پڑھا جا سکتا۔"</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"\"%s\""</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"جواب %s پر بھیجا گیا"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"نام دستیاب نہیں ہے"</string>
+</resources>
diff --git a/car-messenger-common/res/values-uz/strings.xml b/car-messenger-common/res/values-uz/strings.xml
new file mode 100644
index 0000000..d886171
--- /dev/null
+++ b/car-messenger-common/res/values-uz/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="other">%d ta yangi xabar</item>
+ <item quantity="one">Yangi xabar</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"Ijro"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"Ochilgan deb belgilash"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"Takrorlash"</string>
+ <string name="action_reply" msgid="564106590567600685">"Javob berish"</string>
+ <string name="action_stop" msgid="6950369080845695405">"Toʻxtatish"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"Yopish"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"Javob yuborilmadi. Qayta urining."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"Javob yuborilmadi. Qurilma ulanmagan."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s dedi"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"Xabar oʻqilmadi."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"“%s”"</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"Javob bunga yuborildi: %s"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"Bu nom mavjud emas"</string>
+</resources>
diff --git a/car-messenger-common/res/values-vi/strings.xml b/car-messenger-common/res/values-vi/strings.xml
new file mode 100644
index 0000000..bc23c3e
--- /dev/null
+++ b/car-messenger-common/res/values-vi/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="other">%d tin nhắn mới</item>
+ <item quantity="one">Tin nhắn mới</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"Phát"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"Đánh dấu là đã đọc"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"Lặp lại"</string>
+ <string name="action_reply" msgid="564106590567600685">"Trả lời"</string>
+ <string name="action_stop" msgid="6950369080845695405">"Dừng"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"Đóng"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"Không gửi được nội dung trả lời. Vui lòng thử lại."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"Không gửi được nội dung trả lời. Thiết bị chưa được kết nối."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s nhắn"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"Không thể đọc to thông báo."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"\"%s\""</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"Đã gửi nội dung trả lời tới %s"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"Không có tên này"</string>
+</resources>
diff --git a/car-messenger-common/res/values-zh-rCN/strings.xml b/car-messenger-common/res/values-zh-rCN/strings.xml
new file mode 100644
index 0000000..97088d9
--- /dev/null
+++ b/car-messenger-common/res/values-zh-rCN/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="other">%d 条新消息</item>
+ <item quantity="one">1 条新消息</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"播放"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"标记为已读"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"重复"</string>
+ <string name="action_reply" msgid="564106590567600685">"回复"</string>
+ <string name="action_stop" msgid="6950369080845695405">"停止"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"关闭"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"无法发送回复。请重试。"</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"无法发送回复。设备未连接。"</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s说"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"无法读出消息。"</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"“%s”"</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"已将回复发送给%s"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"名称不可用"</string>
+</resources>
diff --git a/car-messenger-common/res/values-zh-rHK/strings.xml b/car-messenger-common/res/values-zh-rHK/strings.xml
new file mode 100644
index 0000000..bdc6a72
--- /dev/null
+++ b/car-messenger-common/res/values-zh-rHK/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="other">%d 個新訊息</item>
+ <item quantity="one">新訊息</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"播放"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"標示為已讀"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"重複"</string>
+ <string name="action_reply" msgid="564106590567600685">"回覆"</string>
+ <string name="action_stop" msgid="6950369080845695405">"停止"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"關閉"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"無法傳送回覆,請再試一次。"</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"無法傳送回覆,裝置未連接。"</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"%s話"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"無法讀出訊息。"</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"「%s」"</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"已向%s傳送回覆"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"找不到名稱"</string>
+</resources>
diff --git a/car-messenger-common/res/values-zh-rTW/strings.xml b/car-messenger-common/res/values-zh-rTW/strings.xml
new file mode 100644
index 0000000..a94a58b
--- /dev/null
+++ b/car-messenger-common/res/values-zh-rTW/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="other">%d 則新訊息</item>
+ <item quantity="one">新訊息</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"播放"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"標示為已讀取"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"重複播放"</string>
+ <string name="action_reply" msgid="564106590567600685">"回覆"</string>
+ <string name="action_stop" msgid="6950369080845695405">"停止"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"關閉"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"無法傳送回覆,請再試一次。"</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"尚未與裝置連線,因此無法傳送回覆。"</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"「%s」說:"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"無法朗讀訊息。"</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"「%s」"</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"已將回覆傳送給「%s」"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"無法使用這個名稱"</string>
+</resources>
diff --git a/car-messenger-common/res/values-zu/strings.xml b/car-messenger-common/res/values-zu/strings.xml
new file mode 100644
index 0000000..1292512
--- /dev/null
+++ b/car-messenger-common/res/values-zu/strings.xml
@@ -0,0 +1,37 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="notification_new_message" formatted="false" msgid="1631343923556571689">
+ <item quantity="one">%d imilayezo emisha</item>
+ <item quantity="other">%d imilayezo emisha</item>
+ </plurals>
+ <string name="action_play" msgid="1884580550634079470">"Dlala"</string>
+ <string name="action_mark_as_read" msgid="5185216939940407938">"Maka njengokufundiwe"</string>
+ <string name="action_repeat" msgid="8184323082093728957">"Phinda"</string>
+ <string name="action_reply" msgid="564106590567600685">"Phendula"</string>
+ <string name="action_stop" msgid="6950369080845695405">"Misa"</string>
+ <string name="action_close_messages" msgid="7949295965012770696">"Vala"</string>
+ <string name="auto_reply_failed_message" msgid="6445984971657465627">"Ayikwazi ukuthumela impendulo. Sicela uzame futhi."</string>
+ <string name="auto_reply_device_disconnected" msgid="5861772755278229950">"Ayikwazi ukuthumela impendulo. Idivayisi ayixhunyiwe."</string>
+ <string name="tts_sender_says" msgid="5352698006545359668">"U-%s uthi"</string>
+ <string name="tts_failed_toast" msgid="1483313550894086353">"Ayikwazi ukufundela phezulu umlayezo."</string>
+ <string name="reply_message_display_template" msgid="6348622926232346974">"\"%s\""</string>
+ <string name="message_sent_notice" msgid="7172592196465284673">"Impendulo ithunyelwe ku-%s"</string>
+ <string name="name_not_available" msgid="3800013092212550915">"Igama alitholakali"</string>
+</resources>
diff --git a/car-messenger-common/res/values/dimens.xml b/car-messenger-common/res/values/dimens.xml
new file mode 100644
index 0000000..ea87725
--- /dev/null
+++ b/car-messenger-common/res/values/dimens.xml
@@ -0,0 +1,20 @@
+<?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.
+ -->
+<resources>
+ <dimen name="notification_contact_photo_size">300dp</dimen>
+ <dimen name="contact_avatar_corner_radius_percent" format="float">0.5</dimen>
+</resources>
diff --git a/car-messenger-common/res/values/strings.xml b/car-messenger-common/res/values/strings.xml
new file mode 100644
index 0000000..ff604e2
--- /dev/null
+++ b/car-messenger-common/res/values/strings.xml
@@ -0,0 +1,46 @@
+<?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.
+ -->
+
+<resources>
+ <plurals name="notification_new_message">
+ <item quantity="one">New message</item>
+ <item quantity="other">%d new messages</item>
+ </plurals>
+
+ <string name="action_play">Play</string>
+ <string name="action_mark_as_read">Mark As Read</string>
+ <string name="action_repeat">Repeat</string>
+ <string name="action_reply">Reply</string>
+ <string name="action_stop">Stop</string>
+ <string name="action_close_messages">Close</string>
+ <string name="auto_reply_failed_message">Unable to send reply. Please try again.</string>
+ <string name="auto_reply_device_disconnected">Unable to send reply. Device is not connected.
+ </string>
+
+ <string name="tts_sender_says">%s says</string>
+
+ <string name="tts_failed_toast">Can\'t read out message.</string>
+ <string name="reply_message_display_template">\"%s\"</string>
+ <string name="message_sent_notice">Reply sent to %s</string>
+
+ <!-- Default Sender name that appears in message notification if sender name is not available. [CHAR_LIMIT=NONE] -->
+ <string name="name_not_available">Name not available</string>
+
+ <!-- Formats a group conversation's title for a message notification. The format is: <Sender of last message> mdot <Name of the conversation>.-->
+ <string name="group_conversation_title_separator" translatable="false">%1$s • %2$s</string>
+
+</resources>
diff --git a/car-messenger-common/src/com/android/car/messenger/common/BaseNotificationDelegate.java b/car-messenger-common/src/com/android/car/messenger/common/BaseNotificationDelegate.java
new file mode 100644
index 0000000..dc22ed1
--- /dev/null
+++ b/car-messenger-common/src/com/android/car/messenger/common/BaseNotificationDelegate.java
@@ -0,0 +1,318 @@
+/*
+ * 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.car.messenger.common;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.app.RemoteInput;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.os.Bundle;
+
+import androidx.core.app.NotificationCompat;
+import androidx.core.app.NotificationCompat.Action;
+import androidx.core.app.Person;
+
+import com.android.car.apps.common.LetterTileDrawable;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Predicate;
+
+/**
+ * Base Interface for Message Notification Delegates.
+ * Any Delegate who chooses to extend from this class is responsible for:
+ * <p> device connection logic </p>
+ * <p> sending and receiving messages from the connected devices </p>
+ * <p> creation of {@link ConversationNotificationInfo} and {@link Message} objects </p>
+ * <p> creation of {@link ConversationKey}, {@link MessageKey}, {@link SenderKey} </p>
+ * <p> loading of largeIcons for each Sender per device </p>
+ * <p> Mark-as-Read and Reply functionality </p>
+ **/
+public class BaseNotificationDelegate {
+
+ /** Used to reply to message. */
+ public static final String ACTION_REPLY = "com.android.car.messenger.common.ACTION_REPLY";
+
+ /** Used to clear notification state when user dismisses notification. */
+ public static final String ACTION_DISMISS_NOTIFICATION =
+ "com.android.car.messenger.common.ACTION_DISMISS_NOTIFICATION";
+
+ /** Used to mark a notification as read **/
+ public static final String ACTION_MARK_AS_READ =
+ "com.android.car.messenger.common.ACTION_MARK_AS_READ";
+
+ /* EXTRAS */
+ /** Key under which the {@link SenderKey} is provided. */
+ public static final String EXTRA_CONVERSATION_KEY =
+ "com.android.car.messenger.common.EXTRA_CONVERSATION_KEY";
+
+ /**
+ * The resultKey of the {@link RemoteInput} which is sent in the reply callback {@link
+ * Notification.Action}.
+ */
+ public static final String EXTRA_REMOTE_INPUT_KEY =
+ "com.android.car.messenger.common.REMOTE_INPUT_KEY";
+
+ protected final Context mContext;
+ protected final String mClassName;
+ protected final NotificationManager mNotificationManager;
+
+ /**
+ * Maps a conversation's Notification Metadata to the conversation's unique key.
+ * The extending class should always keep this map updated with the latest new/updated
+ * notification information before calling {@link BaseNotificationDelegate#postNotification(
+ * ConversationKey, ConversationNotificationInfo, String)}.
+ **/
+ protected final Map<ConversationKey, ConversationNotificationInfo> mNotificationInfos =
+ new HashMap<>();
+
+ /**
+ * Maps a conversation's Notification Builder to the conversation's unique key. When the
+ * conversation gets updated, this builder should be retrieved, updated, and reposted.
+ **/
+ private final Map<ConversationKey, NotificationCompat.Builder> mNotificationBuilders =
+ new HashMap<>();
+
+ /**
+ * Maps a message's metadata with the message's unique key.
+ * The extending class should always keep this map updated with the latest message information
+ * before calling {@link BaseNotificationDelegate#postNotification(
+ * ConversationKey, ConversationNotificationInfo, String)}.
+ **/
+ protected final Map<MessageKey, Message> mMessages = new HashMap<>();
+
+ /**
+ * Maps a Bitmap of a sender's Large Icon to the sender's unique key.
+ * The extending class should always keep this map updated with the loaded Sender large icons
+ * before calling {@link BaseNotificationDelegate#postNotification(
+ * ConversationKey, ConversationNotificationInfo, String)}. If the large icon is not found for
+ * the {@link SenderKey} when constructing the notification, a {@link LetterTileDrawable} will
+ * be created for the sender.
+ **/
+ protected final Map<SenderKey, Bitmap> mSenderLargeIcons = new HashMap<>();
+
+ private final int mBitmapSize;
+ private final float mCornerRadiusPercent;
+
+ public BaseNotificationDelegate(Context context, String className) {
+ mContext = context;
+ mClassName = className;
+ mNotificationManager =
+ (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+ mBitmapSize =
+ mContext.getResources()
+ .getDimensionPixelSize(R.dimen.notification_contact_photo_size);
+ mCornerRadiusPercent = mContext.getResources()
+ .getFloat(R.dimen.contact_avatar_corner_radius_percent);
+ }
+
+ /**
+ * Removes all messages related to the inputted predicate, and cancels their notifications.
+ **/
+ public void cleanupMessagesAndNotifications(Predicate<CompositeKey> predicate) {
+ mMessages.entrySet().removeIf(
+ messageKeyMapMessageEntry -> predicate.test(messageKeyMapMessageEntry.getKey()));
+ clearNotifications(predicate);
+ mNotificationInfos.entrySet().removeIf(entry -> predicate.test(entry.getKey()));
+ }
+
+ /**
+ * Clears all notifications matching the predicate. Example method calls are when user
+ * wants to clear (a) message notification(s), or when the Bluetooth device that received the
+ * messages has been disconnected.
+ */
+ public void clearNotifications(Predicate<CompositeKey> predicate) {
+ mNotificationInfos.forEach((conversationKey, notificationInfo) -> {
+ if (predicate.test(conversationKey)) {
+ mNotificationManager.cancel(notificationInfo.getNotificationId());
+ }
+ });
+ }
+
+ /**
+ * Helper method to add {@link Message}s to the {@link ConversationNotificationInfo}. This
+ * should be called when a new message has arrived.
+ **/
+ protected void addMessageToNotificationInfo(Message message, ConversationKey convoKey) {
+ MessageKey messageKey = new MessageKey(message);
+ boolean repeatMessage = mMessages.containsKey(messageKey);
+ mMessages.put(messageKey, message);
+ if (!repeatMessage) {
+ ConversationNotificationInfo notificationInfo = mNotificationInfos.get(convoKey);
+ notificationInfo.mMessageKeys.add(messageKey);
+ }
+ }
+
+ /**
+ * Creates a new notification, or updates an existing notification with the latest messages,
+ * then posts it.
+ * This should be called after the {@link ConversationNotificationInfo} object has been created,
+ * and all of its {@link Message} objects have been linked to it.
+ **/
+ protected void postNotification(ConversationKey conversationKey,
+ ConversationNotificationInfo notificationInfo, String channelId) {
+ boolean newNotification = !mNotificationBuilders.containsKey(conversationKey);
+
+ NotificationCompat.Builder builder = newNotification ? new NotificationCompat.Builder(
+ mContext, channelId) : mNotificationBuilders.get(
+ conversationKey);
+ Message lastMessage = mMessages.get(notificationInfo.mMessageKeys.getLast());
+
+ builder.setContentTitle(notificationInfo.getConvoTitle());
+ builder.setContentText(mContext.getResources().getQuantityString(
+ R.plurals.notification_new_message, notificationInfo.mMessageKeys.size(),
+ notificationInfo.mMessageKeys.size()));
+
+ if (mSenderLargeIcons.containsKey(getSenderKeyFromConversation(conversationKey))) {
+ builder.setLargeIcon(
+ mSenderLargeIcons.get(getSenderKeyFromConversation(conversationKey)));
+ } else {
+ builder.setLargeIcon(Utils.createLetterTile(mContext,
+ Utils.getInitials(lastMessage.getSenderName(), ""),
+ lastMessage.getSenderName(), mBitmapSize, mCornerRadiusPercent));
+ }
+
+ builder.setWhen(lastMessage.getReceiveTime());
+
+ // Create MessagingStyle
+ String userName = (notificationInfo.getUserDisplayName() == null
+ || notificationInfo.getUserDisplayName().isEmpty()) ? mContext.getString(
+ R.string.name_not_available) : notificationInfo.getUserDisplayName();
+ Person user = new Person.Builder()
+ .setName(userName)
+ .build();
+ NotificationCompat.MessagingStyle messagingStyle = new NotificationCompat.MessagingStyle(
+ user);
+ Person sender = new Person.Builder()
+ .setName(lastMessage.getSenderName())
+ .setUri(lastMessage.getSenderContactUri())
+ .build();
+ notificationInfo.mMessageKeys.stream().map(mMessages::get).forEachOrdered(message -> {
+ if (!message.shouldExcludeFromNotification()) {
+ messagingStyle.addMessage(
+ message.getMessageText(),
+ message.getReceiveTime(),
+ sender);
+ }
+ });
+ if (notificationInfo.isGroupConvo()) {
+ messagingStyle.setConversationTitle(
+ mContext.getString(R.string.group_conversation_title_separator,
+ lastMessage.getSenderName(), notificationInfo.getConvoTitle()));
+ }
+
+ // We are creating this notification for the first time.
+ if (newNotification) {
+ builder.setCategory(Notification.CATEGORY_MESSAGE);
+ if (notificationInfo.getAppSmallIconResId() == 0) {
+ builder.setSmallIcon(R.drawable.ic_message);
+ } else {
+ builder.setSmallIcon(notificationInfo.getAppSmallIconResId());
+ }
+
+ builder.setShowWhen(true);
+ messagingStyle.setGroupConversation(notificationInfo.isGroupConvo());
+
+ if (notificationInfo.getAppDisplayName() != null) {
+ Bundle displayName = new Bundle();
+ displayName.putCharSequence(Notification.EXTRA_SUBSTITUTE_APP_NAME,
+ notificationInfo.getAppDisplayName());
+ builder.addExtras(displayName);
+ }
+
+ PendingIntent deleteIntent = createServiceIntent(conversationKey,
+ notificationInfo.getNotificationId(),
+ ACTION_DISMISS_NOTIFICATION);
+ builder.setDeleteIntent(deleteIntent);
+
+ List<Action> actions = buildNotificationActions(conversationKey,
+ notificationInfo.getNotificationId());
+ for (final Action action : actions) {
+ builder.addAction(action);
+ }
+ }
+ builder.setStyle(messagingStyle);
+
+ mNotificationBuilders.put(conversationKey, builder);
+ mNotificationManager.notify(notificationInfo.getNotificationId(), builder.build());
+ }
+
+ /** Can be overridden by any Delegates that have some devices that do not support reply. **/
+ protected boolean shouldAddReplyAction(String deviceAddress) {
+ return true;
+ }
+
+ private List<Action> buildNotificationActions(ConversationKey conversationKey,
+ int notificationId) {
+ final int icon = android.R.drawable.ic_media_play;
+
+ final List<NotificationCompat.Action> actionList = new ArrayList<>();
+
+ // Reply action
+ if (shouldAddReplyAction(conversationKey.getDeviceId())) {
+ final String replyString = mContext.getString(R.string.action_reply);
+ PendingIntent replyIntent = createServiceIntent(conversationKey, notificationId,
+ ACTION_REPLY);
+ actionList.add(
+ new NotificationCompat.Action.Builder(icon, replyString, replyIntent)
+ .setSemanticAction(NotificationCompat.Action.SEMANTIC_ACTION_REPLY)
+ .setShowsUserInterface(false)
+ .addRemoteInput(
+ new androidx.core.app.RemoteInput.Builder(
+ EXTRA_REMOTE_INPUT_KEY)
+ .build()
+ )
+ .build()
+ );
+ }
+
+ // Mark-as-read Action. This will be the callback of Notification Center's "Read" action.
+ final String markAsRead = mContext.getString(R.string.action_mark_as_read);
+ PendingIntent markAsReadIntent = createServiceIntent(conversationKey, notificationId,
+ ACTION_MARK_AS_READ);
+ actionList.add(
+ new NotificationCompat.Action.Builder(icon, markAsRead, markAsReadIntent)
+ .setSemanticAction(NotificationCompat.Action.SEMANTIC_ACTION_MARK_AS_READ)
+ .setShowsUserInterface(false)
+ .build()
+ );
+
+ return actionList;
+ }
+
+ private PendingIntent createServiceIntent(ConversationKey conversationKey, int notificationId,
+ String action) {
+ Intent intent = new Intent(mContext, mContext.getClass())
+ .setAction(action)
+ .setClassName(mContext, mClassName)
+ .putExtra(EXTRA_CONVERSATION_KEY, conversationKey);
+
+ return PendingIntent.getForegroundService(mContext, notificationId, intent,
+ PendingIntent.FLAG_UPDATE_CURRENT);
+ }
+
+ protected SenderKey getSenderKeyFromConversation(ConversationKey conversationKey) {
+ ConversationNotificationInfo info = mNotificationInfos.get(conversationKey);
+ return mMessages.get(info.getLastMessageKey()).getSenderKey();
+ }
+
+}
diff --git a/car-messenger-common/src/com/android/car/messenger/common/CompositeKey.java b/car-messenger-common/src/com/android/car/messenger/common/CompositeKey.java
new file mode 100644
index 0000000..4d8bacd
--- /dev/null
+++ b/car-messenger-common/src/com/android/car/messenger/common/CompositeKey.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 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.car.messenger.common;
+
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * A composite key used for {@link Map} lookups, using two strings for
+ * checking equality and hashing.
+ */
+public abstract class CompositeKey {
+ private final String mDeviceId;
+ private final String mSubKey;
+
+ protected CompositeKey(String deviceId, String subKey) {
+ mDeviceId = deviceId;
+ mSubKey = subKey;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+
+ if (!(o instanceof CompositeKey)) {
+ return false;
+ }
+
+ CompositeKey that = (CompositeKey) o;
+ return Objects.equals(mDeviceId, that.mDeviceId)
+ && Objects.equals(mSubKey, that.mSubKey);
+ }
+
+ /**
+ * Returns true if the device address of this composite key equals {@code deviceId}.
+ *
+ * @param deviceId the device address which is compared to this key's device address
+ * @return true if the device addresses match
+ */
+ public boolean matches(String deviceId) {
+ return mDeviceId.equals(deviceId);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mDeviceId, mSubKey);
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%s, deviceId: %s, subKey: %s",
+ getClass().getSimpleName(), mDeviceId, mSubKey);
+ }
+
+ /** Returns this composite key's device address. */
+ public String getDeviceId() {
+ return mDeviceId;
+ }
+
+ /** Returns this composite key's sub key. */
+ public String getSubKey() {
+ return mSubKey;
+ }
+}
diff --git a/car-messenger-common/src/com/android/car/messenger/common/ConversationKey.java b/car-messenger-common/src/com/android/car/messenger/common/ConversationKey.java
new file mode 100644
index 0000000..1b9b7b9
--- /dev/null
+++ b/car-messenger-common/src/com/android/car/messenger/common/ConversationKey.java
@@ -0,0 +1,57 @@
+/*
+ * 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.car.messenger.common;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * {@link CompositeKey} subclass used to give each conversation on all the connected devices a
+ * unique Key.
+ */
+public class ConversationKey extends CompositeKey implements Parcelable {
+
+ public ConversationKey(String deviceId, String key) {
+ super(deviceId, key);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(getDeviceId());
+ dest.writeString(getSubKey());
+ }
+
+ /** Creates {@link ConversationKey} instances from {@link Parcel} sources. */
+ public static final Parcelable.Creator<ConversationKey> CREATOR =
+ new Parcelable.Creator<ConversationKey>() {
+ @Override
+ public ConversationKey createFromParcel(Parcel source) {
+ return new ConversationKey(source.readString(), source.readString());
+ }
+
+ @Override
+ public ConversationKey[] newArray(int size) {
+ return new ConversationKey[size];
+ }
+ };
+
+}
diff --git a/car-messenger-common/src/com/android/car/messenger/common/ConversationNotificationInfo.java b/car-messenger-common/src/com/android/car/messenger/common/ConversationNotificationInfo.java
new file mode 100644
index 0000000..1354240
--- /dev/null
+++ b/car-messenger-common/src/com/android/car/messenger/common/ConversationNotificationInfo.java
@@ -0,0 +1,178 @@
+/*
+ * 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.car.messenger.common;
+
+import static com.android.car.connecteddevice.util.SafeLog.logw;
+
+import android.annotation.Nullable;
+import android.os.Build;
+import android.util.Log;
+
+import com.android.car.companiondevicesupport.api.external.CompanionDevice;
+import com.android.car.messenger.NotificationMsgProto.NotificationMsg;
+import com.android.car.messenger.NotificationMsgProto.NotificationMsg.ConversationNotification;
+import com.android.car.messenger.NotificationMsgProto.NotificationMsg.MessagingStyle;
+import com.android.car.messenger.NotificationMsgProto.NotificationMsg.PhoneToCarMessage;
+
+import java.util.LinkedList;
+
+/**
+ * Represents a conversation notification's metadata that is shared between the conversation's
+ * messages. Note, each {@link ConversationKey} should map to exactly one
+ * ConversationNotificationInfo object.
+ **/
+public class ConversationNotificationInfo {
+ private static final String TAG = "CMC.ConversationNotificationInfo";
+ private static int sNextNotificationId = 0;
+ final int mNotificationId = sNextNotificationId++;
+
+ private final String mDeviceName;
+ private final String mDeviceId;
+ // This is always the sender name for SMS Messages from Bluetooth MAP.
+ private final String mConvoTitle;
+ private final boolean mIsGroupConvo;
+
+ /** Only used for {@link NotificationMsg} conversations. **/
+ @Nullable
+ private final String mNotificationKey;
+ @Nullable
+ private final String mAppDisplayName;
+ @Nullable
+ private final String mUserDisplayName;
+ private final int mAppSmallIconResId;
+
+ public final LinkedList<MessageKey> mMessageKeys = new LinkedList<>();
+
+ /**
+ * Creates a ConversationNotificationInfo for a {@link NotificationMsg}. Returns {@code null} if
+ * the {@link ConversationNotification} is missing required fields.
+ **/
+ @Nullable
+ public static ConversationNotificationInfo createConversationNotificationInfo(
+ CompanionDevice device,
+ ConversationNotification conversation, String notificationKey) {
+ MessagingStyle messagingStyle = conversation.getMessagingStyle();
+
+ if (!Utils.isValidConversationNotification(conversation, /* isShallowCheck= */ true)) {
+ if (Log.isLoggable(TAG, Log.DEBUG) || Build.IS_DEBUGGABLE) {
+ throw new IllegalArgumentException(
+ "ConversationNotificationInfo is missing required fields");
+ } else {
+ logw(TAG, "ConversationNotificationInfo is missing required fields");
+ return null;
+ }
+ }
+
+ return new ConversationNotificationInfo(device.getDeviceName(), device.getDeviceId(),
+ messagingStyle.getConvoTitle(),
+ messagingStyle.getIsGroupConvo(), notificationKey,
+ conversation.getMessagingAppDisplayName(),
+ messagingStyle.getUserDisplayName(), /* appSmallIconResId= */ 0);
+
+ }
+
+ private ConversationNotificationInfo(@Nullable String deviceName, String deviceId,
+ String convoTitle, boolean isGroupConvo, @Nullable String notificationKey,
+ @Nullable String appDisplayName, @Nullable String userDisplayName,
+ int appSmallIconResId) {
+ boolean missingDeviceId = (deviceId == null);
+ boolean missingTitle = (convoTitle == null);
+ if (missingDeviceId || missingTitle) {
+ StringBuilder builder = new StringBuilder("Missing required fields:");
+ if (missingDeviceId) {
+ builder.append(" deviceId");
+ }
+ if (missingTitle) {
+ builder.append(" convoTitle");
+ }
+ throw new IllegalArgumentException(builder.toString());
+ }
+ this.mDeviceName = deviceName;
+ this.mDeviceId = deviceId;
+ this.mConvoTitle = convoTitle;
+ this.mIsGroupConvo = isGroupConvo;
+ this.mNotificationKey = notificationKey;
+ this.mAppDisplayName = appDisplayName;
+ this.mUserDisplayName = userDisplayName;
+ this.mAppSmallIconResId = appSmallIconResId;
+ }
+
+ /** Returns the id that should be used for this object's {@link android.app.Notification} **/
+ public int getNotificationId() {
+ return mNotificationId;
+ }
+
+ /** Returns the friendly name of the device that received the notification. **/
+ public String getDeviceName() {
+ return mDeviceName;
+ }
+
+ /** Returns the address of the device that received the notification. **/
+ public String getDeviceId() {
+ return mDeviceId;
+ }
+
+ /**
+ * Returns the conversation title of this notification. If this notification came from MAP
+ * profile, the title will be the Sender's name.
+ */
+ public String getConvoTitle() {
+ return mConvoTitle;
+ }
+
+ /** Returns {@code true} if this message is in a group conversation **/
+ public boolean isGroupConvo() {
+ return mIsGroupConvo;
+ }
+
+ /**
+ * Returns the key if this conversation is based on a {@link ConversationNotification}. Refer to
+ * {@link PhoneToCarMessage#getNotificationKey()} for more info.
+ */
+ @Nullable
+ public String getNotificationKey() {
+ return mNotificationKey;
+ }
+
+ /**
+ * Returns the display name of the application that posted this notification if this object is
+ * based on a {@link ConversationNotification}.
+ **/
+ @Nullable
+ public String getAppDisplayName() {
+ return mAppDisplayName;
+ }
+
+ /**
+ * Returns the User Display Name if this object is based on a @link ConversationNotification}.
+ * This is needed for {@link android.app.Notification.MessagingStyle}.
+ */
+ @Nullable
+ public String getUserDisplayName() {
+ return mUserDisplayName;
+ }
+
+
+ /** Returns the icon's resource id of the application that posted this notification. **/
+ public int getAppSmallIconResId() {
+ return mAppSmallIconResId;
+ }
+
+ public MessageKey getLastMessageKey() {
+ return mMessageKeys.getLast();
+ }
+}
diff --git a/car-messenger-common/src/com/android/car/messenger/common/Message.java b/car-messenger-common/src/com/android/car/messenger/common/Message.java
new file mode 100644
index 0000000..e54f477
--- /dev/null
+++ b/car-messenger-common/src/com/android/car/messenger/common/Message.java
@@ -0,0 +1,227 @@
+/*
+ * 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.car.messenger.common;
+
+import static com.android.car.connecteddevice.util.SafeLog.logw;
+
+import android.annotation.Nullable;
+import android.os.Build;
+import android.util.Log;
+
+import com.android.car.messenger.NotificationMsgProto.NotificationMsg;
+import com.android.car.messenger.NotificationMsgProto.NotificationMsg.MessagingStyleMessage;
+
+
+/**
+ * Represents a SMS, MMS, and {@link NotificationMsg}. This object is based
+ * on {@link NotificationMsg}.
+ */
+public class Message {
+ private static final String TAG = "CMC.Message";
+
+ private final String mSenderName;
+ private final String mDeviceId;
+ private final String mMessageText;
+ private final long mReceiveTime;
+ private final boolean mIsReadOnPhone;
+ private boolean mShouldExclude;
+ private final String mHandle;
+ private final MessageType mMessageType;
+ private final SenderKey mSenderKey;
+
+
+ /**
+ * Note: MAP messages from iOS version 12 and earlier, as well as {@link MessagingStyleMessage},
+ * don't provide these.
+ */
+ @Nullable
+ final String mSenderContactUri;
+
+ /**
+ * Describes if the message was received through Bluetooth MAP or is a {@link NotificationMsg}.
+ */
+ public enum MessageType {
+ BLUETOOTH_MAP_MESSAGE, NOTIFICATION_MESSAGE
+ }
+
+ /**
+ * Creates a Message based on {@link MessagingStyleMessage}. Returns {@code null} if the {@link
+ * MessagingStyleMessage} is missing required fields.
+ **/
+ @Nullable
+ public static Message parseFromMessage(String deviceId,
+ MessagingStyleMessage updatedMessage) {
+
+ if (!Utils.isValidMessagingStyleMessage(updatedMessage)) {
+ if (Log.isLoggable(TAG, Log.DEBUG) || Build.IS_DEBUGGABLE) {
+ throw new IllegalArgumentException(
+ "MessagingStyleMessage is missing required fields");
+ } else {
+ logw(TAG, "MessagingStyleMessage is missing required fields");
+ return null;
+ }
+ }
+
+ return new Message(updatedMessage.getSender().getName(),
+ deviceId,
+ updatedMessage.getTextMessage(),
+ updatedMessage.getTimestamp(),
+ updatedMessage.getIsRead(),
+ Utils.createMessageHandle(updatedMessage),
+ MessageType.NOTIFICATION_MESSAGE,
+ /* senderContactUri= */ null);
+ }
+
+ private Message(String senderName, String deviceId, String messageText, long receiveTime,
+ boolean isReadOnPhone, String handle, MessageType messageType,
+ @Nullable String senderContactUri) {
+ boolean missingSenderName = (senderName == null);
+ boolean missingDeviceId = (deviceId == null);
+ boolean missingText = (messageText == null);
+ boolean missingHandle = (handle == null);
+ boolean missingType = (messageType == null);
+ if (missingSenderName || missingDeviceId || missingText || missingHandle || missingType) {
+ StringBuilder builder = new StringBuilder("Missing required fields:");
+ if (missingSenderName) {
+ builder.append(" senderName");
+ }
+ if (missingDeviceId) {
+ builder.append(" deviceId");
+ }
+ if (missingText) {
+ builder.append(" messageText");
+ }
+ if (missingHandle) {
+ builder.append(" handle");
+ }
+ if (missingType) {
+ builder.append(" type");
+ }
+ throw new IllegalArgumentException(builder.toString());
+ }
+ this.mSenderName = senderName;
+ this.mDeviceId = deviceId;
+ this.mMessageText = messageText;
+ this.mReceiveTime = receiveTime;
+ this.mIsReadOnPhone = isReadOnPhone;
+ this.mShouldExclude = false;
+ this.mHandle = handle;
+ this.mMessageType = messageType;
+ this.mSenderContactUri = senderContactUri;
+ this.mSenderKey = new SenderKey(deviceId, senderName, senderContactUri);
+ }
+
+ /**
+ * Returns the contact name as obtained from the device.
+ * If contact is in the device's address-book, this is typically the contact name.
+ * Otherwise it will be the phone number.
+ */
+ public String getSenderName() {
+ return mSenderName;
+ }
+
+ /**
+ * Returns the id of the device from which this message was received.
+ */
+ public String getDeviceId() {
+ return mDeviceId;
+ }
+
+ /**
+ * Returns the actual content of the message.
+ */
+ public String getMessageText() {
+ return mMessageText;
+ }
+
+ /**
+ * Returns the milliseconds since epoch at which this message notification was received on the
+ * head-unit.
+ */
+ public long getReceiveTime() {
+ return mReceiveTime;
+ }
+
+ /**
+ * Whether message should be included in the notification. Messages that have been read aloud on
+ * the car, or that have been dismissed by the user should be excluded from the notification if/
+ * when the notification gets updated. Note: this state will not be propagated to the phone.
+ */
+ public void excludeFromNotification() {
+ mShouldExclude = true;
+ }
+
+ /**
+ * Returns {@code true} if message was read on the phone before it was received on the car.
+ */
+ public boolean isReadOnPhone() {
+ return mIsReadOnPhone;
+ }
+
+ /**
+ * Returns {@code true} if message should not be included in the notification. Messages that
+ * have been read aloud on the car, or that have been dismissed by the user should be excluded
+ * from the notification if/when the notification gets updated.
+ */
+ public boolean shouldExcludeFromNotification() {
+ return mShouldExclude;
+ }
+
+ /**
+ * Returns a unique handle/key for this message. This is used as this Message's
+ * {@link MessageKey#getSubKey()} Note: this handle might only be unique for the lifetime of a
+ * device connection session.
+ */
+ public String getHandle() {
+ return mHandle;
+ }
+
+ /**
+ * Returns the {@link SenderKey} that is unique for each contact per device.
+ */
+ public SenderKey getSenderKey() {
+ return mSenderKey;
+ }
+
+ /** Returns whether the message is a SMS/MMS or a {@link NotificationMsg} **/
+ public MessageType getMessageType() {
+ return mMessageType;
+ }
+
+ /**
+ * Returns the sender's phone number available as a URI string.
+ * Note: MAP messages from iOS version 12 and earlier, as well as {@link MessagingStyleMessage},
+ * don't provide these.
+ */
+ @Nullable
+ public String getSenderContactUri() {
+ return mSenderContactUri;
+ }
+
+ @Override
+ public String toString() {
+ return "Message{"
+ + " mSenderName='" + mSenderName + '\''
+ + ", mMessageText='" + mMessageText + '\''
+ + ", mSenderContactUri='" + mSenderContactUri + '\''
+ + ", mReceiveTime=" + mReceiveTime + '\''
+ + ", mIsReadOnPhone= " + mIsReadOnPhone + '\''
+ + ", mShouldExclude= " + mShouldExclude + '\''
+ + ", mHandle='" + mHandle
+ + "}";
+ }
+}
diff --git a/car-messenger-common/src/com/android/car/messenger/common/MessageKey.java b/car-messenger-common/src/com/android/car/messenger/common/MessageKey.java
new file mode 100644
index 0000000..8244197
--- /dev/null
+++ b/car-messenger-common/src/com/android/car/messenger/common/MessageKey.java
@@ -0,0 +1,29 @@
+/*
+ * 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.car.messenger.common;
+
+/**
+ * {@link CompositeKey} subclass used to give each message on all the connected devices a
+ * unique Key.
+ **/
+public class MessageKey extends CompositeKey {
+
+ /** Creates a MessageKey for a {@link Message}. **/
+ public MessageKey(Message message) {
+ super(message.getDeviceId(), message.getHandle());
+ }
+}
diff --git a/car-messenger-common/src/com/android/car/messenger/common/SenderKey.java b/car-messenger-common/src/com/android/car/messenger/common/SenderKey.java
new file mode 100644
index 0000000..578a612
--- /dev/null
+++ b/car-messenger-common/src/com/android/car/messenger/common/SenderKey.java
@@ -0,0 +1,34 @@
+/*
+ * 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.car.messenger.common;
+
+import com.android.car.messenger.NotificationMsgProto.NotificationMsg;
+
+/**
+ * {@link CompositeKey} subclass used to give each contact on all the connected devices a
+ * unique Key.
+ */
+public class SenderKey extends CompositeKey {
+ /** Creates a senderkey for SMS, MMS, and {@link NotificationMsg}. **/
+ protected SenderKey(String deviceId, String senderName, String contactUri) {
+ // Use a combination of senderName and senderContactUri for key. Ideally we would use
+ // only senderContactUri (which is encoded phone no.). However since some phones don't
+ // provide these, we fall back to senderName. Since senderName may not be unique, we
+ // include senderContactUri also to provide uniqueness in cases it is available.
+ super(deviceId, senderName + "/" + contactUri);
+ }
+}
diff --git a/car-messenger-common/src/com/android/car/messenger/common/Utils.java b/car-messenger-common/src/com/android/car/messenger/common/Utils.java
new file mode 100644
index 0000000..8e0f7a2
--- /dev/null
+++ b/car-messenger-common/src/com/android/car/messenger/common/Utils.java
@@ -0,0 +1,229 @@
+/*
+ * 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.car.messenger.common;
+
+import static com.android.car.connecteddevice.util.SafeLog.logw;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.text.TextUtils;
+
+import androidx.annotation.Nullable;
+import androidx.core.graphics.drawable.RoundedBitmapDrawable;
+import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
+
+import com.android.car.apps.common.LetterTileDrawable;
+import com.android.car.messenger.NotificationMsgProto.NotificationMsg;
+import com.android.car.messenger.NotificationMsgProto.NotificationMsg.ConversationNotification;
+import com.android.car.messenger.NotificationMsgProto.NotificationMsg.MessagingStyle;
+import com.android.car.messenger.NotificationMsgProto.NotificationMsg.MessagingStyleMessage;
+import com.android.car.messenger.NotificationMsgProto.NotificationMsg.Person;
+
+/** Utils methods for the car-messenger-common lib. **/
+public class Utils {
+ private static final String TAG = "CMC.Utils";
+ /**
+ * Represents the maximum length of a message substring to be used when constructing the
+ * message's unique handle/key.
+ */
+ private static final int MAX_SUB_MESSAGE_LENGTH = 5;
+
+ /** Gets the latest message for a {@link NotificationMsg} Conversation. **/
+ public static MessagingStyleMessage getLatestMessage(
+ ConversationNotification notification) {
+ MessagingStyle messagingStyle = notification.getMessagingStyle();
+ long latestTime = 0;
+ MessagingStyleMessage latestMessage = null;
+
+ for (MessagingStyleMessage message : messagingStyle.getMessagingStyleMsgList()) {
+ if (message.getTimestamp() > latestTime) {
+ latestTime = message.getTimestamp();
+ latestMessage = message;
+ }
+ }
+ return latestMessage;
+ }
+
+ /**
+ * Helper method to create a unique handle/key for this message. This is used as this Message's
+ * {@link MessageKey#getSubKey()}.
+ */
+ public static String createMessageHandle(MessagingStyleMessage message) {
+ String textMessage = message.getTextMessage();
+ String subMessage = textMessage.substring(
+ Math.min(MAX_SUB_MESSAGE_LENGTH, textMessage.length()));
+ return message.getTimestamp() + "/" + message.getSender().getName() + "/" + subMessage;
+ }
+
+ /**
+ * Ensure the {@link ConversationNotification} object has all the required fields.
+ *
+ * @param isShallowCheck should be {@code true} if the caller only wants to verify the
+ * notification and its {@link MessagingStyle} is valid, without checking
+ * all of the notification's {@link MessagingStyleMessage}s.
+ **/
+ public static boolean isValidConversationNotification(ConversationNotification notification,
+ boolean isShallowCheck) {
+ if (notification == null) {
+ logw(TAG, "ConversationNotification is null");
+ return false;
+ } else if (!notification.hasMessagingStyle()) {
+ logw(TAG, "ConversationNotification is missing required field: messagingStyle");
+ return false;
+ } else if (notification.getMessagingAppDisplayName() == null) {
+ logw(TAG, "ConversationNotification is missing required field: appDisplayName");
+ return false;
+ } else if (notification.getMessagingAppPackageName() == null) {
+ logw(TAG, "ConversationNotification is missing required field: appPackageName");
+ return false;
+ }
+ return isValidMessagingStyle(notification.getMessagingStyle(), isShallowCheck);
+ }
+
+ /**
+ * Ensure the {@link MessagingStyle} object has all the required fields.
+ **/
+ private static boolean isValidMessagingStyle(MessagingStyle messagingStyle,
+ boolean isShallowCheck) {
+ if (messagingStyle == null) {
+ logw(TAG, "MessagingStyle is null");
+ return false;
+ } else if (messagingStyle.getConvoTitle() == null) {
+ logw(TAG, "MessagingStyle is missing required field: convoTitle");
+ return false;
+ } else if (messagingStyle.getUserDisplayName() == null) {
+ logw(TAG, "MessagingStyle is missing required field: userDisplayName");
+ return false;
+ } else if (messagingStyle.getMessagingStyleMsgCount() == 0) {
+ logw(TAG, "MessagingStyle is missing required field: messagingStyleMsg");
+ return false;
+ }
+ if (!isShallowCheck) {
+ for (MessagingStyleMessage message : messagingStyle.getMessagingStyleMsgList()) {
+ if (!isValidMessagingStyleMessage(message)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Ensure the {@link MessagingStyleMessage} object has all the required fields.
+ **/
+ public static boolean isValidMessagingStyleMessage(MessagingStyleMessage message) {
+ if (message == null) {
+ logw(TAG, "MessagingStyleMessage is null");
+ return false;
+ } else if (message.getTextMessage() == null) {
+ logw(TAG, "MessagingStyleMessage is missing required field: textMessage");
+ return false;
+ } else if (!message.hasSender()) {
+ logw(TAG, "MessagingStyleMessage is missing required field: sender");
+ return false;
+ }
+ return isValidSender(message.getSender());
+ }
+
+ /**
+ * Ensure the {@link Person} object has all the required fields.
+ **/
+ public static boolean isValidSender(Person person) {
+ if (person.getName() == null) {
+ logw(TAG, "Person is missing required field: name");
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Creates a Letter Tile Icon that will display the given initials. If the initials are null,
+ * then an avatar anonymous icon will be drawn.
+ **/
+ public static Bitmap createLetterTile(Context context, @Nullable String initials,
+ String identifier, int avatarSize, float cornerRadiusPercent) {
+ // TODO(b/135446418): use TelecomUtils once car-telephony-common supports bp.
+ LetterTileDrawable letterTileDrawable = createLetterTileDrawable(context, initials,
+ identifier);
+ RoundedBitmapDrawable roundedBitmapDrawable = RoundedBitmapDrawableFactory.create(
+ context.getResources(), letterTileDrawable.toBitmap(avatarSize));
+ return createFromRoundedBitmapDrawable(roundedBitmapDrawable, avatarSize,
+ cornerRadiusPercent);
+ }
+
+ /** Creates an Icon based on the given roundedBitmapDrawable. **/
+ private static Bitmap createFromRoundedBitmapDrawable(
+ RoundedBitmapDrawable roundedBitmapDrawable, int avatarSize,
+ float cornerRadiusPercent) {
+ // TODO(b/135446418): use TelecomUtils once car-telephony-common supports bp.
+ float radius = avatarSize * cornerRadiusPercent;
+ roundedBitmapDrawable.setCornerRadius(radius);
+
+ final Bitmap result = Bitmap.createBitmap(avatarSize, avatarSize,
+ Bitmap.Config.ARGB_8888);
+ final Canvas canvas = new Canvas(result);
+ roundedBitmapDrawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
+ roundedBitmapDrawable.draw(canvas);
+ return roundedBitmapDrawable.getBitmap();
+ }
+
+
+ /**
+ * Create a {@link LetterTileDrawable} for the given initials.
+ *
+ * @param initials is the letters that will be drawn on the canvas. If it is null, then an
+ * avatar anonymous icon will be drawn
+ * @param identifier will decide the color for the drawable. If null, a default color will be
+ * used.
+ */
+ private static LetterTileDrawable createLetterTileDrawable(
+ Context context,
+ @Nullable String initials,
+ @Nullable String identifier) {
+ // TODO(b/135446418): use TelecomUtils once car-telephony-common supports bp.
+ int numberOfLetter = context.getResources().getInteger(
+ R.integer.config_number_of_letters_shown_for_avatar);
+ String letters = initials != null
+ ? initials.substring(0, Math.min(initials.length(), numberOfLetter)) : null;
+ LetterTileDrawable letterTileDrawable = new LetterTileDrawable(context.getResources(),
+ letters, identifier);
+ return letterTileDrawable;
+ }
+
+
+ /**
+ * Returns the initials based on the name and nameAlt.
+ *
+ * @param name should be the display name of a contact.
+ * @param nameAlt should be alternative display name of a contact.
+ */
+ public static String getInitials(String name, String nameAlt) {
+ // TODO(b/135446418): use TelecomUtils once car-telephony-common supports bp.
+ StringBuilder initials = new StringBuilder();
+ if (!TextUtils.isEmpty(name) && Character.isLetter(name.charAt(0))) {
+ initials.append(Character.toUpperCase(name.charAt(0)));
+ }
+ if (!TextUtils.isEmpty(nameAlt)
+ && !TextUtils.equals(name, nameAlt)
+ && Character.isLetter(nameAlt.charAt(0))) {
+ initials.append(Character.toUpperCase(nameAlt.charAt(0)));
+ }
+ return initials.toString();
+ }
+
+}
diff --git a/car-settings-lib/AndroidManifest.xml b/car-settings-lib/AndroidManifest.xml
deleted file mode 100644
index 5c2e6c9..0000000
--- a/car-settings-lib/AndroidManifest.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2018 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.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.car.settingslib">
- <uses-sdk android:minSdkVersion="24"/>
- <application />
-</manifest>
\ No newline at end of file
diff --git a/car-settings-lib/OWNERS b/car-settings-lib/OWNERS
deleted file mode 100644
index e8ed8af..0000000
--- a/car-settings-lib/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# People who can approve changes for submission.
-davidln@google.com
-rogerxue@google.com
-roshanagrawal@google.com
diff --git a/car-settings-lib/README.txt b/car-settings-lib/README.txt
deleted file mode 100644
index 8dcdb8a..0000000
--- a/car-settings-lib/README.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-Library Project for Car settings.
-Intended for sharing related code between Car Settings and CarSetUpWizard.
\ No newline at end of file
diff --git a/car-settings-lib/res/values-af/strings.xml b/car-settings-lib/res/values-af/strings.xml
deleted file mode 100644
index 38a0e1b..0000000
--- a/car-settings-lib/res/values-af/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"Voorgestel"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"Alle tale"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"Veld kan nie leeg wees nie."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"Ingevoerde gebruikernaam is ongeldig."</string>
-</resources>
diff --git a/car-settings-lib/res/values-am/strings.xml b/car-settings-lib/res/values-am/strings.xml
deleted file mode 100644
index 7aec3e0..0000000
--- a/car-settings-lib/res/values-am/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"የተጠቆሙ"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"ሁሉም ቋንቋዎች"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"መስክ ባዶ መሆን አይችልም።"</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"የገባው ተጠቃሚ ስም የማይሠራ ነው።"</string>
-</resources>
diff --git a/car-settings-lib/res/values-ar/strings.xml b/car-settings-lib/res/values-ar/strings.xml
deleted file mode 100644
index 2fb7894..0000000
--- a/car-settings-lib/res/values-ar/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"اللغات المقترحة"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"جميع اللغات"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"يجب عدم ترك الحقل فارغًا."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"اسم المستخدم المُدخل غير صالح."</string>
-</resources>
diff --git a/car-settings-lib/res/values-as/strings.xml b/car-settings-lib/res/values-as/strings.xml
deleted file mode 100644
index 747e8ab..0000000
--- a/car-settings-lib/res/values-as/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"পৰামৰ্শ দিয়া ভাষা"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"সকলো ভাষা"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"এই খালী ঠাই পূৰ নকৰাকৈ এৰিব নোৱাৰি।"</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"আপুনি দিয়া ব্য়ৱহাৰকাৰীৰ নাম মান্য় নহয়।"</string>
-</resources>
diff --git a/car-settings-lib/res/values-az/strings.xml b/car-settings-lib/res/values-az/strings.xml
deleted file mode 100644
index 29f7cfb..0000000
--- a/car-settings-lib/res/values-az/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"Təklif edilmiş"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"Bütün dillər"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"Sahə boş ola bilməz."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"Daxil edilən istifadəçi adı yanlışdır."</string>
-</resources>
diff --git a/car-settings-lib/res/values-b+sr+Latn/strings.xml b/car-settings-lib/res/values-b+sr+Latn/strings.xml
deleted file mode 100644
index c9450b1..0000000
--- a/car-settings-lib/res/values-b+sr+Latn/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"Predloženi"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"Svi jezici"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"Polje ne sme da bude prazno."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"Korisničko ime koje ste uneli je nevažeće."</string>
-</resources>
diff --git a/car-settings-lib/res/values-be/strings.xml b/car-settings-lib/res/values-be/strings.xml
deleted file mode 100644
index 0a55864..0000000
--- a/car-settings-lib/res/values-be/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"Прапанавана"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"Усе мовы"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"Поле не можа быць пустым."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"Уведзена несапраўднае імя карыстальніка"</string>
-</resources>
diff --git a/car-settings-lib/res/values-bg/strings.xml b/car-settings-lib/res/values-bg/strings.xml
deleted file mode 100644
index 7427987..0000000
--- a/car-settings-lib/res/values-bg/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"Предложени"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"Всички езици"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"Полето трябва да се попълни."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"Въведеното потребителско име е невалидно."</string>
-</resources>
diff --git a/car-settings-lib/res/values-bn/strings.xml b/car-settings-lib/res/values-bn/strings.xml
deleted file mode 100644
index 2023f4f..0000000
--- a/car-settings-lib/res/values-bn/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"প্রস্তাবিত"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"সমস্ত ভাষা"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"ক্ষেত্র খালি রাখা যাবে না।"</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"প্রদান করা ব্যবহারকারীর নামটি সঠিক নয়।"</string>
-</resources>
diff --git a/car-settings-lib/res/values-bs/strings.xml b/car-settings-lib/res/values-bs/strings.xml
deleted file mode 100644
index adf86c9..0000000
--- a/car-settings-lib/res/values-bs/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"Predloženo"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"Svi jezici"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"Polje ne može biti prazno."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"Korisničko ime koje ste unijeli je nevažeće."</string>
-</resources>
diff --git a/car-settings-lib/res/values-ca/strings.xml b/car-settings-lib/res/values-ca/strings.xml
deleted file mode 100644
index ee2b958..0000000
--- a/car-settings-lib/res/values-ca/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"Suggerits"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"Tots els idiomes"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"El camp no pot estar en blanc."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"El nom d\'usuari que has introduït no és vàlid."</string>
-</resources>
diff --git a/car-settings-lib/res/values-cs/strings.xml b/car-settings-lib/res/values-cs/strings.xml
deleted file mode 100644
index fca045b..0000000
--- a/car-settings-lib/res/values-cs/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"Navrženo"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"Všechny jazyky"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"Pole nesmí být prázdné."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"Zadané uživatelské jméno není platné."</string>
-</resources>
diff --git a/car-settings-lib/res/values-da/strings.xml b/car-settings-lib/res/values-da/strings.xml
deleted file mode 100644
index 2a585cb..0000000
--- a/car-settings-lib/res/values-da/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"Foreslået"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"Alle sprog"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"Feltet må ikke være tomt."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"Det brugernavn, du har angivet, er ugyldigt."</string>
-</resources>
diff --git a/car-settings-lib/res/values-de/strings.xml b/car-settings-lib/res/values-de/strings.xml
deleted file mode 100644
index a138ce7..0000000
--- a/car-settings-lib/res/values-de/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"Vorgeschlagen"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"Alle Sprachen"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"Das Feld darf nicht leer sein."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"Der eingegebene Nutzername ist ungültig."</string>
-</resources>
diff --git a/car-settings-lib/res/values-el/strings.xml b/car-settings-lib/res/values-el/strings.xml
deleted file mode 100644
index 2496924..0000000
--- a/car-settings-lib/res/values-el/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"Προτεινόμενες"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"Όλες οι γλώσσες"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"Το πεδίο δεν μπορεί να παραμείνει κενό."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"Το όνομα χρήστη που καταχωρίστηκε είναι μη έγκυρο."</string>
-</resources>
diff --git a/car-settings-lib/res/values-en-rAU/strings.xml b/car-settings-lib/res/values-en-rAU/strings.xml
deleted file mode 100644
index 96a64e0..0000000
--- a/car-settings-lib/res/values-en-rAU/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"Suggested"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"All languages"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"Field can\'t be blank."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"Username entered is invalid."</string>
-</resources>
diff --git a/car-settings-lib/res/values-en-rCA/strings.xml b/car-settings-lib/res/values-en-rCA/strings.xml
deleted file mode 100644
index 96a64e0..0000000
--- a/car-settings-lib/res/values-en-rCA/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"Suggested"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"All languages"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"Field can\'t be blank."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"Username entered is invalid."</string>
-</resources>
diff --git a/car-settings-lib/res/values-en-rGB/strings.xml b/car-settings-lib/res/values-en-rGB/strings.xml
deleted file mode 100644
index 96a64e0..0000000
--- a/car-settings-lib/res/values-en-rGB/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"Suggested"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"All languages"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"Field can\'t be blank."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"Username entered is invalid."</string>
-</resources>
diff --git a/car-settings-lib/res/values-en-rIN/strings.xml b/car-settings-lib/res/values-en-rIN/strings.xml
deleted file mode 100644
index 96a64e0..0000000
--- a/car-settings-lib/res/values-en-rIN/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"Suggested"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"All languages"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"Field can\'t be blank."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"Username entered is invalid."</string>
-</resources>
diff --git a/car-settings-lib/res/values-en-rXC/strings.xml b/car-settings-lib/res/values-en-rXC/strings.xml
deleted file mode 100644
index 80192d2..0000000
--- a/car-settings-lib/res/values-en-rXC/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"Suggested"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"All languages"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"Field can’t be blank."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"Username entered is invalid."</string>
-</resources>
diff --git a/car-settings-lib/res/values-es-rUS/strings.xml b/car-settings-lib/res/values-es-rUS/strings.xml
deleted file mode 100644
index 92eff9f..0000000
--- a/car-settings-lib/res/values-es-rUS/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"Sugerencias"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"Todos los idiomas"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"Este campo no puede quedar vacío."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"El nombre de usuario ingresado no es válido."</string>
-</resources>
diff --git a/car-settings-lib/res/values-es/strings.xml b/car-settings-lib/res/values-es/strings.xml
deleted file mode 100644
index 0e70ac6..0000000
--- a/car-settings-lib/res/values-es/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"Sugerencias"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"Todos los idiomas"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"El campo no puede estar vacío."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"El nombre de usuario introducido no es válido."</string>
-</resources>
diff --git a/car-settings-lib/res/values-et/strings.xml b/car-settings-lib/res/values-et/strings.xml
deleted file mode 100644
index 0282368..0000000
--- a/car-settings-lib/res/values-et/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"Soovitatud"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"Kõik keeled"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"Väli ei tohi olla tühi."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"Sisestatud kasutajanimi on sobimatu."</string>
-</resources>
diff --git a/car-settings-lib/res/values-eu/strings.xml b/car-settings-lib/res/values-eu/strings.xml
deleted file mode 100644
index c8c0e10..0000000
--- a/car-settings-lib/res/values-eu/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"Iradokitakoak"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"Hizkuntza guztiak"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"Eremuak ezin du hutsik egon."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"Idatzitako erabiltzaile-izenak ez du balio."</string>
-</resources>
diff --git a/car-settings-lib/res/values-fa/strings.xml b/car-settings-lib/res/values-fa/strings.xml
deleted file mode 100644
index 3ce1002..0000000
--- a/car-settings-lib/res/values-fa/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"پیشنهادشده"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"همه زبانها"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"این فیلد نمیتواند خالی باشد."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"نام کاربری واردشده نامعتبر است."</string>
-</resources>
diff --git a/car-settings-lib/res/values-fi/strings.xml b/car-settings-lib/res/values-fi/strings.xml
deleted file mode 100644
index cb5f2c9..0000000
--- a/car-settings-lib/res/values-fi/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"Ehdotettu"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"Kaikki kielet"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"Kenttä ei voi olla tyhjä."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"Annettu käyttäjänimi on virheellinen."</string>
-</resources>
diff --git a/car-settings-lib/res/values-fr-rCA/strings.xml b/car-settings-lib/res/values-fr-rCA/strings.xml
deleted file mode 100644
index ee93f50..0000000
--- a/car-settings-lib/res/values-fr-rCA/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"Suggestions"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"Toutes les langues"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"Champ obligatoire."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"Le nom d\'utilisateur entré n\'est pas valide."</string>
-</resources>
diff --git a/car-settings-lib/res/values-fr/strings.xml b/car-settings-lib/res/values-fr/strings.xml
deleted file mode 100644
index 250d38a..0000000
--- a/car-settings-lib/res/values-fr/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"Suggestion"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"Toutes les langues"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"Champ obligatoire."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"Le nom d\'utilisateur saisi est incorrect."</string>
-</resources>
diff --git a/car-settings-lib/res/values-gl/strings.xml b/car-settings-lib/res/values-gl/strings.xml
deleted file mode 100644
index e2a772a..0000000
--- a/car-settings-lib/res/values-gl/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"Idiomas suxeridos"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"Todos os idiomas"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"O campo non pode estar en branco."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"O nome de usuario que introduciches non é válido."</string>
-</resources>
diff --git a/car-settings-lib/res/values-gu/strings.xml b/car-settings-lib/res/values-gu/strings.xml
deleted file mode 100644
index 22826c7..0000000
--- a/car-settings-lib/res/values-gu/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"સૂચવેલા"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"બધી ભાષાઓ"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"ફીલ્ડ ખાલી રાખી શકાય નહીં."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"દાખલ કરેલું વપરાશકર્તાનું નામ અમાન્ય છે."</string>
-</resources>
diff --git a/car-settings-lib/res/values-hi/strings.xml b/car-settings-lib/res/values-hi/strings.xml
deleted file mode 100644
index 042be3b..0000000
--- a/car-settings-lib/res/values-hi/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"सुझाए गए"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"सभी भाषाएं"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"नाम लिखने की जगह (फ़ील्ड) खाली नहीं रखी जा सकती."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"डाला गया उपयोगकर्ता नाम गलत है."</string>
-</resources>
diff --git a/car-settings-lib/res/values-hr/strings.xml b/car-settings-lib/res/values-hr/strings.xml
deleted file mode 100644
index c0a69ff..0000000
--- a/car-settings-lib/res/values-hr/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"Predloženo"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"Svi jezici"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"Polje ne može biti prazno."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"Uneseno korisničko ime nije važeće."</string>
-</resources>
diff --git a/car-settings-lib/res/values-hu/strings.xml b/car-settings-lib/res/values-hu/strings.xml
deleted file mode 100644
index 275ea75..0000000
--- a/car-settings-lib/res/values-hu/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"Javasolt"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"Minden nyelv"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"A mező nem lehet üres."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"A megadott felhasználónév érvénytelen."</string>
-</resources>
diff --git a/car-settings-lib/res/values-hy/strings.xml b/car-settings-lib/res/values-hy/strings.xml
deleted file mode 100644
index fcab9c7..0000000
--- a/car-settings-lib/res/values-hy/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"Առաջարկվող"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"Բոլոր լեզուները"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"Դաշտը չի կարող դատարկ լինել:"</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"Մուտքագրված օգտանունն անվավեր է։"</string>
-</resources>
diff --git a/car-settings-lib/res/values-in/strings.xml b/car-settings-lib/res/values-in/strings.xml
deleted file mode 100644
index 51e4d3e..0000000
--- a/car-settings-lib/res/values-in/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"Disarankan"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"Semua bahasa"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"Kolom harus diisi."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"Nama pengguna yang dimasukkan tidak valid."</string>
-</resources>
diff --git a/car-settings-lib/res/values-is/strings.xml b/car-settings-lib/res/values-is/strings.xml
deleted file mode 100644
index 3dffde3..0000000
--- a/car-settings-lib/res/values-is/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"Tillögur"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"Öll tungumál"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"Reiturinn má ekki vera auður."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"Ógilt notandanafn var slegið inn."</string>
-</resources>
diff --git a/car-settings-lib/res/values-it/strings.xml b/car-settings-lib/res/values-it/strings.xml
deleted file mode 100644
index 69e1425..0000000
--- a/car-settings-lib/res/values-it/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"Suggerite"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"Tutte le lingue"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"Il campo non può essere vuoto."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"Il nome utente inserito non è valido."</string>
-</resources>
diff --git a/car-settings-lib/res/values-iw/strings.xml b/car-settings-lib/res/values-iw/strings.xml
deleted file mode 100644
index 180b3e8..0000000
--- a/car-settings-lib/res/values-iw/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"הצעות"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"כל השפות"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"חובה למלא את השדה."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"שם המשתמש שהוזן לא חוקי."</string>
-</resources>
diff --git a/car-settings-lib/res/values-ja/strings.xml b/car-settings-lib/res/values-ja/strings.xml
deleted file mode 100644
index 6374217..0000000
--- a/car-settings-lib/res/values-ja/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"言語の候補"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"すべての言語"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"フィールドは空欄にできません。"</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"入力されたユーザー名が無効です。"</string>
-</resources>
diff --git a/car-settings-lib/res/values-ka/strings.xml b/car-settings-lib/res/values-ka/strings.xml
deleted file mode 100644
index 6f93ba9..0000000
--- a/car-settings-lib/res/values-ka/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"რეკომენდებული"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"ყველა ენა"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"არ შეიძლება ველი ცარიელი იყოს."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"მომხმარებლის სახელი არასწორადაა შეყვანილი."</string>
-</resources>
diff --git a/car-settings-lib/res/values-kk/strings.xml b/car-settings-lib/res/values-kk/strings.xml
deleted file mode 100644
index ebf2013..0000000
--- a/car-settings-lib/res/values-kk/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"Ұсынылған"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"Барлық тілдер"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"Өріс бос болмауы керек."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"Енгізілген пайдаланушы аты жарамсыз."</string>
-</resources>
diff --git a/car-settings-lib/res/values-km/strings.xml b/car-settings-lib/res/values-km/strings.xml
deleted file mode 100644
index 2274c4c..0000000
--- a/car-settings-lib/res/values-km/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"បានណែនាំ"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"ភាសាទាំងអស់"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"កន្លែងបញ្ចូលមិនអាចទទេឡើយ។"</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"ឈ្មោះអ្នកប្រើប្រាស់ដែលបានបញ្ចូលគឺមិនត្រឹមត្រូវទេ។"</string>
-</resources>
diff --git a/car-settings-lib/res/values-kn/strings.xml b/car-settings-lib/res/values-kn/strings.xml
deleted file mode 100644
index c5815cc..0000000
--- a/car-settings-lib/res/values-kn/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"ಸೂಚಿಸಲಾಗಿರುವುದು"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"ಎಲ್ಲಾ ಭಾಷೆಗಳು"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"ಕ್ಷೇತ್ರವು ಖಾಲಿ ಇರುವಂತಿಲ್ಲ."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"ನಮೂದಿಸಿದ ಬಳಕೆದಾರರ ಹೆಸರು ಅಮಾನ್ಯವಾಗಿದೆ."</string>
-</resources>
diff --git a/car-settings-lib/res/values-ko/strings.xml b/car-settings-lib/res/values-ko/strings.xml
deleted file mode 100644
index 1a818d9..0000000
--- a/car-settings-lib/res/values-ko/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"추천"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"모든 언어"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"입력란을 비워 둘 수 없습니다."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"입력한 사용자 이름이 올바르지 않습니다."</string>
-</resources>
diff --git a/car-settings-lib/res/values-ky/strings.xml b/car-settings-lib/res/values-ky/strings.xml
deleted file mode 100644
index 03e5756..0000000
--- a/car-settings-lib/res/values-ky/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"Сунушталган тилдер"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"Бардык тилдер"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"Талаа бош болбошу керек."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"Киргизилген колдонуучунун аты жараксыз."</string>
-</resources>
diff --git a/car-settings-lib/res/values-lo/strings.xml b/car-settings-lib/res/values-lo/strings.xml
deleted file mode 100644
index 439bafa..0000000
--- a/car-settings-lib/res/values-lo/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"ແນະນຳ"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"ທຸກພາສາ"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"ຊ່ອງຂໍ້ມູນບໍ່ສາມາດຫວ່າງເປົ່າໄດ້."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"ຊື່ຜູ້ໃຊ້ທີ່ປ້ອນເຂົ້າບໍ່ຖືກຕ້ອງ."</string>
-</resources>
diff --git a/car-settings-lib/res/values-lt/strings.xml b/car-settings-lib/res/values-lt/strings.xml
deleted file mode 100644
index 3b3f481..0000000
--- a/car-settings-lib/res/values-lt/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"Siūloma"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"Visos kalbos"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"Laukas negali būti tuščias."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"Įvestas naudotojo vardas yra netinkamas."</string>
-</resources>
diff --git a/car-settings-lib/res/values-lv/strings.xml b/car-settings-lib/res/values-lv/strings.xml
deleted file mode 100644
index 856dcf4..0000000
--- a/car-settings-lib/res/values-lv/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"Ieteiktās"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"Visas valodas"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"Lauks nedrīkst būt tukšs."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"Ievadītais lietotājvārds nav derīgs."</string>
-</resources>
diff --git a/car-settings-lib/res/values-mk/strings.xml b/car-settings-lib/res/values-mk/strings.xml
deleted file mode 100644
index f344b18..0000000
--- a/car-settings-lib/res/values-mk/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"Предложени"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"Сите јазици"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"Полето не може да биде празно."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"Внесеното корисничко име е неважечко."</string>
-</resources>
diff --git a/car-settings-lib/res/values-ml/strings.xml b/car-settings-lib/res/values-ml/strings.xml
deleted file mode 100644
index afb887d..0000000
--- a/car-settings-lib/res/values-ml/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"നിര്ദ്ദേശിക്കുന്നവ"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"എല്ലാ ഭാഷകളും"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"ഫീൽഡ് ശൂന്യമായിടരുത്."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"നൽകിയ ഉപയോക്തൃ നാമം അസാധുവാണ്."</string>
-</resources>
diff --git a/car-settings-lib/res/values-mn/strings.xml b/car-settings-lib/res/values-mn/strings.xml
deleted file mode 100644
index d747c7b..0000000
--- a/car-settings-lib/res/values-mn/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"Санал болгосон"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"Бүх хэл"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"Талбар хоосон байж болохгүй."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"Оруулсан хэрэглэгчийн нэр буруу байна."</string>
-</resources>
diff --git a/car-settings-lib/res/values-mr/strings.xml b/car-settings-lib/res/values-mr/strings.xml
deleted file mode 100644
index f915f65..0000000
--- a/car-settings-lib/res/values-mr/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"सूचित"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"सर्व भाषा"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"फील्ड रिकामे असू शकत नाही."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"एंटर केलेले वापरकर्ता नाव चुकीचे आहे."</string>
-</resources>
diff --git a/car-settings-lib/res/values-ms/strings.xml b/car-settings-lib/res/values-ms/strings.xml
deleted file mode 100644
index e67f995..0000000
--- a/car-settings-lib/res/values-ms/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"Dicadangkan"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"Semua bahasa"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"Medan tidak boleh kosong."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"Nama pengguna yang dimasukkan tidak sah."</string>
-</resources>
diff --git a/car-settings-lib/res/values-my/strings.xml b/car-settings-lib/res/values-my/strings.xml
deleted file mode 100644
index dd448fa..0000000
--- a/car-settings-lib/res/values-my/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"အကြံပြုထားသော"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"ဘာသာစကားအားလုံး"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"အကွက်ကို ကွက်လပ်ထား၍ မရပါ။"</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"ထည့်ထားသော အသုံးပြုသူအမည် မမှန်ကန်ပါ။"</string>
-</resources>
diff --git a/car-settings-lib/res/values-nb/strings.xml b/car-settings-lib/res/values-nb/strings.xml
deleted file mode 100644
index 77dc43a..0000000
--- a/car-settings-lib/res/values-nb/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"Foreslått"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"Alle språk"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"Feltet må fylles ut."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"Brukernavnet du skrev inn, er ugyldig."</string>
-</resources>
diff --git a/car-settings-lib/res/values-ne/strings.xml b/car-settings-lib/res/values-ne/strings.xml
deleted file mode 100644
index 6d32ddc..0000000
--- a/car-settings-lib/res/values-ne/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"सुझाव दिइयो"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"सम्पूर्ण भाषाहरू"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"फिल्ड खाली हुन सक्दैन।"</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"प्रविष्ट गरिएको प्रयोगकर्ता नाम अमान्य छ।"</string>
-</resources>
diff --git a/car-settings-lib/res/values-nl/strings.xml b/car-settings-lib/res/values-nl/strings.xml
deleted file mode 100644
index 25f84ef..0000000
--- a/car-settings-lib/res/values-nl/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"Voorgesteld"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"Alle talen"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"Veld mag niet leeg zijn."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"De ingevoerde gebruikersnaam is ongeldig."</string>
-</resources>
diff --git a/car-settings-lib/res/values-or/strings.xml b/car-settings-lib/res/values-or/strings.xml
deleted file mode 100644
index 3690ef6..0000000
--- a/car-settings-lib/res/values-or/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"ପରାମର୍ଶିତ"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"ସମସ୍ତ ଭାଷା"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"ସ୍ଥାନକୁ ଖାଲି ଛାଡ଼ି ହେବନାହିଁ।"</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"ଲେଖାଯାଇଥିବା ଉପଯୋଗକର୍ତ୍ତାନାମଟି ଠିକ୍ ନାହିଁ।"</string>
-</resources>
diff --git a/car-settings-lib/res/values-pa/strings.xml b/car-settings-lib/res/values-pa/strings.xml
deleted file mode 100644
index c501aaf..0000000
--- a/car-settings-lib/res/values-pa/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"ਸੁਝਾਏ ਗਏ"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"ਸਾਰੀਆਂ ਭਾਸ਼ਾਵਾਂ"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"ਖੇਤਰ ਖਾਲੀ ਨਹੀਂ ਛੱਡਿਆ ਜਾ ਸਕਦਾ।"</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"ਦਾਖਲ ਕੀਤਾ ਗਿਆ ਵਰਤੋਂਕਾਰ ਨਾਮ ਅਵੈਧ ਹੈ।"</string>
-</resources>
diff --git a/car-settings-lib/res/values-pl/strings.xml b/car-settings-lib/res/values-pl/strings.xml
deleted file mode 100644
index 00bbad3..0000000
--- a/car-settings-lib/res/values-pl/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"Sugerowane"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"Wszystkie języki"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"Pole nie może być puste."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"Podana nazwa użytkownika jest nieprawidłowa."</string>
-</resources>
diff --git a/car-settings-lib/res/values-pt-rPT/strings.xml b/car-settings-lib/res/values-pt-rPT/strings.xml
deleted file mode 100644
index 7ad6367..0000000
--- a/car-settings-lib/res/values-pt-rPT/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"Sugeridos"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"Todos os idiomas"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"O campo não pode estar em branco."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"O nome de utilizador introduzido é inválido."</string>
-</resources>
diff --git a/car-settings-lib/res/values-pt/strings.xml b/car-settings-lib/res/values-pt/strings.xml
deleted file mode 100644
index ac5fb11..0000000
--- a/car-settings-lib/res/values-pt/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"Sugeridos"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"Todos os idiomas"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"O campo não pode ficar em branco."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"O nome de usuário informado é inválido."</string>
-</resources>
diff --git a/car-settings-lib/res/values-ro/strings.xml b/car-settings-lib/res/values-ro/strings.xml
deleted file mode 100644
index b79ede1..0000000
--- a/car-settings-lib/res/values-ro/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"Sugerate"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"Toate limbile"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"Câmpul trebuie completat."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"Numele de utilizator introdus este nevalid."</string>
-</resources>
diff --git a/car-settings-lib/res/values-ru/strings.xml b/car-settings-lib/res/values-ru/strings.xml
deleted file mode 100644
index d5f064c..0000000
--- a/car-settings-lib/res/values-ru/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"Рекомендуемые"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"Все языки"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"Поле должно быть заполнено."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"Указано недопустимое имя пользователя."</string>
-</resources>
diff --git a/car-settings-lib/res/values-si/strings.xml b/car-settings-lib/res/values-si/strings.xml
deleted file mode 100644
index 79e83f7..0000000
--- a/car-settings-lib/res/values-si/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"යෝජිත"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"සියලු භාෂා"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"ක්ෂේත්රය හිස් විය නොහැක."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"ඇතුළු කළ පරිශීලක නාමය අවලංගුය."</string>
-</resources>
diff --git a/car-settings-lib/res/values-sk/strings.xml b/car-settings-lib/res/values-sk/strings.xml
deleted file mode 100644
index 7bf3819..0000000
--- a/car-settings-lib/res/values-sk/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"Navrhované"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"Všetky jazyky"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"Pole nesmie byť prázdne."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"Zadané používateľské meno je neplatné."</string>
-</resources>
diff --git a/car-settings-lib/res/values-sl/strings.xml b/car-settings-lib/res/values-sl/strings.xml
deleted file mode 100644
index 5f46458..0000000
--- a/car-settings-lib/res/values-sl/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"Predlagano"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"Vsi jeziki"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"Polje ne sme biti prazno."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"Vneseno uporabniško ime ni veljavno."</string>
-</resources>
diff --git a/car-settings-lib/res/values-sq/strings.xml b/car-settings-lib/res/values-sq/strings.xml
deleted file mode 100644
index 18cbe0f..0000000
--- a/car-settings-lib/res/values-sq/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"Sugjeruar"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"Të gjitha gjuhët"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"Fusha nuk mund të lihet bosh."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"Emri i përdoruesit që fute është i pavlefshëm."</string>
-</resources>
diff --git a/car-settings-lib/res/values-sr/strings.xml b/car-settings-lib/res/values-sr/strings.xml
deleted file mode 100644
index 46b5008..0000000
--- a/car-settings-lib/res/values-sr/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"Предложени"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"Сви језици"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"Поље не сме да буде празно."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"Корисничко име које сте унели је неважеће."</string>
-</resources>
diff --git a/car-settings-lib/res/values-sv/strings.xml b/car-settings-lib/res/values-sv/strings.xml
deleted file mode 100644
index d9e2309..0000000
--- a/car-settings-lib/res/values-sv/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"Förslag"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"Alla språk"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"Fältet får inte vara tomt."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"Du har angett ett ogiltigt användarnamn."</string>
-</resources>
diff --git a/car-settings-lib/res/values-sw/strings.xml b/car-settings-lib/res/values-sw/strings.xml
deleted file mode 100644
index dbe4958..0000000
--- a/car-settings-lib/res/values-sw/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"Zinazopendekezwa"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"Lugha zote"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"Ni lazima ujaze sehemu hii"</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"Jina uliloweka la mtumiaji si sahihi."</string>
-</resources>
diff --git a/car-settings-lib/res/values-ta/strings.xml b/car-settings-lib/res/values-ta/strings.xml
deleted file mode 100644
index e21d564..0000000
--- a/car-settings-lib/res/values-ta/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"பரிந்துரைகள்"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"எல்லா மொழிகளும்"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"புலம், வெறுமையாக இருக்கக்கூடாது."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"பயனர்பெயரைத் தவறாக உள்ளிட்டுள்ளீர்கள்."</string>
-</resources>
diff --git a/car-settings-lib/res/values-te/strings.xml b/car-settings-lib/res/values-te/strings.xml
deleted file mode 100644
index 38b470d..0000000
--- a/car-settings-lib/res/values-te/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"సూచించినవి"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"అన్ని భాషలు"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"ఫీల్డ్ ఖాళీగా ఉండరాదు."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"నమోదు చేసిన వినియోగదారు పేరు చెల్లదు."</string>
-</resources>
diff --git a/car-settings-lib/res/values-th/strings.xml b/car-settings-lib/res/values-th/strings.xml
deleted file mode 100644
index 10ac43a..0000000
--- a/car-settings-lib/res/values-th/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"แนะนำ"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"ทุกภาษา"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"ต้องกรอกข้อมูลในช่อง"</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"ชื่อผู้ใช้ที่ป้อนไม่ถูกต้อง"</string>
-</resources>
diff --git a/car-settings-lib/res/values-tl/strings.xml b/car-settings-lib/res/values-tl/strings.xml
deleted file mode 100644
index 852721f..0000000
--- a/car-settings-lib/res/values-tl/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"Iminumungkahi"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"Lahat ng wika"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"Hindi maaaring blangko ang field."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"Invalid ang inilagay na username."</string>
-</resources>
diff --git a/car-settings-lib/res/values-tr/strings.xml b/car-settings-lib/res/values-tr/strings.xml
deleted file mode 100644
index bb7499e..0000000
--- a/car-settings-lib/res/values-tr/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"Önerilen"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"Tüm diller"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"Alan boş olamaz."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"Girilen kullanıcı adı geçersiz."</string>
-</resources>
diff --git a/car-settings-lib/res/values-uk/strings.xml b/car-settings-lib/res/values-uk/strings.xml
deleted file mode 100644
index 4429605..0000000
--- a/car-settings-lib/res/values-uk/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"Пропонується"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"Усі мови"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"Поле не може бути порожнім."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"Введене ім’я користувача недійсне."</string>
-</resources>
diff --git a/car-settings-lib/res/values-ur/strings.xml b/car-settings-lib/res/values-ur/strings.xml
deleted file mode 100644
index 64f8d4a..0000000
--- a/car-settings-lib/res/values-ur/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"تجویز کردہ"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"سبھی زبانیں"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"فیلڈ خالی نہیں رہ سکتی۔"</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"درج کردہ صارف نام غلط ہے۔"</string>
-</resources>
diff --git a/car-settings-lib/res/values-uz/strings.xml b/car-settings-lib/res/values-uz/strings.xml
deleted file mode 100644
index 1947548..0000000
--- a/car-settings-lib/res/values-uz/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"Taklif qilingan"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"Barcha tillar"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"Maydon bo‘sh qoldirilishi mumkin emas."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"Kiritilgan foydalanuvchi nomi xato."</string>
-</resources>
diff --git a/car-settings-lib/res/values-vi/strings.xml b/car-settings-lib/res/values-vi/strings.xml
deleted file mode 100644
index 6dbc7d7..0000000
--- a/car-settings-lib/res/values-vi/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"Ðược đề xuất"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"Tất cả ngôn ngữ"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"Không được để trống trường."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"Tên người dùng đã nhập là không hợp lệ."</string>
-</resources>
diff --git a/car-settings-lib/res/values-zh-rCN/strings.xml b/car-settings-lib/res/values-zh-rCN/strings.xml
deleted file mode 100644
index f9462c5..0000000
--- a/car-settings-lib/res/values-zh-rCN/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"建议"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"所有语言"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"此字段不能留空。"</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"输入的用户名无效。"</string>
-</resources>
diff --git a/car-settings-lib/res/values-zh-rHK/strings.xml b/car-settings-lib/res/values-zh-rHK/strings.xml
deleted file mode 100644
index 8c5d191..0000000
--- a/car-settings-lib/res/values-zh-rHK/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"建議"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"所有語言"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"欄位不得留空。"</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"輸入的使用者名稱無效。"</string>
-</resources>
diff --git a/car-settings-lib/res/values-zh-rTW/strings.xml b/car-settings-lib/res/values-zh-rTW/strings.xml
deleted file mode 100644
index 8e9c84a..0000000
--- a/car-settings-lib/res/values-zh-rTW/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"建議"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"所有語言"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"欄位不能空白。"</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"輸入的使用者名稱無效。"</string>
-</resources>
diff --git a/car-settings-lib/res/values-zu/strings.xml b/car-settings-lib/res/values-zu/strings.xml
deleted file mode 100644
index 2e55b3f..0000000
--- a/car-settings-lib/res/values-zu/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="language_picker_list_suggested_header" msgid="8931437200168779395">"Okuphakanyisiwe"</string>
- <string name="language_picker_list_all_header" msgid="3907663373765943630">"Zonke izilimi"</string>
- <string name="name_input_blank_error" msgid="5460631644831377461">"Inkundla ayikwazi ukungabi nalutho."</string>
- <string name="name_input_invalid_error" msgid="8735081597199782922">"Igama lomsebenzisi elifakiwe alivumelekile."</string>
-</resources>
diff --git a/car-settings-lib/res/values/strings.xml b/car-settings-lib/res/values/strings.xml
deleted file mode 100644
index c9f76e7..0000000
--- a/car-settings-lib/res/values/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 Google Inc.
-
- 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.
--->
-<resources>
-
- <!-- Language picker list suggested locale header [CHAR LIMIT=40] -->
- <string name="language_picker_list_suggested_header">Suggested</string>
-
- <!-- Language picker list all other locales header [CHAR LIMIT=40] -->
- <string name="language_picker_list_all_header">All languages</string>
-
- <!-- An error message indicating that the name input field has been left blank and cannot be. [CHAR_LIMIT=50] -->
- <string name="name_input_blank_error">Field can\u2019t be blank.</string>
-
- <!-- An error message indicating that the name the user has entered is invalid. [CHAR_LIMIT=50] -->
- <string name="name_input_invalid_error">Username entered is invalid.</string>
-
-</resources>
\ No newline at end of file
diff --git a/car-settings-lib/src/com/android/car/settingslib/language/LanguagePickerUtils.java b/car-settings-lib/src/com/android/car/settingslib/language/LanguagePickerUtils.java
deleted file mode 100644
index ef5dc46..0000000
--- a/car-settings-lib/src/com/android/car/settingslib/language/LanguagePickerUtils.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2018 Google Inc.
- *
- * 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.settingslib.language;
-
-import android.app.ActivityManager;
-import android.content.Context;
-import android.os.RemoteException;
-
-import androidx.annotation.Nullable;
-
-import com.android.internal.app.LocaleHelper;
-import com.android.internal.app.LocaleStore;
-import com.android.internal.app.SuggestedLocaleAdapter;
-
-import java.util.Locale;
-import java.util.Set;
-
-/**
- * Utility class that supports the language/locale picker flows.
- */
-public final class LanguagePickerUtils {
- /**
- * Creates an instance of {@link SuggestedLocaleAdapter} with a locale
- * {@link LocaleStore.LocaleInfo} that is scoped to a parent locale if a parent locale is
- * provided.
- */
- public static SuggestedLocaleAdapter createSuggestedLocaleAdapter(
- Context context,
- Set<LocaleStore.LocaleInfo> localeInfoSet,
- @Nullable LocaleStore.LocaleInfo parent) {
- boolean countryMode = (parent != null);
- Locale displayLocale = countryMode ? parent.getLocale() : Locale.getDefault();
- SuggestedLocaleAdapter adapter = new SuggestedLocaleAdapter(localeInfoSet, countryMode);
- LocaleHelper.LocaleInfoComparator comp =
- new LocaleHelper.LocaleInfoComparator(displayLocale, countryMode);
- adapter.sort(comp);
- adapter.setDisplayLocale(context, displayLocale);
- return adapter;
- }
-
- /**
- * Returns the locale from current system configuration, or the default locale if no system
- * locale is available.
- */
- public static Locale getConfiguredLocale() {
- try {
- Locale configLocale =
- ActivityManager.getService().getConfiguration().getLocales().get(0);
- return configLocale != null ? configLocale : Locale.getDefault();
- } catch (RemoteException e) {
- return Locale.getDefault();
- }
- }
-
- private LanguagePickerUtils() {}
-}
diff --git a/car-settings-lib/src/com/android/car/settingslib/language/LocaleSelectionListener.java b/car-settings-lib/src/com/android/car/settingslib/language/LocaleSelectionListener.java
deleted file mode 100644
index 2541bf8..0000000
--- a/car-settings-lib/src/com/android/car/settingslib/language/LocaleSelectionListener.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2018 Google Inc.
- *
- * 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.settingslib.language;
-
-import com.android.internal.app.LocaleStore;
-
-/**
- * Listener interface that facilitates notification of changes is locale selection.
- */
-public interface LocaleSelectionListener {
- /**
- * Called when a language choice has been selected.
- */
- void onLocaleSelected(LocaleStore.LocaleInfo localeInfo);
-
- /**
- * Called when a parent locale that has at least 2 child locales is selected. The
- * expectation here is what the PagedList in the LanguagePickerFragment will be updated to
- * display the child locales.
- */
- void onParentWithChildrenLocaleSelected(LocaleStore.LocaleInfo localeInfo);
-}
diff --git a/car-settings-lib/src/com/android/car/settingslib/loader/AsyncLoader.java b/car-settings-lib/src/com/android/car/settingslib/loader/AsyncLoader.java
deleted file mode 100644
index d706c3a..0000000
--- a/car-settings-lib/src/com/android/car/settingslib/loader/AsyncLoader.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2018 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.settingslib.loader;
-
-import android.annotation.Nullable;
-import android.content.Context;
-
-import androidx.loader.content.AsyncTaskLoader;
-
-/**
- * This class fills in some boilerplate for AsyncTaskLoader to actually load things.
- * Classes the extend {@link AsyncLoader} need to properly implement required methods expressed in
- * {@link AsyncTaskLoader}
- *
- * <p>Taken from {@link com.android.settingslib.utils.AsyncLoader}. Only change to extend from
- * support library {@link AsyncTaskLoader}
- *
- * @param <T> the data type to be loaded.
- */
-public abstract class AsyncLoader<T> extends AsyncTaskLoader<T> {
- @Nullable
- private T mResult;
-
- public AsyncLoader(Context context) {
- super(context);
- }
-
- @Override
- protected void onStartLoading() {
- if (mResult != null) {
- deliverResult(mResult);
- }
-
- if (takeContentChanged() || mResult == null) {
- forceLoad();
- }
- }
-
- @Override
- protected void onStopLoading() {
- cancelLoad();
- }
-
- @Override
- public void deliverResult(T data) {
- if (isReset()) {
- return;
- }
- mResult = data;
- if (isStarted()) {
- super.deliverResult(data);
- }
- }
-
- @Override
- protected void onReset() {
- super.onReset();
- onStopLoading();
- mResult = null;
- }
-}
diff --git a/car-settings-lib/src/com/android/car/settingslib/log/LoggerBase.java b/car-settings-lib/src/com/android/car/settingslib/log/LoggerBase.java
deleted file mode 100644
index 2d59899..0000000
--- a/car-settings-lib/src/com/android/car/settingslib/log/LoggerBase.java
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * Copyright (C) 2018 Google Inc.
- *
- * 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.settingslib.log;
-
-import android.text.TextUtils;
-import android.util.Log;
-
-import androidx.annotation.NonNull;
-
-/**
- * Helper class that wraps {@link Log} to log messages to logcat. The intended use for a Logger is
- * to include one per file, using the class.getSimpleName as the prefix, like this:
- * <pre> private static final Logger LOG = new Logger(MyClass.class); </pre>
- *
- * <p>
- * The logger will log statements in this format:
- * mTag: [PREFIX] MESSAGE
- *
- * <p>
- * Where mTag is defined by the subclass. This helps differentiate logs while staying within the
- * 23 character limit of the log mTag.
- *
- * <p>
- * When logging verbose and debug logs, the logs should either be guarded by {@code if (LOG.isV())},
- * or a constant if (DEBUG). That DEBUG constant should be false on any submitted code.
- */
-public abstract class LoggerBase {
- private final String mTag;
- private final String mPrefix;
-
- public LoggerBase(Class<?> cls) {
- this(cls.getSimpleName());
- }
-
- public LoggerBase(String prefix) {
- mTag = getTag();
- if (TextUtils.isEmpty(mTag)) {
- throw new IllegalStateException("Tag must be not null or empty");
- }
- if (mTag.length() > 23) {
- throw new IllegalStateException("Tag must be 23 characters or less");
- }
- mPrefix = "[" + prefix + "] ";
- }
-
- /**
- * Gets the tag that will be used in all logging calls.
- */
- @NonNull
- protected abstract String getTag();
-
- /**
- * Returns true when it is desired to force log all messages.
- */
- protected boolean forceAllLogging() {
- return false;
- }
-
- /**
- * Logs a {@link Log#VERBOSE} log message. Will only be logged if {@link Log#VERBOSE} is
- * loggable. This is a wrapper around {@link Log#v(String, String)}.
- *
- * @param message The message you would like logged.
- */
- public void v(String message) {
- if (isV()) {
- Log.v(mTag, mPrefix.concat(message));
- }
- }
-
- /**
- * Logs a {@link Log#VERBOSE} log message. Will only be logged if {@link Log#VERBOSE} is
- * loggable. This is a wrapper around {@link Log#v(String, String, Throwable)}.
- *
- * @param message The message you would like logged.
- * @param throwable An exception to log
- */
- public void v(String message, Throwable throwable) {
- if (isV()) {
- Log.v(mTag, mPrefix.concat(message), throwable);
- }
- }
-
- /**
- * Logs a {@link Log#DEBUG} log message. Will only be logged if {@link Log#DEBUG} is
- * loggable. This is a wrapper around {@link Log#d(String, String)}.
- *
- * @param message The message you would like logged.
- */
- public void d(String message) {
- if (isD()) {
- Log.d(mTag, mPrefix.concat(message));
- }
- }
-
- /**
- * Logs a {@link Log#DEBUG} log message. Will only be logged if {@link Log#DEBUG} is
- * loggable. This is a wrapper around {@link Log#d(String, String, Throwable)}.
- *
- * @param message The message you would like logged.
- * @param throwable An exception to log
- */
- public void d(String message, Throwable throwable) {
- if (isD()) {
- Log.d(mTag, mPrefix.concat(message), throwable);
- }
- }
-
- /**
- * Logs a {@link Log#INFO} log message. Will only be logged if {@link Log#INFO} is loggable.
- * This is a wrapper around {@link Log#i(String, String)}.
- *
- * @param message The message you would like logged.
- */
- public void i(String message) {
- if (isI()) {
- Log.i(mTag, mPrefix.concat(message));
- }
- }
-
- /**
- * Logs a {@link Log#INFO} log message. Will only be logged if {@link Log#INFO} is loggable.
- * This is a wrapper around {@link Log#i(String, String, Throwable)}.
- *
- * @param message The message you would like logged.
- * @param throwable An exception to log
- */
- public void i(String message, Throwable throwable) {
- if (isI()) {
- Log.i(mTag, mPrefix.concat(message), throwable);
- }
- }
-
- /**
- * Logs a {@link Log#WARN} log message. This is a wrapper around {@link Log#w(String, String)}.
- *
- * @param message The message you would like logged.
- */
- public void w(String message) {
- Log.w(mTag, mPrefix.concat(message));
- }
-
- /**
- * Logs a {@link Log#WARN} log message. This is a wrapper around
- * {@link Log#w(String, String, Throwable)}.
- *
- * @param message The message you would like logged.
- * @param throwable An exception to log
- */
- public void w(String message, Throwable throwable) {
- Log.w(mTag, mPrefix.concat(message), throwable);
- }
-
- /**
- * Logs a {@link Log#ERROR} log message. This is a wrapper around {@link Log#e(String, String)}.
- *
- * @param message The message you would like logged.
- */
- public void e(String message) {
- Log.e(mTag, mPrefix.concat(message));
- }
-
- /**
- * Logs a {@link Log#ERROR} log message. This is a wrapper around
- * {@link Log#e(String, String, Throwable)}.
- *
- * @param message The message you would like logged.
- * @param throwable An exception to log
- */
- public void e(String message, Throwable throwable) {
- Log.e(mTag, mPrefix.concat(message), throwable);
- }
-
- /**
- * Logs a "What a Terrible Failure" as an {@link Log#ASSERT} log message. This is a wrapper
- * around {@link Log#w(String, String)}.
- *
- * @param message The message you would like logged.
- */
- public void wtf(String message) {
- Log.wtf(mTag, mPrefix.concat(message));
- }
-
- /**
- * Logs a "What a Terrible Failure" as an {@link Log#ASSERT} log message. This is a wrapper
- * around {@link Log#wtf(String, String, Throwable)}.
- *
- * @param message The message you would like logged.
- * @param throwable An exception to log
- */
- public void wtf(String message, Throwable throwable) {
- Log.wtf(mTag, mPrefix.concat(message), throwable);
- }
-
- private boolean isV() {
- return Log.isLoggable(mTag, Log.VERBOSE) || forceAllLogging();
- }
-
- private boolean isD() {
- return Log.isLoggable(mTag, Log.DEBUG) || forceAllLogging();
- }
-
- private boolean isI() {
- return Log.isLoggable(mTag, Log.INFO) || forceAllLogging();
- }
-}
diff --git a/car-settings-lib/src/com/android/car/settingslib/util/ProfileNameSaver.java b/car-settings-lib/src/com/android/car/settingslib/util/ProfileNameSaver.java
deleted file mode 100644
index 8f7067c..0000000
--- a/car-settings-lib/src/com/android/car/settingslib/util/ProfileNameSaver.java
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (C) 2018 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.settingslib.util;
-
-import android.content.ContentResolver;
-import android.content.ContentUris;
-import android.content.ContentValues;
-import android.database.Cursor;
-import android.net.Uri;
-import android.provider.ContactsContract;
-import android.text.TextUtils;
-import android.util.Log;
-
-/**
- * Saves name as GIVEN_NAME on "Me" Profile. If "Me" contact does not exist, it's created.
- */
-public class ProfileNameSaver {
- private static final String TAG = "ProfileNameSaver";
- private static final Uri PROFILE_URI = ContactsContract.Profile.CONTENT_RAW_CONTACTS_URI;
- private static final int INVALID_ID = -1;
-
- /**
- * The projection into the profiles database that retrieves just the id of a profile.
- */
- private static final String[] CONTACTS_PROJECTION =
- new String[]{ContactsContract.RawContacts._ID};
-
- /**
- * A projection into the profile data for one particular contact that includes the
- * contact's MIME type.
- */
- private static final String[] CONTACTS_PROFILE_PROJECTION = new String[]{
- ContactsContract.Data._ID,
- ContactsContract.Data.MIMETYPE};
-
- /**
- * A selection into the profiles database that queries for a MIME type.
- */
- private static final String CONTACT_MIME_QUERY = ContactsContract.Data.MIMETYPE + " = ?";
-
- /**
- * Updates the "Me" contact profile card with the given name as the first name of the
- * contact. If the "Me" contact does not exist, then one will be created.
- *
- * @param name The first name for the "Me" contact. If this value is {@code null} or
- * empty, then the contact will not be updated.
- */
- public static void updateMeContactWith(String name, ContentResolver contentResolver) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "updateMeContactWith name=" + name);
- }
-
- if (TextUtils.isEmpty(name)) {
- return;
- }
-
- // Check if there is already an existing "me" contact.
- Cursor cursor = contentResolver.query(
- PROFILE_URI,
- CONTACTS_PROJECTION,
- /* selection= */ null,
- /* selectionArgs= */ null,
- /* sortOrder= */ null);
-
- if (cursor == null) {
- // Error in querying the content resolver, skip the update flow
- Log.e(TAG, "Received null from query to the \"me\" contact at " + PROFILE_URI);
- return;
- }
-
- long meRawContactId = -1; // no ID can be < 0
- boolean newContact = true;
- try {
- if (cursor.moveToFirst()) {
- meRawContactId = cursor.getLong(0);
- newContact = false; // An entry indicates that the "me" contact exists.
- }
- } finally {
- cursor.close();
- }
-
- ContentValues values = new ContentValues();
-
- if (newContact) {
- meRawContactId = ContentUris.parseId(contentResolver.insert(PROFILE_URI, values));
- }
-
- values.put(ContactsContract.Data.RAW_CONTACT_ID, meRawContactId);
- values.put(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, name);
- values.put(ContactsContract.Data.MIMETYPE,
- ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE);
-
- long structuredNameId = getProfileItem(meRawContactId, contentResolver);
- if (newContact || structuredNameId == INVALID_ID) {
- contentResolver.insert(ContactsContract.Data.CONTENT_URI, values);
- } else {
- contentResolver.update(ContentUris.withAppendedId(
- ContactsContract.Data.CONTENT_URI, structuredNameId), values,
- /* where= */ null, /* selectionArgs= */ null);
- }
- }
-
- /**
- * Helper method to search for the first profile item of the type {@link
- * ContactsContract.CommonDataKinds.StructuredName#CONTENT_ITEM_TYPE}.
- *
- * @return The item's ID or {@link #INVALID_ID} if not found.
- */
- private static long getProfileItem(long profileContactId, ContentResolver contentResolver) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "getProfileItem profileContactId=" + profileContactId);
- }
- Uri dataUri = ContactsContract.Profile.CONTENT_RAW_CONTACTS_URI.buildUpon()
- .appendPath(String.valueOf(profileContactId))
- .appendPath(ContactsContract.RawContacts.Data.CONTENT_DIRECTORY)
- .build();
-
- Cursor cursor = contentResolver.query(
- dataUri,
- CONTACTS_PROFILE_PROJECTION,
- CONTACT_MIME_QUERY,
- new String[]{
- ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE},
- /* sortOrder= */ null);
-
- // Error in querying the content resolver.
- if (cursor == null) {
- Log.e(TAG, "Received null from query to the first profile item at " + dataUri);
- return INVALID_ID;
- }
-
- try {
- return cursor.moveToFirst() ? cursor.getLong(0) : INVALID_ID;
- } finally {
- cursor.close();
- }
- }
-}
diff --git a/car-settings-lib/src/com/android/car/settingslib/util/ResultCodes.java b/car-settings-lib/src/com/android/car/settingslib/util/ResultCodes.java
deleted file mode 100644
index 2ac5ef2..0000000
--- a/car-settings-lib/src/com/android/car/settingslib/util/ResultCodes.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2018 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.settingslib.util;
-
-import static android.app.Activity.RESULT_FIRST_USER;
-
-/**
- * Result code set shared between Settings and other Car components
- */
-public final class ResultCodes {
- public static final int RESULT_SKIP = RESULT_FIRST_USER;
- public static final int RESULT_NONE = RESULT_FIRST_USER + 1;
-}
diff --git a/car-settings-lib/tests/robotests/Android.bp b/car-settings-lib/tests/robotests/Android.bp
deleted file mode 100644
index 083e80d..0000000
--- a/car-settings-lib/tests/robotests/Android.bp
+++ /dev/null
@@ -1,46 +0,0 @@
-// 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.
-
-// Car Settings Library app just for Robolectric test target.
-android_app {
- name: "CarSettingsLib",
-
- resource_dirs: [],
-
- platform_apis: true,
-
- privileged: true,
-
- static_libs: ["car-settings-lib"],
-}
-
-// Car Settings Library Robolectric test target.
-android_robolectric_test {
- name: "CarSettingsLibRoboTests",
-
- srcs: ["src/**/*.java"],
-
- libs: [
- "robolectric_android-all-stub",
- "Robolectric_all-target",
- "mockito-robolectric-prebuilt",
- "truth-prebuilt",
- "testng",
- "android.car",
- ],
-
- java_resource_dirs: ["config"],
-
- instrumentation_for: "CarSettingsLib",
-}
diff --git a/car-settings-lib/tests/robotests/config/robolectric.properties b/car-settings-lib/tests/robotests/config/robolectric.properties
deleted file mode 100644
index 3626c87..0000000
--- a/car-settings-lib/tests/robotests/config/robolectric.properties
+++ /dev/null
@@ -1,16 +0,0 @@
-#
-# Copyright (C) 2018 Google Inc.
-#
-# 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.
-#
-sdk=NEWEST_SDK
\ No newline at end of file
diff --git a/car-settings-lib/tests/robotests/src/com/android/car/settingslib/log/LoggerBaseTest.java b/car-settings-lib/tests/robotests/src/com/android/car/settingslib/log/LoggerBaseTest.java
deleted file mode 100644
index 468c010..0000000
--- a/car-settings-lib/tests/robotests/src/com/android/car/settingslib/log/LoggerBaseTest.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2018 Google Inc.
- *
- * 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.settingslib.log;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-
-/**
- * Tests {@link LoggerBase}
- */
-@RunWith(RobolectricTestRunner.class)
-public class LoggerBaseTest {
-
- @Rule
- public ExpectedException mExpectedException = ExpectedException.none();
-
- @Test
- public void testNullTag() {
- mExpectedException.expect(IllegalStateException.class);
- mExpectedException.expectMessage("Tag must be not null or empty");
- new NullTagLogger("NullLogger");
- }
-
- @Test
- public void testEmptyTag() {
- mExpectedException.expect(IllegalStateException.class);
- mExpectedException.expectMessage("Tag must be not null or empty");
- new EmptyTagLogger("EmptyTagLogger");
- }
-
- @Test
- public void testTooLongTag() {
- mExpectedException.expect(IllegalStateException.class);
- mExpectedException.expectMessage("Tag must be 23 characters or less");
- new TooLongTagLogger("TooLongTagLogger");
- }
-
- private class NullTagLogger extends LoggerBase {
-
- NullTagLogger(String prefix) {
- super(prefix);
- }
-
- @Override
- protected String getTag() {
- return null;
- }
- }
-
- private class EmptyTagLogger extends LoggerBase {
-
- EmptyTagLogger(String prefix) {
- super(prefix);
- }
-
- @Override
- protected String getTag() {
- return "";
- }
- }
-
- /**
- * A Logger with a tag that is 24 characters long.
- */
- private class TooLongTagLogger extends LoggerBase {
-
- TooLongTagLogger(String prefix) {
- super(prefix);
- }
-
- @Override
- protected String getTag() {
- return "LoremIpsumLoremIpsumLore";
- }
- }
-}
diff --git a/car-telephony-common/res/values-af/strings.xml b/car-telephony-common/res/values-af/strings.xml
index 235376e..7e19555 100644
--- a/car-telephony-common/res/values-af/strings.xml
+++ b/car-telephony-common/res/values-af/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"Onbekend"</string>
<string name="voicemail" msgid="2125552157407909509">"Stemboodskap"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"Koppel tans"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"Bel tans"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"Koppel tans …"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"Bel tans …"</string>
<string name="call_state_hold" msgid="6834028102796624100">"Hou aan"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"Oproep beëindig"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"Gekoppel"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"Lui tans"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"Ontkoppel tans"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"Lui tans …"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"Ontkoppel tans …"</string>
</resources>
diff --git a/car-telephony-common/res/values-am/strings.xml b/car-telephony-common/res/values-am/strings.xml
index cf05285..6d0315e 100644
--- a/car-telephony-common/res/values-am/strings.xml
+++ b/car-telephony-common/res/values-am/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"ያልታወቀ"</string>
<string name="voicemail" msgid="2125552157407909509">"የድምፅ መልዕክት"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"በመገናኘት ላይ"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"በመደወል ላይ"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"በመገናኘት ላይ…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"በመደወል ላይ"</string>
<string name="call_state_hold" msgid="6834028102796624100">"ያዝናቆይ"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"ጥሪ አብቅቷል"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"ተገናኝቷል"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"በመጥራት ላይ"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"ግንኙነት በማቋረጥ ላይ"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"በመጥራት ላይ…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"ግንኝነትን በማቋረጥ ላይ…"</string>
</resources>
diff --git a/car-telephony-common/res/values-ar/strings.xml b/car-telephony-common/res/values-ar/strings.xml
index bc48b4d..fcc72fb 100644
--- a/car-telephony-common/res/values-ar/strings.xml
+++ b/car-telephony-common/res/values-ar/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"المتّصِل غير معروف."</string>
<string name="voicemail" msgid="2125552157407909509">"البريد الصوتي"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"جارٍ الاتصال"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"جارٍ الطلب"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"جارٍ الاتصال…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"جارٍ طلب الرقم…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"قيد الانتظار"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"انتهت المكالمة"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"متّصل"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"جارٍ استصدار الرنين…"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"جارٍ قطع الاتصال"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"جارٍ إطلاق الرنين…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"جارٍ قطع الاتصال…"</string>
</resources>
diff --git a/car-telephony-common/res/values-as/strings.xml b/car-telephony-common/res/values-as/strings.xml
index 567a480..a4c90ae 100644
--- a/car-telephony-common/res/values-as/strings.xml
+++ b/car-telephony-common/res/values-as/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"অজ্ঞাত"</string>
<string name="voicemail" msgid="2125552157407909509">"ভইচমেইল"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"সংযোগ কৰি থকা হৈছে"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"ডায়েল হৈ আছে"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"সংযোগ কৰি থকা হৈছে…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"ডায়েল কৰি থকা হৈছে…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"হ’ল্ডত আছে"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"কল শেষ হৈছে"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"সংযোগ কৰা হ’ল"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"ৰিং কৰি আছে"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"সংযোগ বিচ্ছিন্ন কৰি থকা হৈছে"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"ৰিং কৰি আছে…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"সংযোগ ছেদ হৈ আছে…"</string>
</resources>
diff --git a/car-telephony-common/res/values-az/strings.xml b/car-telephony-common/res/values-az/strings.xml
index fa9e0f6..d29aeab 100644
--- a/car-telephony-common/res/values-az/strings.xml
+++ b/car-telephony-common/res/values-az/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"Naməlum"</string>
<string name="voicemail" msgid="2125552157407909509">"Səsli poçt"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"Qoşulur"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"Nömrə yığılır"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"Qoşulur…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"Nömrə yığılır…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"Gözləmədə"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"Zəng sona çatdı"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"Qoşuldu"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"Zəng"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"Əlaqə kəsilir"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"Zəng çalır…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"Bağlantı kəsilir…"</string>
</resources>
diff --git a/car-telephony-common/res/values-b+sr+Latn/strings.xml b/car-telephony-common/res/values-b+sr+Latn/strings.xml
index e31bd43..d05ef72 100644
--- a/car-telephony-common/res/values-b+sr+Latn/strings.xml
+++ b/car-telephony-common/res/values-b+sr+Latn/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"Nepoznato"</string>
<string name="voicemail" msgid="2125552157407909509">"Govorna pošta"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"Povezuje se"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"Poziva se"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"Povezuje se…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"Poziva se…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"Na čekanju"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"Poziv je završen"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"Povezan"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"Zvoni"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"Prekida se veza"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"Zvoni…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"Prekida se veza…"</string>
</resources>
diff --git a/car-telephony-common/res/values-be/strings.xml b/car-telephony-common/res/values-be/strings.xml
index da1e944..1e1bcdf 100644
--- a/car-telephony-common/res/values-be/strings.xml
+++ b/car-telephony-common/res/values-be/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"Невядома"</string>
<string name="voicemail" msgid="2125552157407909509">"Галасавая пошта"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"Ідзе падключэнне"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"Ідзе набор нумара"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"Ідзе падключэнне…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"Ідзе набор нумара…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"На ўтрыманні"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"Выклік скончаны"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"Падключана"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"Ідзе празвон"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"Ідзе адключэнне"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"Ідзе празвон…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"Ідзе адключэнне…"</string>
</resources>
diff --git a/car-telephony-common/res/values-bg/strings.xml b/car-telephony-common/res/values-bg/strings.xml
index dcdff62..1f38d61 100644
--- a/car-telephony-common/res/values-bg/strings.xml
+++ b/car-telephony-common/res/values-bg/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"Неизвестно"</string>
<string name="voicemail" msgid="2125552157407909509">"Гласова поща"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"Установява се връзка"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"Набира се"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"Свързва се…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"Набира се…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"Задържано"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"Обаждането завърши"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"Установена е връзка"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"Звъни се"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"Връзката се прекрат."</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"Звъни се…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"Връзката се прекр…"</string>
</resources>
diff --git a/car-telephony-common/res/values-bn/strings.xml b/car-telephony-common/res/values-bn/strings.xml
index 2a857ff..4855b6e 100644
--- a/car-telephony-common/res/values-bn/strings.xml
+++ b/car-telephony-common/res/values-bn/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"অজানা"</string>
<string name="voicemail" msgid="2125552157407909509">"ভয়েসমেল"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"কানেক্ট হচ্ছে"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"ডায়াল করা হচ্ছে"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"কানেক্ট হচ্ছে…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"ডায়াল করা হচ্ছে…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"হোল্ডে আছে"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"কল শেষ হয়েছে"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"কানেক্ট করা হয়েছে"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"রিং হচ্ছে"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"ডিসকানেক্ট হচ্ছে"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"রিং হচ্ছে…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"ডিসকানেক্ট করা হচ্ছে…"</string>
</resources>
diff --git a/car-telephony-common/res/values-bs/strings.xml b/car-telephony-common/res/values-bs/strings.xml
index b28a348..1d6a8b8 100644
--- a/car-telephony-common/res/values-bs/strings.xml
+++ b/car-telephony-common/res/values-bs/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"Nepoznat"</string>
<string name="voicemail" msgid="2125552157407909509">"Govorna pošta"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"Povezivanje"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"Biranje"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"Povezivanje…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"Biranje…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"Na čekanju"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"Poziv je završen"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"Povezan"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"Zvoni"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"Prekidanje veze"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"Zvoni…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"Prekidanje veze…"</string>
</resources>
diff --git a/car-telephony-common/res/values-ca/strings.xml b/car-telephony-common/res/values-ca/strings.xml
index 908e512..356f31c 100644
--- a/car-telephony-common/res/values-ca/strings.xml
+++ b/car-telephony-common/res/values-ca/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"Desconegut"</string>
<string name="voicemail" msgid="2125552157407909509">"Missatge de veu"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"S\'està connectant"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"S\'està marcant"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"S\'està connectant…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"S\'està marcant…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"En espera"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"Trucada finalitzada"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"Connectat"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"S\'està trucant"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"S\'està desconnectant"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"Està sonant…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"S\'està desconnectant…"</string>
</resources>
diff --git a/car-telephony-common/res/values-cs/strings.xml b/car-telephony-common/res/values-cs/strings.xml
index ff07c0b..41a29b5 100644
--- a/car-telephony-common/res/values-cs/strings.xml
+++ b/car-telephony-common/res/values-cs/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"Neznámé"</string>
<string name="voicemail" msgid="2125552157407909509">"Hlasová schránka"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"Připojování"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"Vytáčení"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"Připojování…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"Vytáčení…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"Podrženo"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"Hovor byl ukončen"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"Připojeno"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"Prozvánění"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"Odpojování"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"Vyzvánění…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"Odpojování…"</string>
</resources>
diff --git a/car-telephony-common/res/values-da/strings.xml b/car-telephony-common/res/values-da/strings.xml
index 99ac474..dcd52a0 100644
--- a/car-telephony-common/res/values-da/strings.xml
+++ b/car-telephony-common/res/values-da/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"Ukendt"</string>
<string name="voicemail" msgid="2125552157407909509">"Talebesked"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"Opretter forbindelse"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"Ringer op"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"Tilslutter…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"Ringer op…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"Afventer"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"Opkaldet er slut"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"Der er forbindelse"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"Ringer"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"Lægger på"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"Ringer…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"Afbryder…"</string>
</resources>
diff --git a/car-telephony-common/res/values-de/strings.xml b/car-telephony-common/res/values-de/strings.xml
index b81f82d..a5257d3 100644
--- a/car-telephony-common/res/values-de/strings.xml
+++ b/car-telephony-common/res/values-de/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"Unbekannt"</string>
<string name="voicemail" msgid="2125552157407909509">"Mailbox"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"Wird verbunden"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"Rufaufbau"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"Verbinden…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"Rufaufbau…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"Warten"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"Anruf beendet"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"Verbunden"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"Klingelt"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"Wird getrennt"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"Klingelt…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"Verbindung wird getrennt…"</string>
</resources>
diff --git a/car-telephony-common/res/values-el/strings.xml b/car-telephony-common/res/values-el/strings.xml
index 6712065..40d1716 100644
--- a/car-telephony-common/res/values-el/strings.xml
+++ b/car-telephony-common/res/values-el/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"Άγνωστη"</string>
<string name="voicemail" msgid="2125552157407909509">"Αυτόματος τηλεφωνητής"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"Σύνδεση"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"Κλήση"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"Σύνδεση…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"Κλήση…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"Σε αναμονή"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"Η κλήση τερματίστηκε"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"Συνδέθηκε"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"Κλήση"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"Αποσύνδεση"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"Κλήση…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"Αποσύνδεση…"</string>
</resources>
diff --git a/car-telephony-common/res/values-en-rAU/strings.xml b/car-telephony-common/res/values-en-rAU/strings.xml
index b3923a4..06d1973 100644
--- a/car-telephony-common/res/values-en-rAU/strings.xml
+++ b/car-telephony-common/res/values-en-rAU/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"Unknown"</string>
<string name="voicemail" msgid="2125552157407909509">"Voicemail"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"Connecting"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"Dialling"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"Connecting…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"Dialling…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"On Hold"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"Call Ended"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"Connected"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"Ringing"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"Disconnecting"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"Ringing…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"Disconnecting…"</string>
</resources>
diff --git a/car-telephony-common/res/values-en-rCA/strings.xml b/car-telephony-common/res/values-en-rCA/strings.xml
index b3923a4..06d1973 100644
--- a/car-telephony-common/res/values-en-rCA/strings.xml
+++ b/car-telephony-common/res/values-en-rCA/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"Unknown"</string>
<string name="voicemail" msgid="2125552157407909509">"Voicemail"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"Connecting"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"Dialling"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"Connecting…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"Dialling…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"On Hold"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"Call Ended"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"Connected"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"Ringing"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"Disconnecting"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"Ringing…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"Disconnecting…"</string>
</resources>
diff --git a/car-telephony-common/res/values-en-rGB/strings.xml b/car-telephony-common/res/values-en-rGB/strings.xml
index b3923a4..06d1973 100644
--- a/car-telephony-common/res/values-en-rGB/strings.xml
+++ b/car-telephony-common/res/values-en-rGB/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"Unknown"</string>
<string name="voicemail" msgid="2125552157407909509">"Voicemail"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"Connecting"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"Dialling"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"Connecting…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"Dialling…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"On Hold"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"Call Ended"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"Connected"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"Ringing"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"Disconnecting"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"Ringing…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"Disconnecting…"</string>
</resources>
diff --git a/car-telephony-common/res/values-en-rIN/strings.xml b/car-telephony-common/res/values-en-rIN/strings.xml
index b3923a4..06d1973 100644
--- a/car-telephony-common/res/values-en-rIN/strings.xml
+++ b/car-telephony-common/res/values-en-rIN/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"Unknown"</string>
<string name="voicemail" msgid="2125552157407909509">"Voicemail"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"Connecting"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"Dialling"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"Connecting…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"Dialling…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"On Hold"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"Call Ended"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"Connected"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"Ringing"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"Disconnecting"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"Ringing…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"Disconnecting…"</string>
</resources>
diff --git a/car-telephony-common/res/values-en-rXC/strings.xml b/car-telephony-common/res/values-en-rXC/strings.xml
index ff35156..b80f8fa 100644
--- a/car-telephony-common/res/values-en-rXC/strings.xml
+++ b/car-telephony-common/res/values-en-rXC/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"Unknown"</string>
<string name="voicemail" msgid="2125552157407909509">"Voicemail"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"Connecting"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"Dialing"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"Connecting…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"Dialing…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"On Hold"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"Call Ended"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"Connected"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"Ringing"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"Disconnecting"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"Ringing…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"Disconnecting…"</string>
</resources>
diff --git a/car-telephony-common/res/values-es-rUS/strings.xml b/car-telephony-common/res/values-es-rUS/strings.xml
index a807d20..2e71140 100644
--- a/car-telephony-common/res/values-es-rUS/strings.xml
+++ b/car-telephony-common/res/values-es-rUS/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"Desconocido"</string>
<string name="voicemail" msgid="2125552157407909509">"Buzón de voz"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"Conectando"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"Marcando"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"Conectando…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"Marcando…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"En espera"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"Llamada finalizada"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"Conectado"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"Sonando"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"Desconectando"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"Sonando…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"Desconectando…"</string>
</resources>
diff --git a/car-telephony-common/res/values-es/strings.xml b/car-telephony-common/res/values-es/strings.xml
index 20ba994..390354f 100644
--- a/car-telephony-common/res/values-es/strings.xml
+++ b/car-telephony-common/res/values-es/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"Desconocida"</string>
<string name="voicemail" msgid="2125552157407909509">"Buzón de voz"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"Conectando"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"Marcando"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"Conectando…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"Marcando…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"En espera"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"Llamada finalizada"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"Conectado"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"Sonando"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"Desconectando"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"Sonando…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"Desconectando…"</string>
</resources>
diff --git a/car-telephony-common/res/values-et/strings.xml b/car-telephony-common/res/values-et/strings.xml
index c44ebe2..ee65909 100644
--- a/car-telephony-common/res/values-et/strings.xml
+++ b/car-telephony-common/res/values-et/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"Tundmatu"</string>
<string name="voicemail" msgid="2125552157407909509">"Kõnepost"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"Ühendamine"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"Valimine"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"Ühendamine …"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"Valimine …"</string>
<string name="call_state_hold" msgid="6834028102796624100">"Ootel"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"Kõne lõpetati"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"Ühendatud"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"Helistamine"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"Ühenduse katkestam."</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"Heliseb …"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"Ühenduse katkest. …"</string>
</resources>
diff --git a/car-telephony-common/res/values-eu/strings.xml b/car-telephony-common/res/values-eu/strings.xml
index 3c187ce..ddaec85 100644
--- a/car-telephony-common/res/values-eu/strings.xml
+++ b/car-telephony-common/res/values-eu/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"Ezezaguna"</string>
<string name="voicemail" msgid="2125552157407909509">"Erantzungailua"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"Konektatzen"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"Deitzen"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"Konektatzen…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"Markatzen…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"Zain"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"Deia amaituta"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"Konektatuta"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"Tonua jotzen"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"Deskonektatzen"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"Deitzen…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"Deskonektatzen…"</string>
</resources>
diff --git a/car-telephony-common/res/values-fa/strings.xml b/car-telephony-common/res/values-fa/strings.xml
index a395890..092b944 100644
--- a/car-telephony-common/res/values-fa/strings.xml
+++ b/car-telephony-common/res/values-fa/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"نامشخص"</string>
<string name="voicemail" msgid="2125552157407909509">"پست صوتی"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"درحال برقراری ارتباط"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"درحال شمارهگیری"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"درحال اتصال…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"درحال شمارهگیری"</string>
<string name="call_state_hold" msgid="6834028102796624100">"در انتظار"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"تماس پایان یافت"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"متصل"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"درحال زنگ خوردن"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"درحال قطع ارتباط"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"درحال زنگ زدن…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"درحال قطع اتصال…"</string>
</resources>
diff --git a/car-telephony-common/res/values-fi/strings.xml b/car-telephony-common/res/values-fi/strings.xml
index 9e4b096..ce6ff53 100644
--- a/car-telephony-common/res/values-fi/strings.xml
+++ b/car-telephony-common/res/values-fi/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"Tuntematon"</string>
<string name="voicemail" msgid="2125552157407909509">"Vastaaja"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"Yhdistetään"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"Soitetaan"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"Yhdistetään…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"Soitetaan…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"Pidossa"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"Puhelu päättyi"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"Yhdistetty"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"Soi"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"Katkaistaan yhteyttä"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"Soi…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"Katkaistaan…"</string>
</resources>
diff --git a/car-telephony-common/res/values-fr-rCA/strings.xml b/car-telephony-common/res/values-fr-rCA/strings.xml
index 31ede80..cef9278 100644
--- a/car-telephony-common/res/values-fr-rCA/strings.xml
+++ b/car-telephony-common/res/values-fr-rCA/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"Inconnu"</string>
<string name="voicemail" msgid="2125552157407909509">"Messagerie vocale"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> : <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"Connexion en cours…"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"Composition…"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"Connexion en cours…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"Composition…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"En attente"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"Appel terminé"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"Connecté"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"Sonnerie en cours…"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"Déconnexion…"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"Sonnerie en cours…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"Déconnexion…"</string>
</resources>
diff --git a/car-telephony-common/res/values-fr/strings.xml b/car-telephony-common/res/values-fr/strings.xml
index 0c0f207..164f23d 100644
--- a/car-telephony-common/res/values-fr/strings.xml
+++ b/car-telephony-common/res/values-fr/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"Inconnu"</string>
<string name="voicemail" msgid="2125552157407909509">"Messagerie vocale"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"Tentative d\'appel"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"Composition numéro"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"Connexion…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"Composition numéro…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"En attente"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"Appel terminé"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"Appel en cours"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"Sonnerie"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"Fin de l\'appel"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"Sonnerie…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"Déconnexion…"</string>
</resources>
diff --git a/car-telephony-common/res/values-gl/strings.xml b/car-telephony-common/res/values-gl/strings.xml
index 088b4b2..2251c16 100644
--- a/car-telephony-common/res/values-gl/strings.xml
+++ b/car-telephony-common/res/values-gl/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"Descoñecido"</string>
<string name="voicemail" msgid="2125552157407909509">"Correo de voz"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"Conectando"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"Marcando"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"Conectando…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"Marcando…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"En espera"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"Chamada finalizada"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"Conectado"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"Chamando"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"Desconectando"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"Facendo soar…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"Desconectando…"</string>
</resources>
diff --git a/car-telephony-common/res/values-gu/strings.xml b/car-telephony-common/res/values-gu/strings.xml
index a37024a..04cf443 100644
--- a/car-telephony-common/res/values-gu/strings.xml
+++ b/car-telephony-common/res/values-gu/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"અજાણ"</string>
<string name="voicemail" msgid="2125552157407909509">"વૉઇસમેઇલ"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"કનેક્ટ થઈ રહ્યું છે"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"ડાયલ કરી રહ્યાં છે"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"કનેક્ટ થઈ રહ્યું છે…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"ડાયલ કરી રહ્યાં છે…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"હોલ્ડ પર"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"કૉલ સમાપ્ત થયો"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"કનેક્ટેડ"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"રિંગ વગાડીએ છીએ"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"ડિસ્કનેક્ટ થાય છે"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"રિંગ વાગી રહી છે…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"ડિસ્કનેક્ટ થાય છે…"</string>
</resources>
diff --git a/car-telephony-common/res/values-hi/strings.xml b/car-telephony-common/res/values-hi/strings.xml
index fd3a50a..5fdb213 100644
--- a/car-telephony-common/res/values-hi/strings.xml
+++ b/car-telephony-common/res/values-hi/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"अनजान"</string>
<string name="voicemail" msgid="2125552157407909509">"वॉइसमेल"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"कनेक्ट हो रहा है"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"डायल किया जा रहा है"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"कनेक्ट हो रहा है…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"डायल किया जा रहा है…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"कॉल होल्ड पर है"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"कॉल खत्म हो गया"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"जुड़ गया है"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"घंटी बज रही है"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"डिसकनेक्ट हो रहा है"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"घंटी बज रही है…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"डिसकनेक्ट हो रहा है…"</string>
</resources>
diff --git a/car-telephony-common/res/values-hr/strings.xml b/car-telephony-common/res/values-hr/strings.xml
index cb311bc..5e0f4d7 100644
--- a/car-telephony-common/res/values-hr/strings.xml
+++ b/car-telephony-common/res/values-hr/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"Nepoznato"</string>
<string name="voicemail" msgid="2125552157407909509">"Govorna pošta"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"Povezivanje"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"Biranje broja"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"Povezivanje…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"Biranje broja…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"Na čekanju"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"Poziv je završio"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"Povezano"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"Zvonjenje"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"Prekid veze"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"Zvonjenje…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"Isključivanje…"</string>
</resources>
diff --git a/car-telephony-common/res/values-hu/strings.xml b/car-telephony-common/res/values-hu/strings.xml
index 65b2543..fa95e1a 100644
--- a/car-telephony-common/res/values-hu/strings.xml
+++ b/car-telephony-common/res/values-hu/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"Ismeretlen"</string>
<string name="voicemail" msgid="2125552157407909509">"Hangposta"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"Csatlakozás"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"Tárcsázás"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"Csatlakozás…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"Tárcsázás…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"Várakoztatva"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"A hívás befejeződött"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"Csatlakozva"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"Csörgés"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"Szétkapcsolás"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"Csörgés…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"Kapcsolat bontása…"</string>
</resources>
diff --git a/car-telephony-common/res/values-hy/strings.xml b/car-telephony-common/res/values-hy/strings.xml
index e040c42..c8d7ea9 100644
--- a/car-telephony-common/res/values-hy/strings.xml
+++ b/car-telephony-common/res/values-hy/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"Անհայտ"</string>
<string name="voicemail" msgid="2125552157407909509">"Ձայնային փոստ"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"Միացում"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"Համարը հավաքվում է"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"Միացում…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"Համարհավաքում…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"Սպասում"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"Զանգն ավարտվեց"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"Միացած է"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"Զանգ"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"Անջատվում է"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"Զանգ…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"Անջատվում է…"</string>
</resources>
diff --git a/car-telephony-common/res/values-in/strings.xml b/car-telephony-common/res/values-in/strings.xml
index 11e2406..53a7831 100644
--- a/car-telephony-common/res/values-in/strings.xml
+++ b/car-telephony-common/res/values-in/strings.xml
@@ -17,13 +17,13 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="unknown" msgid="3237922751873109097">"Tidak dikenal"</string>
- <string name="voicemail" msgid="2125552157407909509">"Pesan Suara"</string>
+ <string name="voicemail" msgid="2125552157407909509">"Pesan suara"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"Menghubungkan"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"Memanggil"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"Menghubungkan…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"Memanggil…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"Harap Tunggu"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"Panggilan Diakhiri"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"Terhubung"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"Berdering"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"Memutuskan"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"Berdering…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"Memutus hubungan..."</string>
</resources>
diff --git a/car-telephony-common/res/values-is/strings.xml b/car-telephony-common/res/values-is/strings.xml
index 891dc89..b91a805 100644
--- a/car-telephony-common/res/values-is/strings.xml
+++ b/car-telephony-common/res/values-is/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"Óþekkt"</string>
<string name="voicemail" msgid="2125552157407909509">"Talhólf"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"Tengist"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"Hringir"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"Tengist…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"Hringir…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"Í bið"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"Símtali lokið"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"Tengt"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"Hringir"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"Aftengist"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"Hringir…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"Aftengist…"</string>
</resources>
diff --git a/car-telephony-common/res/values-it/strings.xml b/car-telephony-common/res/values-it/strings.xml
index b4b8b22..cb4bc61 100644
--- a/car-telephony-common/res/values-it/strings.xml
+++ b/car-telephony-common/res/values-it/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"Sconosciuto"</string>
<string name="voicemail" msgid="2125552157407909509">"Segreteria"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"Connessione"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"Composizione"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"Connessione…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"Chiamata…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"In attesa"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"Chiamata terminata"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"Connesso"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"Sta squillando"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"Disconnessione"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"Sta squillando…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"Disconnessione…"</string>
</resources>
diff --git a/car-telephony-common/res/values-iw/strings.xml b/car-telephony-common/res/values-iw/strings.xml
index 8e8bcb0..0d1cd68 100644
--- a/car-telephony-common/res/values-iw/strings.xml
+++ b/car-telephony-common/res/values-iw/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"לא ידוע"</string>
<string name="voicemail" msgid="2125552157407909509">"דואר קולי"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"מתבצעת התחברות"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"מתבצע חיוג"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"מתחבר…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"מחייג…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"בהמתנה"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"השיחה הסתיימה"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"מתבצעת שיחה"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"מושמע צלצול"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"מתבצע ניתוק"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"מצלצל…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"מתנתק…"</string>
</resources>
diff --git a/car-telephony-common/res/values-ja/strings.xml b/car-telephony-common/res/values-ja/strings.xml
index 1c3f652..4c0a6c1 100644
--- a/car-telephony-common/res/values-ja/strings.xml
+++ b/car-telephony-common/res/values-ja/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"不明"</string>
<string name="voicemail" msgid="2125552157407909509">"ボイスメール"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"接続中"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"発信中"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"接続中…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"発信中…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"保留中"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"通話終了"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"接続済み"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"着信中"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"切断中"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"着信中…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"切断中…"</string>
</resources>
diff --git a/car-telephony-common/res/values-ka/strings.xml b/car-telephony-common/res/values-ka/strings.xml
index 901e053..858ffa3 100644
--- a/car-telephony-common/res/values-ka/strings.xml
+++ b/car-telephony-common/res/values-ka/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"უცნობი"</string>
<string name="voicemail" msgid="2125552157407909509">"ხმოვანი ფოსტა"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"უკავშირდება"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"მიმდინარეობს აკრეფა"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"დაკავშირება…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"მიმდინარეობს აკრეფა…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"შეყოვნების რეჟიმში"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"ზარი დასრულდა"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"დაკავშირებულია"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"ირეკება"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"მიმდინარეობს გათიშვა"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"ირეკება…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"კავშირი წყდება…"</string>
</resources>
diff --git a/car-telephony-common/res/values-kk/strings.xml b/car-telephony-common/res/values-kk/strings.xml
index b08c58d..48eba3d 100644
--- a/car-telephony-common/res/values-kk/strings.xml
+++ b/car-telephony-common/res/values-kk/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"Белгісіз"</string>
<string name="voicemail" msgid="2125552157407909509">"Дауыстық хабар"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"Жалғануда"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"Терілуде"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"Жалғануда…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"Терілуде…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"Күтуде"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"Қоңырау аяқталды"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"Жалғанды"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"Шылдырлауда"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"Ажыратылуда"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"Шылдырлату…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"Ажыратылуда…"</string>
</resources>
diff --git a/car-telephony-common/res/values-km/strings.xml b/car-telephony-common/res/values-km/strings.xml
index 98c9cea..a483de3 100644
--- a/car-telephony-common/res/values-km/strings.xml
+++ b/car-telephony-common/res/values-km/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"មិនស្គាល់"</string>
<string name="voicemail" msgid="2125552157407909509">"សារជាសំឡេង"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"កំពុងភ្ជាប់"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"កំពុងហៅ"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"កំពុងភ្ជាប់…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"កំពុងហៅ…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"រង់ចាំ"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"បានបញ្ចប់ការហៅ"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"បានភ្ជាប់"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"កំពុងរោទ៍"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"កំពុងផ្ដាច់"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"កំពុងរោទ៍…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"កំពុងផ្ដាច់…"</string>
</resources>
diff --git a/car-telephony-common/res/values-kn/strings.xml b/car-telephony-common/res/values-kn/strings.xml
index 8516261..7b57804 100644
--- a/car-telephony-common/res/values-kn/strings.xml
+++ b/car-telephony-common/res/values-kn/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"ಅಪರಿಚಿತ"</string>
<string name="voicemail" msgid="2125552157407909509">"ಧ್ವನಿಮೇಲ್"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"ಸಂಪರ್ಕಿಸಲಾಗುತ್ತಿದೆ"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"ಡಯಲ್ ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"ಸಂಪರ್ಕಿಸಲಾಗುತ್ತಿದೆ…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"ಡಯಲ್ ಮಾಡಲಾಗುತ್ತಿದೆ…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"ಹೋಲ್ಡ್ ಮಾಡಲಾಗಿದೆ"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"ಕರೆ ಅಂತ್ಯಗೊಂಡಿದೆ"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"ಸಂಪರ್ಕಿಸಲಾಗಿದೆ"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"ರಿಂಗ್ ಆಗುತ್ತಿದೆ"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"ಸಂಪರ್ಕ ಕಡಿತಗೊಳಿಸಲಾಗುತ್ತಿದೆ"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"ರಿಂಗ್ ಆಗುತ್ತಿದೆ…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"ಸಂಪರ್ಕ ಕಡಿತಗೊಳಿಸಲಾ…"</string>
</resources>
diff --git a/car-telephony-common/res/values-ko/strings.xml b/car-telephony-common/res/values-ko/strings.xml
index 8bd6bb9..1171186 100644
--- a/car-telephony-common/res/values-ko/strings.xml
+++ b/car-telephony-common/res/values-ko/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"알 수 없음"</string>
<string name="voicemail" msgid="2125552157407909509">"음성사서함"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"연결 중"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"전화 거는 중"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"연결 중…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"전화 거는 중..."</string>
<string name="call_state_hold" msgid="6834028102796624100">"대기 중"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"통화 종료됨"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"연결됨"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"전화 수신 중"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"연결 해제 중"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"벨소리 울리는 중…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"연결 해제 중..."</string>
</resources>
diff --git a/car-telephony-common/res/values-ky/strings.xml b/car-telephony-common/res/values-ky/strings.xml
index 711c256..b76e748 100644
--- a/car-telephony-common/res/values-ky/strings.xml
+++ b/car-telephony-common/res/values-ky/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"Белгисиз"</string>
<string name="voicemail" msgid="2125552157407909509">"Үн почтасы"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"Туташууда"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"Терилүүдө"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"Туташууда…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"Терилүүдө…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"Күтүү режиминде"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"Чалуу аяктады"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"Туташты"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"Шыңгыроодо"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"Ажыратылууда"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"Шыңгырап жатат…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"Ажыратылууда…"</string>
</resources>
diff --git a/car-telephony-common/res/values-lo/strings.xml b/car-telephony-common/res/values-lo/strings.xml
index dd91d15..b6cc9df 100644
--- a/car-telephony-common/res/values-lo/strings.xml
+++ b/car-telephony-common/res/values-lo/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"ບໍ່ຮູ້ຈັກ"</string>
<string name="voicemail" msgid="2125552157407909509">"ຂໍ້ຄວາມສຽງ"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"ກຳລັງເຊື່ອມຕໍ່"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"ກຳລັງໂທ"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"ກຳລັງເຊື່ອມຕໍ່…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"ກຳລັງໂທ…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"ຖືສາຍລໍຖ້າ"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"ວາງສາຍແລ້ວ"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"ເຊື່ອມຕໍ່ແລ້ວ"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"ກຳລັງດັງ"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"ກຳລັງຕັດການເຊື່ອມຕໍ່"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"ກຳລັງດັງ…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"ກຳລັງຕັດການເຊື່ອມຕໍ່…"</string>
</resources>
diff --git a/car-telephony-common/res/values-lt/strings.xml b/car-telephony-common/res/values-lt/strings.xml
index 5fd0ebe..ea0508a 100644
--- a/car-telephony-common/res/values-lt/strings.xml
+++ b/car-telephony-common/res/values-lt/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"Nežinomas"</string>
<string name="voicemail" msgid="2125552157407909509">"Balso paštas"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"Sujungiama"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"Renkamas numeris"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"Prisijungiama…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"Renkamas numeris…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"Sulaikyta"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"Skambutis baigtas"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"Sujungta"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"Skambinama"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"Atjungiama"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"Skambinama…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"Atsijungiama…"</string>
</resources>
diff --git a/car-telephony-common/res/values-lv/strings.xml b/car-telephony-common/res/values-lv/strings.xml
index adc33d7..28e49f5 100644
--- a/car-telephony-common/res/values-lv/strings.xml
+++ b/car-telephony-common/res/values-lv/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"Nezināms"</string>
<string name="voicemail" msgid="2125552157407909509">"Balss pasts"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"Notiek savienošana"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"Sastāda numuru"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"Veido savienojumu…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"Sastāda numuru…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"Aizturēts"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"Zvans ir pabeigts"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"Savienots"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"Zvana"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"Notiek atvienošana"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"Zvana…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"Notiek atvienošana…"</string>
</resources>
diff --git a/car-telephony-common/res/values-mk/strings.xml b/car-telephony-common/res/values-mk/strings.xml
index 6633002..b6053e3 100644
--- a/car-telephony-common/res/values-mk/strings.xml
+++ b/car-telephony-common/res/values-mk/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"Непознат"</string>
<string name="voicemail" msgid="2125552157407909509">"Говорна пошта"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"Се поврзува"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"Бирање"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"Се поврзува…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"Бирање…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"На чекање"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"Повикот заврши"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"Поврзан"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"Ѕвонење"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"Се исклучува"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"Ѕвони…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"Се исклучува…"</string>
</resources>
diff --git a/car-telephony-common/res/values-ml/strings.xml b/car-telephony-common/res/values-ml/strings.xml
index 3d63a21..e940e9b 100644
--- a/car-telephony-common/res/values-ml/strings.xml
+++ b/car-telephony-common/res/values-ml/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"അജ്ഞാതം"</string>
<string name="voicemail" msgid="2125552157407909509">"വോയ്സ്മെയിൽ"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"കണക്റ്റ് ചെയ്യുന്നു"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"ഡയൽ ചെയ്യുന്നു"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"കണക്റ്റ് ചെയ്യുന്നു…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"ഡയൽ ചെയ്യുന്നു…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"ഹോള്ഡിലാണ്"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"കോൾ അവസാനിച്ചു"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"കണക്റ്റ് ചെയ്തു"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"റിംഗ് ചെയ്യുന്നു"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"വിച്ഛേദിക്കുന്നു"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"റിംഗ് ചെയ്യുന്നു…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"വിച്ഛേദിക്കുന്നു…"</string>
</resources>
diff --git a/car-telephony-common/res/values-mn/strings.xml b/car-telephony-common/res/values-mn/strings.xml
index 9d04a08..5fdc776 100644
--- a/car-telephony-common/res/values-mn/strings.xml
+++ b/car-telephony-common/res/values-mn/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"Тодорхойгүй"</string>
<string name="voicemail" msgid="2125552157407909509">"Дуут шуудан"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"Холбогдож байна"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"Залгаж байна"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"Холбогдож байна…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"Залгаж байна…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"Хүлээлгэнд байна"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"Дуудлагыг тасалсан"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"Холбогдсон"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"Дуудаж байна"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"Салгаж байна"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"Дуугарч байна…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"Салгаж байна…"</string>
</resources>
diff --git a/car-telephony-common/res/values-mr/strings.xml b/car-telephony-common/res/values-mr/strings.xml
index d59e336..9c7f085 100644
--- a/car-telephony-common/res/values-mr/strings.xml
+++ b/car-telephony-common/res/values-mr/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"अज्ञात"</string>
<string name="voicemail" msgid="2125552157407909509">"व्हॉइसमेल"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"कनेक्ट करत आहे"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"डायल करत आहे"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"कनेक्ट करत आहे…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"डायल करत आहे…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"होल्ड वर"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"कॉल संपला"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"कनेक्ट केले"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"रिंग होत आहे"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"डिस्कनेक्ट करत आहे"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"रिंग होत आहे…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"डिस्कनेक्ट करत आहे…"</string>
</resources>
diff --git a/car-telephony-common/res/values-ms/strings.xml b/car-telephony-common/res/values-ms/strings.xml
index 57bd37e..1c1d5de 100644
--- a/car-telephony-common/res/values-ms/strings.xml
+++ b/car-telephony-common/res/values-ms/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"Tidak diketahui"</string>
<string name="voicemail" msgid="2125552157407909509">"Mel suara"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"Menyambung"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"Mendail"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"Menyambung…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"Mendail…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"Ditunda"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"Panggilan Tamat"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"Disambungkan"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"Berdering"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"Memutuskan sambungan"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"Berdering…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"Memutuskan sambungn…"</string>
</resources>
diff --git a/car-telephony-common/res/values-my/strings.xml b/car-telephony-common/res/values-my/strings.xml
index 317f9a5..130935a 100644
--- a/car-telephony-common/res/values-my/strings.xml
+++ b/car-telephony-common/res/values-my/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"အမည်မသိ"</string>
<string name="voicemail" msgid="2125552157407909509">"အသံမေးလ်"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"ချိတ်ဆက်နေသည်"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"ခေါ်ဆိုနေသည်"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"ချိတ်ဆက်နေသည်…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"ခေါ်ဆိုနေသည်…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"ဖုန်းကိုင်ထားသည်"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"ခေါ်ဆိုမှု ပြီးပါပြီ"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"ချိတ်ဆက်ထားသည်"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"အသံမြည်နေသည်"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"ချိတ်ဆက်မှု ရပ်နေသည်"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"အသံမြည်နေသည်…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"အဆက်အသွယ် ဖြတ်နေသည်…"</string>
</resources>
diff --git a/car-telephony-common/res/values-nb/strings.xml b/car-telephony-common/res/values-nb/strings.xml
index c1555df..119f352 100644
--- a/car-telephony-common/res/values-nb/strings.xml
+++ b/car-telephony-common/res/values-nb/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"Ukjent"</string>
<string name="voicemail" msgid="2125552157407909509">"Talepost"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"Kobler til"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"Slår nummeret"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"Kobler til …"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"Slår nummeret …"</string>
<string name="call_state_hold" msgid="6834028102796624100">"På vent"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"Anropet er avsluttet"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"Tilkoblet"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"Ringer"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"Kobler fra"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"Ringer …"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"Kobler fra …"</string>
</resources>
diff --git a/car-telephony-common/res/values-ne/strings.xml b/car-telephony-common/res/values-ne/strings.xml
index 8bce1e2..b021f11 100644
--- a/car-telephony-common/res/values-ne/strings.xml
+++ b/car-telephony-common/res/values-ne/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"अज्ञात"</string>
<string name="voicemail" msgid="2125552157407909509">"भ्वाइस मेल"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"जडान गर्दै"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"डायल गर्दै"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"जोड्दै…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"डायल गर्दै…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"होल्डमा छ"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"कल समाप्त भयो"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"जडान गरिएको छ"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"घन्टी बज्दै छ"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"विच्छेद गर्दै"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"घन्टी बज्दै छ…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"विच्छेद गर्दै…"</string>
</resources>
diff --git a/car-telephony-common/res/values-nl/strings.xml b/car-telephony-common/res/values-nl/strings.xml
index 0a14c26..7d00163 100644
--- a/car-telephony-common/res/values-nl/strings.xml
+++ b/car-telephony-common/res/values-nl/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"Onbekend"</string>
<string name="voicemail" msgid="2125552157407909509">"Voicemail"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"Verbinden…"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"Kiezen"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"Verbinden…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"Kiezen…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"In de wacht"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"Gesprek beëindigd"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"Verbonden"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"Telefoon gaat over"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"Verbinding verbreken"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"Gaat over…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"Verb. verbreken…"</string>
</resources>
diff --git a/car-telephony-common/res/values-or/strings.xml b/car-telephony-common/res/values-or/strings.xml
index 5b4b9bd..775e33c 100644
--- a/car-telephony-common/res/values-or/strings.xml
+++ b/car-telephony-common/res/values-or/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"ଅଜଣା"</string>
<string name="voicemail" msgid="2125552157407909509">"ଭଏସ୍ମେଲ୍"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"ସଂଯୋଗ କରୁଛି"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"ଡାଏଲ୍ କରାଯାଉଛି"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"ସଂଯୋଗ ହେଉଛି…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"ଡାଏଲ୍ କରାଯାଉଛି…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"ହୋଲ୍ଡରେ ଅଛି"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"କଲ୍ ସମାପ୍ତ ହେଲା"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"ସଂଯୋଗ ହୋଇଛି"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"ରିଙ୍ଗ ହେଉଛି"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"ବିଚ୍ଛିନ୍ନ ହେଉଛି"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"ରିଙ୍ଗ ହେଉଛି…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"ବିଚ୍ଛିନ୍ନ ହେଉଛି…"</string>
</resources>
diff --git a/car-telephony-common/res/values-pa/strings.xml b/car-telephony-common/res/values-pa/strings.xml
index 3bfc923..129276b 100644
--- a/car-telephony-common/res/values-pa/strings.xml
+++ b/car-telephony-common/res/values-pa/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"ਅਗਿਆਤ"</string>
<string name="voicemail" msgid="2125552157407909509">"ਵੌਇਸਮੇਲ"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"ਕਨੈਕਟ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"ਡਾਇਲ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"ਕਨੈਕਟ ਹੋ ਰਿਹਾ ਹੈ…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"ਡਾਇਲ ਹੋ ਰਿਹਾ ਹੈ…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"ਰੋਕ ਕੇ ਰੱਖੀ ਗਈ"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"ਕਾਲ ਸਮਾਪਤ ਹੋਈ"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"ਕਨੈਕਟ ਹੈ"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"ਘੰਟੀ ਵਜ ਰਹੀ ਹੈ"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"ਡਿਸਕਨੈਕਟ ਕਰ ਰਿਹਾ ਹੈ"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"ਘੰਟੀ ਵੱਜ ਰਹੀ ਹੈ…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"ਡਿਸਕਨੈਕਟ ਹੋ ਰਿਹਾ ਹੈ…"</string>
</resources>
diff --git a/car-telephony-common/res/values-pl/strings.xml b/car-telephony-common/res/values-pl/strings.xml
index 0c948d4..1212857 100644
--- a/car-telephony-common/res/values-pl/strings.xml
+++ b/car-telephony-common/res/values-pl/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"Nieznany numer"</string>
<string name="voicemail" msgid="2125552157407909509">"Poczta głosowa"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"Łączę"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"Wybieram numer"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"Łączę…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"Wybieram numer…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"Oczekujące"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"Koniec połączenia"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"Połączono"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"Dzwonię"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"Rozłączam"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"Dzwonię…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"Rozłączam…"</string>
</resources>
diff --git a/car-telephony-common/res/values-pt-rPT/strings.xml b/car-telephony-common/res/values-pt-rPT/strings.xml
index 5f3340d..3b518e6 100644
--- a/car-telephony-common/res/values-pt-rPT/strings.xml
+++ b/car-telephony-common/res/values-pt-rPT/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"Desconhecido"</string>
<string name="voicemail" msgid="2125552157407909509">"Correio de voz"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"A ligar…"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"A marcar…"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"A ligar…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"A marcar…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"Em espera"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"Chamada terminada"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"Ligado"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"A tocar…"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"A desligar…"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"A tocar…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"A desligar…"</string>
</resources>
diff --git a/car-telephony-common/res/values-pt/strings.xml b/car-telephony-common/res/values-pt/strings.xml
index 3231c7a..7531adb 100644
--- a/car-telephony-common/res/values-pt/strings.xml
+++ b/car-telephony-common/res/values-pt/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"Desconhecido"</string>
<string name="voicemail" msgid="2125552157407909509">"Correio de voz"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"Conectando"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"Discando"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"Conectando…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"Discando…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"Em espera"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"Chamada encerrada"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"Conectado"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"Tocando"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"Desconectando"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"Tocando…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"Desconectando…"</string>
</resources>
diff --git a/car-telephony-common/res/values-ro/strings.xml b/car-telephony-common/res/values-ro/strings.xml
index b75ec0f..a9883de 100644
--- a/car-telephony-common/res/values-ro/strings.xml
+++ b/car-telephony-common/res/values-ro/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"Necunoscut"</string>
<string name="voicemail" msgid="2125552157407909509">"Mesagerie vocală"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"Se conectează"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"Se apelează"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"Se conectează…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"Se apelează…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"În așteptare"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"Apel încheiat"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"Conectat"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"Sună"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"Se deconectează"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"Sună…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"Se deconectează…"</string>
</resources>
diff --git a/car-telephony-common/res/values-ru/strings.xml b/car-telephony-common/res/values-ru/strings.xml
index 9c834fb..2e37211 100644
--- a/car-telephony-common/res/values-ru/strings.xml
+++ b/car-telephony-common/res/values-ru/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"Неизвестный абонент"</string>
<string name="voicemail" msgid="2125552157407909509">"Голосовая почта"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"Подключение…"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"Набор номера…"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"Подключение…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"Набор номера…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"На удержании"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"Вызов завершен"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"Подключено"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"Вызов…"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"Отключение…"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"Вызов…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"Отключение…"</string>
</resources>
diff --git a/car-telephony-common/res/values-si/strings.xml b/car-telephony-common/res/values-si/strings.xml
index 9c290ae..399c8d8 100644
--- a/car-telephony-common/res/values-si/strings.xml
+++ b/car-telephony-common/res/values-si/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"නොදනී"</string>
<string name="voicemail" msgid="2125552157407909509">"හඬ තැපෑල"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"සබැඳෙමින්"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"අමතමින්"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"සබැඳෙමින්…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"අමතමින්…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"රඳවා ඇත"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"ඇමතුම නිමා විය"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"සම්බන්ධයි"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"නාද වෙමින්"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"විසන්ධි වෙමින්"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"නාද වෙමින්…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"විසන්ධි වෙමින්…"</string>
</resources>
diff --git a/car-telephony-common/res/values-sk/strings.xml b/car-telephony-common/res/values-sk/strings.xml
index 9349775..83721d3 100644
--- a/car-telephony-common/res/values-sk/strings.xml
+++ b/car-telephony-common/res/values-sk/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"Neznáme"</string>
<string name="voicemail" msgid="2125552157407909509">"Hlasová schránka"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"Pripája sa"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"Vytáča sa"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"Pripája sa…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"Vytáča sa…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"Podržané"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"Hovor bol ukončený"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"Pripojené"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"Prezváňa sa"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"Odpája sa"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"Prezváňa sa…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"Odpája sa…"</string>
</resources>
diff --git a/car-telephony-common/res/values-sl/strings.xml b/car-telephony-common/res/values-sl/strings.xml
index 30d64a0..03a7063 100644
--- a/car-telephony-common/res/values-sl/strings.xml
+++ b/car-telephony-common/res/values-sl/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"Neznano"</string>
<string name="voicemail" msgid="2125552157407909509">"Odzivnik"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"Povezovanje"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"Klicanje"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"Povezovanje …"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"Klicanje …"</string>
<string name="call_state_hold" msgid="6834028102796624100">"Zadržan"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"Klic je bil končan"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"Povezano"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"Zvonjenje"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"Prekinjanje povezave"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"Zvonjenje …"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"Prekin. povezave …"</string>
</resources>
diff --git a/car-telephony-common/res/values-sq/strings.xml b/car-telephony-common/res/values-sq/strings.xml
index 0d5351c..f6439eb 100644
--- a/car-telephony-common/res/values-sq/strings.xml
+++ b/car-telephony-common/res/values-sq/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"I panjohur"</string>
<string name="voicemail" msgid="2125552157407909509">"Posta zanore"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"Po lidhet"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"Po formon numrin"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"Po lidhet…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"Po formon numrin…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"Në pritje"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"Telefonata përfundoi"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"Lidhur"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"Po bie zilja"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"Po shkëputet"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"Po bie zilja…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"Po shkëputet…"</string>
</resources>
diff --git a/car-telephony-common/res/values-sr/strings.xml b/car-telephony-common/res/values-sr/strings.xml
index cd3a045..1f3837f 100644
--- a/car-telephony-common/res/values-sr/strings.xml
+++ b/car-telephony-common/res/values-sr/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"Непознато"</string>
<string name="voicemail" msgid="2125552157407909509">"Говорна пошта"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"Повезује се"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"Позива се"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"Повезује се…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"Позива се…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"На чекању"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"Позив је завршен"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"Повезан"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"Звони"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"Прекида се веза"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"Звони…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"Прекида се веза…"</string>
</resources>
diff --git a/car-telephony-common/res/values-sv/strings.xml b/car-telephony-common/res/values-sv/strings.xml
index dc384ae..f4b9b1a 100644
--- a/car-telephony-common/res/values-sv/strings.xml
+++ b/car-telephony-common/res/values-sv/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"Okänd"</string>
<string name="voicemail" msgid="2125552157407909509">"Röstbrevlåda"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"Ansluter"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"Ringer"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"Ansluter …"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"Ringer upp …"</string>
<string name="call_state_hold" msgid="6834028102796624100">"Parkerat"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"Samtal avslutat"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"Ansluten"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"Ringer"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"Kopplar från"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"Ringer …"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"Kopplar från …"</string>
</resources>
diff --git a/car-telephony-common/res/values-sw/strings.xml b/car-telephony-common/res/values-sw/strings.xml
index 18ea6e2..f6adbc1 100644
--- a/car-telephony-common/res/values-sw/strings.xml
+++ b/car-telephony-common/res/values-sw/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"Haijulikani"</string>
<string name="voicemail" msgid="2125552157407909509">"Ujumbe wa sauti"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"Inaunganisha"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"Inapiga"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"Inaunganisha…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"Inapigia…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"Inangoja"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"Simu Imekamilika"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"Imeunganisha"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"Inalia"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"Inakata muunganisho"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"Inalia…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"Inaondoa…"</string>
</resources>
diff --git a/car-telephony-common/res/values-ta/strings.xml b/car-telephony-common/res/values-ta/strings.xml
index 848f744..d835fab 100644
--- a/car-telephony-common/res/values-ta/strings.xml
+++ b/car-telephony-common/res/values-ta/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"தெரியாதவர்"</string>
<string name="voicemail" msgid="2125552157407909509">"குரலஞ்சல்"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"இணைக்கிறது"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"டயல் செய்கிறது"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"இணைக்கிறது…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"டயல் செய்கிறது…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"காத்திருப்பில்"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"அழைப்பு முடிந்தது"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"இணைக்கப்பட்டது"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"ரிங் ஆகிறது"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"துண்டிக்கிறது"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"அழைக்கிறது…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"துண்டிக்கிறது…"</string>
</resources>
diff --git a/car-telephony-common/res/values-te/strings.xml b/car-telephony-common/res/values-te/strings.xml
index 4df7667..2ebcb08 100644
--- a/car-telephony-common/res/values-te/strings.xml
+++ b/car-telephony-common/res/values-te/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"తెలియదు"</string>
<string name="voicemail" msgid="2125552157407909509">"వాయిస్ మెయిల్"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"కనెక్ట్ చేయబడుతోంది"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"డయల్ చేస్తోంది"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"కనెక్ట్ అవుతోంది…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"డయల్ చేస్తోంది…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"హోల్డ్లో ఉంది"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"కాల్ ముగిసింది"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"కనెక్ట్ చేయబడింది"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"రింగ్ వస్తోంది"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"డిస్కనెక్ట్ చేస్తోంది"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"రింగ్ అవుతోంది…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"డిస్కనెక్టవుతోంది…"</string>
</resources>
diff --git a/car-telephony-common/res/values-th/strings.xml b/car-telephony-common/res/values-th/strings.xml
index be4474d..7af5876 100644
--- a/car-telephony-common/res/values-th/strings.xml
+++ b/car-telephony-common/res/values-th/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"ไม่รู้จัก"</string>
<string name="voicemail" msgid="2125552157407909509">"ข้อความเสียง"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"กำลังเชื่อมต่อ"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"กำลังโทรออก"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"กำลังเชื่อมต่อ…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"กำลังโทรออก…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"พักสาย"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"วางสายแล้ว"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"เชื่อมต่อแล้ว"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"เสียงกริ่ง"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"กำลังตัดการเชื่อมต่อ"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"กำลังส่งเสียง…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"ยกเลิกการเชื่อมต่อ…"</string>
</resources>
diff --git a/car-telephony-common/res/values-tl/strings.xml b/car-telephony-common/res/values-tl/strings.xml
index 01d562f..f5f02ef 100644
--- a/car-telephony-common/res/values-tl/strings.xml
+++ b/car-telephony-common/res/values-tl/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"Hindi Alam"</string>
<string name="voicemail" msgid="2125552157407909509">"Voicemail"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"Kumokonekta"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"Dina-dial"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"Kumokonekta…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"Dina-dial…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"Naka-hold"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"Natapos ang Tawag"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"Nakakonekta"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"Nagri-ring"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"Nagdidiskonekta"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"Nagri-ring…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"Dinidiskonekta…"</string>
</resources>
diff --git a/car-telephony-common/res/values-tr/strings.xml b/car-telephony-common/res/values-tr/strings.xml
index 8a1798b..8da8d62 100644
--- a/car-telephony-common/res/values-tr/strings.xml
+++ b/car-telephony-common/res/values-tr/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"Arayan Bilinmiyor"</string>
<string name="voicemail" msgid="2125552157407909509">"Sesli Mesaj"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"Bağlanıyor"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"Numara Çevriliyor"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"Bağlanıyor…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"Numara çevriliyor…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"Beklemede"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"Çağrı Sonlandırıldı"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"Bağlandı"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"Çalıyor"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"Bağlantı Kesiliyor"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"Zil çaldırılıyor…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"Bağlantı kesiliyor…"</string>
</resources>
diff --git a/car-telephony-common/res/values-uk/strings.xml b/car-telephony-common/res/values-uk/strings.xml
index 7502dab..6c05db2 100644
--- a/car-telephony-common/res/values-uk/strings.xml
+++ b/car-telephony-common/res/values-uk/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"Невідомо"</string>
<string name="voicemail" msgid="2125552157407909509">"Голосова пошта"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"З’єднання"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"Набір номера"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"З’єднання…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"Набір номера…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"Утримується"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"Виклик завершено"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"Під’єднано"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"Дзвінок"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"Від’єднання"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"Дзвінок…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"Від’єднання…"</string>
</resources>
diff --git a/car-telephony-common/res/values-ur/strings.xml b/car-telephony-common/res/values-ur/strings.xml
index 36a3e2a..92dfe09 100644
--- a/car-telephony-common/res/values-ur/strings.xml
+++ b/car-telephony-common/res/values-ur/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"نامعلوم"</string>
<string name="voicemail" msgid="2125552157407909509">"صوتی میل"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"منسلک ہو رہا ہے"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"ڈائل ہو رہا ہے"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"منسلک ہو رہا ہے…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"ڈائل کر رہا ہے…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"ہولڈ پر ہے"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"کال ختم ہوگئی"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"منسلک ہے"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"کال کی جا رہی ہے"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"غیر منسلک ہو رہا ہے"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"گھنٹی بج رہی ہے…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"غیر منسلک ہو رہا ہے…"</string>
</resources>
diff --git a/car-telephony-common/res/values-uz/strings.xml b/car-telephony-common/res/values-uz/strings.xml
index 7b7e8dd..2683304 100644
--- a/car-telephony-common/res/values-uz/strings.xml
+++ b/car-telephony-common/res/values-uz/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"Noaniq"</string>
<string name="voicemail" msgid="2125552157407909509">"Ovozli pochta"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"Ulanmoqda"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"Raqam terilmoqda"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"Ulanmoqda…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"Raqam terilmoqda…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"Kutish holatida"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"Chaqiruv yakunlandi"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"Ulandi"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"Jiringlamoqda"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"Aloqa uzilmoqda"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"Jiringlamoqda…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"Uzilmoqda…"</string>
</resources>
diff --git a/car-telephony-common/res/values-vi/strings.xml b/car-telephony-common/res/values-vi/strings.xml
index 9e6056b..e52194a 100644
--- a/car-telephony-common/res/values-vi/strings.xml
+++ b/car-telephony-common/res/values-vi/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"Không xác định"</string>
<string name="voicemail" msgid="2125552157407909509">"Thư thoại"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"Đang kết nối"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"Đang gọi"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"Đang kết nối…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"Đang quay số..."</string>
<string name="call_state_hold" msgid="6834028102796624100">"Đang chờ"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"Cuộc gọi đã kết thúc"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"Đã kết nối"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"Đang đổ chuông"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"Đang ngắt kết nối"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"Đang đổ chuông..."</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"Đang ngắt kết nối…"</string>
</resources>
diff --git a/car-telephony-common/res/values-zh-rCN/strings.xml b/car-telephony-common/res/values-zh-rCN/strings.xml
index a38b026..1a6a652 100644
--- a/car-telephony-common/res/values-zh-rCN/strings.xml
+++ b/car-telephony-common/res/values-zh-rCN/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"未知"</string>
<string name="voicemail" msgid="2125552157407909509">"语音邮件"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"正在连接"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"正在拨号"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"正在连接…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"正在拨号…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"呼叫等待"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"通话已结束"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"已连接"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"正在响铃"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"正在中断连接"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"正在响铃…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"正在断开连接…"</string>
</resources>
diff --git a/car-telephony-common/res/values-zh-rHK/strings.xml b/car-telephony-common/res/values-zh-rHK/strings.xml
index ee64d81..c92766e 100644
--- a/car-telephony-common/res/values-zh-rHK/strings.xml
+++ b/car-telephony-common/res/values-zh-rHK/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"不明"</string>
<string name="voicemail" msgid="2125552157407909509">"留言"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"正在連接"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"正在撥號"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"正在連接…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"正在撥號…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"保留通話"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"通話已結束"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"已連接"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"正在發出鈴聲"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"正在中斷連線"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"正在發出鈴聲…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"正在解除連接…"</string>
</resources>
diff --git a/car-telephony-common/res/values-zh-rTW/strings.xml b/car-telephony-common/res/values-zh-rTW/strings.xml
index 821c867..decc1db 100644
--- a/car-telephony-common/res/values-zh-rTW/strings.xml
+++ b/car-telephony-common/res/values-zh-rTW/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"不明"</string>
<string name="voicemail" msgid="2125552157407909509">"語音信箱"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"連線中"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"撥號中"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"連線中…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"撥號中…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"保留中"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"通話結束"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"已連線"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"鈴響中"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"正在中斷連線"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"鈴響中…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"正在中斷連線…"</string>
</resources>
diff --git a/car-telephony-common/res/values-zu/strings.xml b/car-telephony-common/res/values-zu/strings.xml
index 63de418..0978e00 100644
--- a/car-telephony-common/res/values-zu/strings.xml
+++ b/car-telephony-common/res/values-zu/strings.xml
@@ -19,11 +19,11 @@
<string name="unknown" msgid="3237922751873109097">"Akwaziwa"</string>
<string name="voicemail" msgid="2125552157407909509">"Ivoyisimeyili"</string>
<string name="phone_label_with_info" msgid="4652109530699808645">"<xliff:g id="LABEL">%1$s</xliff:g> · <xliff:g id="DURATION">%2$s</xliff:g>"</string>
- <string name="call_state_connecting" msgid="6844097368588248151">"Iyaxhuma"</string>
- <string name="call_state_dialing" msgid="4397655224585553327">"Iyadayela"</string>
+ <string name="call_state_connecting" msgid="5930724746375294866">"Iyaxhuma…"</string>
+ <string name="call_state_dialing" msgid="1534599871716648114">"Iyadayela…"</string>
<string name="call_state_hold" msgid="6834028102796624100">"Ibanjiwe"</string>
<string name="call_state_call_ended" msgid="4159349597599886429">"Ikholi iqediwe"</string>
<string name="call_state_call_active" msgid="2769644783657864202">"Ixhunyiwe"</string>
- <string name="call_state_call_ringing" msgid="2115824593555284816">"Iyakhala"</string>
- <string name="call_state_call_ending" msgid="738099494362020903">"Iyanqamula"</string>
+ <string name="call_state_call_ringing" msgid="4618803402954375017">"Iyakhala…"</string>
+ <string name="call_state_call_ending" msgid="5037498349965472247">"Iyanqamula…"</string>
</resources>
diff --git a/car-ui-lib/Android.bp b/car-ui-lib/Android.bp
index bec412b..023ffff 100644
--- a/car-ui-lib/Android.bp
+++ b/car-ui-lib/Android.bp
@@ -16,24 +16,21 @@
android_library {
name: "car-ui-lib",
-
+ sdk_version: "system_current",
+ min_sdk_version: "14",
srcs: ["src/**/*.java"],
-
resource_dirs: ["res"],
-
optimize: {
enabled: false,
},
-
- libs: ["android.car"],
-
+ libs: ["android.car-stubs"],
static_libs: [
"androidx.annotation_annotation",
"androidx.appcompat_appcompat",
"androidx-constraintlayout_constraintlayout",
"androidx.preference_preference",
"androidx.recyclerview_recyclerview",
- "androidx.asynclayoutinflater_asynclayoutinflater",
"androidx-constraintlayout_constraintlayout-solver",
+ "androidx.asynclayoutinflater_asynclayoutinflater",
],
}
diff --git a/car-ui-lib/build.gradle b/car-ui-lib/build.gradle
index aa720d4..f6f5fd0 100644
--- a/car-ui-lib/build.gradle
+++ b/car-ui-lib/build.gradle
@@ -35,6 +35,10 @@
google()
jcenter()
}
+ buildDir = "/tmp/car-ui-build/${rootProject.name}/${project.name}"
+ tasks.withType(JavaCompile) {
+ options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation"
+ }
}
// Library-level build file
diff --git a/car-ui-lib/res/color/car_ui_dialog_icon_color.xml b/car-ui-lib/res/color/car_ui_dialog_icon_color.xml
new file mode 100644
index 0000000..b6941aa
--- /dev/null
+++ b/car-ui-lib/res/color/car_ui_dialog_icon_color.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="?android:attr/colorForeground"/>
+</selector>
\ No newline at end of file
diff --git a/car-ui-lib/res/drawable/car_ui_icon_add.xml b/car-ui-lib/res/drawable/car_ui_icon_add.xml
new file mode 100644
index 0000000..2877cfc
--- /dev/null
+++ b/car-ui-lib/res/drawable/car_ui_icon_add.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+<!-- Used in Carboard's toolbar. -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="48"
+ android:viewportHeight="48">
+<path
+ android:fillColor="@color/car_ui_toolbar_menu_item_icon_color"
+ android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
+</vector>
\ No newline at end of file
diff --git a/car-ui-lib/res/drawable/car_ui_icon_save.xml b/car-ui-lib/res/drawable/car_ui_icon_save.xml
new file mode 100644
index 0000000..a0859db
--- /dev/null
+++ b/car-ui-lib/res/drawable/car_ui_icon_save.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+<!-- Used in Carboard's toolbar. -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="48"
+ android:viewportHeight="48">
+<path
+ android:fillColor="@color/car_ui_toolbar_menu_item_icon_color"
+ android:pathData="M17,3L5,3c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L21,7l-4,-4zM12,19c-1.66,0 -3,-1.34 -3,-3s1.34,-3 3,-3 3,1.34 3,3 -1.34,3 -3,3zM15,9L5,9L5,5h10v4z"/>
+</vector>
diff --git a/car-settings-lib/tests/robotests/AndroidManifest.xml b/car-ui-lib/res/layout/car_ui_radio_button_preference_widget.xml
similarity index 63%
copy from car-settings-lib/tests/robotests/AndroidManifest.xml
copy to car-ui-lib/res/layout/car_ui_radio_button_preference_widget.xml
index dd1a985..d179a09 100644
--- a/car-settings-lib/tests/robotests/AndroidManifest.xml
+++ b/car-ui-lib/res/layout/car_ui_radio_button_preference_widget.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (C) 2018 Google Inc.
+ Copyright 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.
@@ -15,7 +15,11 @@
limitations under the License.
-->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.car.settingslib.robotests">
-
-</manifest>
+<RadioButton
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/radio_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:clickable="false"
+ android:focusable="false"/>
diff --git a/car-ui-lib/res/layout/car_ui_seekbar_dialog.xml b/car-ui-lib/res/layout/car_ui_seekbar_dialog.xml
new file mode 100644
index 0000000..90124c4
--- /dev/null
+++ b/car-ui-lib/res/layout/car_ui_seekbar_dialog.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center_horizontal"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/seek_bar_text_top"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="center_horizontal"
+ style="@style/Preference.CarUi.DialogSeekBarPreference.TopText"/>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal" >
+
+ <TextView
+ android:id="@+id/seek_bar_text_left"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:visibility="gone"
+ style="@style/Preference.CarUi.DialogSeekBarPreference.LeftText"/>
+
+ <SeekBar
+ android:id="@+id/seek_bar"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ style="@style/Preference.CarUi.DialogSeekBarPreference.Seekbar"/>
+
+ <TextView
+ android:id="@+id/seek_bar_text_right"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:visibility="gone"
+ style="@style/Preference.CarUi.DialogSeekBarPreference.RightText"/>
+ </LinearLayout>
+
+</LinearLayout>
diff --git a/car-ui-lib/res/layout/car_ui_toolbar_menu_item.xml b/car-ui-lib/res/layout/car_ui_toolbar_menu_item.xml
index 3e49e5f..a24b1cf 100644
--- a/car-ui-lib/res/layout/car_ui_toolbar_menu_item.xml
+++ b/car-ui-lib/res/layout/car_ui_toolbar_menu_item.xml
@@ -17,7 +17,7 @@
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
+ android:layout_height="match_parent"
style="@style/Widget.CarUi.Toolbar.MenuItem.IndividualContainer">
<FrameLayout
android:id="@+id/car_ui_toolbar_menu_item_icon_container"
diff --git a/car-ui-lib/res/layout/car_ui_toolbar_tab_item.xml b/car-ui-lib/res/layout/car_ui_toolbar_tab_item.xml
index 82faedc..9172f5b 100644
--- a/car-ui-lib/res/layout/car_ui_toolbar_tab_item.xml
+++ b/car-ui-lib/res/layout/car_ui_toolbar_tab_item.xml
@@ -18,7 +18,7 @@
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
+ android:layout_height="match_parent"
style="@style/Widget.CarUi.Toolbar.Tab.Container">
<ImageView
android:id="@+id/car_ui_toolbar_tab_item_icon"
diff --git a/car-ui-lib/res/layout/car_ui_toolbar_tab_item_flexible.xml b/car-ui-lib/res/layout/car_ui_toolbar_tab_item_flexible.xml
new file mode 100644
index 0000000..44e4725
--- /dev/null
+++ b/car-ui-lib/res/layout/car_ui_toolbar_tab_item_flexible.xml
@@ -0,0 +1,34 @@
+<?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.
+ -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ style="@style/Widget.CarUi.Toolbar.Tab.Container">
+ <ImageView
+ android:id="@+id/car_ui_toolbar_tab_item_icon"
+ android:layout_width="@dimen/car_ui_toolbar_tab_icon_width"
+ android:layout_height="@dimen/car_ui_toolbar_tab_icon_height"
+ style="@style/Widget.CarUi.Toolbar.Tab.Icon"/>
+ <TextView
+ android:id="@+id/car_ui_toolbar_tab_item_text"
+ android:layout_width="@dimen/car_ui_toolbar_tab_text_width"
+ android:layout_height="wrap_content"
+ style="@style/Widget.CarUi.Toolbar.Tab.Text"/>
+</LinearLayout>
diff --git a/car-ui-lib/res/layout/car_ui_two_action_preference.xml b/car-ui-lib/res/layout/car_ui_two_action_preference.xml
new file mode 100644
index 0000000..4ad6ce4
--- /dev/null
+++ b/car-ui-lib/res/layout/car_ui_two_action_preference.xml
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2018 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.
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@android:color/transparent"
+ android:gravity="center_vertical"
+ android:minHeight="?android:attr/listPreferredItemHeightSmall">
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:background="?android:attr/selectableItemBackground"
+ android:clipToPadding="false"
+ android:gravity="start|center_vertical"
+ android:paddingBottom="@dimen/car_ui_preference_content_margin_bottom"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingTop="@dimen/car_ui_preference_content_margin_top">
+ <androidx.preference.internal.PreferenceImageView
+ android:id="@android:id/icon"
+ android:layout_width="@dimen/car_ui_preference_icon_size"
+ android:layout_height="@dimen/car_ui_preference_icon_size"
+ android:layout_marginEnd="@dimen/car_ui_preference_icon_margin_end"/>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:orientation="vertical">
+ <TextView
+ android:id="@android:id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:ellipsize="end"
+ android:singleLine="true"
+ android:textAppearance="@style/TextAppearance.CarUi.PreferenceTitle"/>
+ <TextView
+ android:id="@android:id/summary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="@style/TextAppearance.CarUi.PreferenceSummary"/>
+ </LinearLayout>
+ </LinearLayout>
+ <LinearLayout
+ android:id="@+id/action_widget_container"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent">
+ <View
+ android:layout_width="@dimen/car_ui_divider_width"
+ android:layout_height="match_parent"
+ android:layout_marginBottom="@dimen/car_ui_preference_content_margin_bottom"
+ android:layout_marginTop="@dimen/car_ui_preference_content_margin_top"
+ style="@style/Preference.CarUi.Divider"/>
+ <!-- Preference should place its actual preference widget here. -->
+ <FrameLayout
+ android:id="@android:id/widget_frame"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:background="?android:attr/selectableItemBackground"
+ android:minWidth="?android:attr/listPreferredItemHeightSmall"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"/>
+ </LinearLayout>
+</LinearLayout>
diff --git a/car-ui-lib/res/values/attrs.xml b/car-ui-lib/res/values/attrs.xml
index d8e2e00..ac78971 100644
--- a/car-ui-lib/res/values/attrs.xml
+++ b/car-ui-lib/res/values/attrs.xml
@@ -118,6 +118,13 @@
<declare-styleable name="CarUiPreference">
<!-- Toggle for showing chevron -->
<attr name="showChevron" format="boolean" />
+ <!-- Show ripple when disabled preference is clicked -->
+ <attr name="showRippleOnDisabledPreference" format="boolean" />
+ </declare-styleable>
+
+ <declare-styleable name="CarUiTwoActionPreference">
+ <!-- Determines if the secondary action is initially shown -->
+ <attr name="actionShown" format="boolean"/>
</declare-styleable>
<!-- Theme attribute to specify a default style for all CarUiPreferences -->
diff --git a/car-ui-lib/res/values/colors.xml b/car-ui-lib/res/values/colors.xml
index 78d1ecc..7a12327 100644
--- a/car-ui-lib/res/values/colors.xml
+++ b/car-ui-lib/res/values/colors.xml
@@ -41,15 +41,6 @@
<!-- Preferences -->
- <color name="car_ui_preference_category_title_text_color">@color/car_ui_color_accent</color>
- <color name="car_ui_preference_summary_text_color">@color/car_ui_text_color_secondary</color>
- <color name="car_ui_preference_title_text_color">@color/car_ui_text_color_primary</color>
- <color name="car_ui_preference_edit_text_dialog_message_text_color">@color/car_ui_text_color_primary</color>
<color name="car_ui_preference_icon_color">@color/car_ui_text_color_primary</color>
- <color name="car_ui_preference_switch_track_text_color">@color/car_ui_text_color_primary</color>
-
- <!-- List item -->
- <color name="car_ui_list_item_header_text_color">@color/car_ui_color_accent</color>
- <color name="car_ui_list_item_title_text_color">@color/car_ui_text_color_primary</color>
- <color name="car_ui_list_item_body_text_color">@color/car_ui_text_color_secondary</color>
+ <color name="car_ui_preference_two_action_divider_color">#1fffffff</color>
</resources>
diff --git a/car-ui-lib/res/values/dimens.xml b/car-ui-lib/res/values/dimens.xml
index 3a77194..c4bf244 100644
--- a/car-ui-lib/res/values/dimens.xml
+++ b/car-ui-lib/res/values/dimens.xml
@@ -19,8 +19,6 @@
<dimen name="car_ui_touch_target_width">76dp</dimen>
<dimen name="car_ui_touch_target_height">76dp</dimen>
<dimen name="car_ui_primary_icon_size">44dp</dimen>
- <item name="car_ui_letter_spacing_body1" format="float" type="dimen">0.0</item>
- <item name="car_ui_letter_spacing_body3" format="float" type="dimen">0.0</item>
<!-- Horizontal margin between screen content and display border. In reference
implementation, this value matches the CarUiRecyclerView scrollbar width -->
@@ -142,10 +140,7 @@
<!-- Preferences -->
- <dimen name="car_ui_preference_category_text_size">24sp</dimen>
- <dimen name="car_ui_preference_summary_text_size">24sp</dimen>
- <dimen name="car_ui_preference_title_text_size">32sp</dimen>
- <dimen name="car_ui_preference_edit_text_dialog_message_text_size">24sp</dimen>
+ <dimen name="car_ui_divider_width">1dp</dimen>
<dimen name="car_ui_preference_content_margin_top">16dp</dimen>
<dimen name="car_ui_preference_content_margin_bottom">16dp</dimen>
@@ -166,11 +161,6 @@
<dimen name="car_ui_preference_edit_text_dialog_text_margin_start">24dp</dimen>
<dimen name="car_ui_preference_edit_text_dialog_text_margin_end">24dp</dimen>
- <dimen name="car_ui_preference_switch_text_size">30sp</dimen>
- <dimen name="car_ui_preference_switch_width">288dp</dimen>
- <dimen name="car_ui_preference_switch_width_half">144dp</dimen>
- <dimen name="car_ui_preference_switch_height">101dp</dimen>
-
<!-- Alert dialog -->
<dimen name="car_ui_dialog_edittext_height">50dp</dimen>
@@ -183,9 +173,6 @@
<!-- List item -->
- <dimen name="car_ui_list_item_header_text_size">24sp</dimen>
- <dimen name="car_ui_list_item_title_text_size">32sp</dimen>
- <dimen name="car_ui_list_item_body_text_size">24sp</dimen>
<dimen name="car_ui_list_item_height">116dp</dimen>
<dimen name="car_ui_list_item_header_height">76dp</dimen>
<dimen name="car_ui_list_item_header_start_inset">0dp</dimen>
diff --git a/car-ui-lib/res/values/strings.xml b/car-ui-lib/res/values/strings.xml
index a42068f..ebb72b1 100644
--- a/car-ui-lib/res/values/strings.xml
+++ b/car-ui-lib/res/values/strings.xml
@@ -44,11 +44,6 @@
<string name="car_ui_preference_switch_on">On</string>
<!-- Text to show when a preference switch is off. [CHAR_LIMIT=30] -->
<string name="car_ui_preference_switch_off">Off</string>
- <!-- Font family to use for preference category titles. [CHAR_LIMIT=NONE] -->
- <string name="car_ui_preference_category_title_font_family" translatable="false">sans-serif-medium</string>
-
- <!-- Font family to use for list item headers. [CHAR_LIMIT=NONE] -->
- <string name="car_ui_list_item_header_font_family" translatable="false">sans-serif-medium</string>
<!-- Text to show when no button is provided and a default button is used. -->
<string name="car_ui_alert_dialog_default_button" translatable="false">Close</string>
diff --git a/car-ui-lib/res/values/styles.xml b/car-ui-lib/res/values/styles.xml
index a242baf..807ff96 100644
--- a/car-ui-lib/res/values/styles.xml
+++ b/car-ui-lib/res/values/styles.xml
@@ -182,6 +182,10 @@
<item name="android:dialogLayout">@layout/car_ui_preference_dialog_edittext</item>
</style>
+ <style name="Preference.CarUi.Divider">
+ <item name="android:background">@color/car_ui_preference_two_action_divider_color</item>
+ </style>
+
<style name="Preference.CarUi.DropDown">
<item name="android:layout">@layout/car_ui_preference_dropdown</item>
</style>
@@ -203,6 +207,14 @@
<item name="showSeekBarValue">false</item>
</style>
+ <style name="Preference.CarUi.DialogSeekBarPreference"/>
+
+ <style name="Preference.CarUi.DialogSeekBarPreference.Seekbar"/>
+
+ <style name="Preference.CarUi.DialogSeekBarPreference.TopText"/>
+ <style name="Preference.CarUi.DialogSeekBarPreference.RightText"/>
+ <style name="Preference.CarUi.DialogSeekBarPreference.LeftText"/>
+
<style name="Preference.CarUi.SwitchPreference">
<item name="android:widgetLayout">@layout/car_ui_preference_widget_switch</item>
<item name="android:switchTextOn">@string/car_ui_preference_switch_on</item>
@@ -229,42 +241,38 @@
<item name="android:textColor">?android:attr/textColorPrimary</item>
</style>
- <style name="TextAppearance.CarUi.PreferenceCategoryTitle">
- <item name="android:fontFamily">@string/car_ui_preference_category_title_font_family</item>
- <item name="android:textColor">@color/car_ui_preference_category_title_text_color</item>
- <item name="android:textSize">@dimen/car_ui_preference_category_text_size</item>
+ <style name="TextAppearance.CarUi.Body1">
+ <item name="android:textSize">32sp</item>
</style>
- <style name="TextAppearance.CarUi.PreferenceSummary">
- <item name="android:textColor">@color/car_ui_preference_summary_text_color</item>
- <item name="android:textSize">@dimen/car_ui_preference_summary_text_size</item>
+ <style name="TextAppearance.CarUi.Body3">
+ <item name="android:textSize">24sp</item>
</style>
- <style name="TextAppearance.CarUi.PreferenceTitle">
- <item name="android:textColor">@color/car_ui_preference_title_text_color</item>
- <item name="android:textSize">@dimen/car_ui_preference_title_text_size</item>
+ <style name="TextAppearance.CarUi.PreferenceCategoryTitle" parent="TextAppearance.CarUi.Body3">
+ <item name="android:fontFamily">sans-serif-medium</item>
+ <item name="android:textColor">@color/car_ui_color_accent</item>
</style>
- <style name="TextAppearance.CarUi.PreferenceEditTextDialogMessage">
- <item name="android:textColor">@color/car_ui_preference_edit_text_dialog_message_text_color</item>
- <item name="android:textSize">@dimen/car_ui_preference_edit_text_dialog_message_text_size</item>
+ <style name="TextAppearance.CarUi.PreferenceSummary" parent="TextAppearance.CarUi.Body3">
+ <item name="android:textColor">@color/car_ui_text_color_secondary</item>
</style>
+ <style name="TextAppearance.CarUi.PreferenceTitle" parent="TextAppearance.CarUi.Body1"/>
+
+ <style name="TextAppearance.CarUi.PreferenceEditTextDialogMessage" parent="TextAppearance.CarUi.Body3"/>
+
<style name="TextAppearance.CarUi.AlertDialog.Subtitle" parent="android:TextAppearance.DeviceDefault"/>
<style name="TextAppearance.CarUi.Widget" parent="android:TextAppearance.DeviceDefault.Widget"/>
<style name="TextAppearance.CarUi.Widget.Toolbar"/>
- <style name="TextAppearance.CarUi.Widget.Toolbar.Title">
+ <style name="TextAppearance.CarUi.Widget.Toolbar.Title" parent="TextAppearance.CarUi.Body1">
<item name="android:singleLine">true</item>
- <item name="android:textSize">32sp</item>
- <item name="android:letterSpacing">@dimen/car_ui_letter_spacing_body1</item>
</style>
- <style name="TextAppearance.CarUi.Widget.Toolbar.Tab">
- <item name="android:textSize">24sp</item>
- <item name="android:letterSpacing">@dimen/car_ui_letter_spacing_body3</item>
+ <style name="TextAppearance.CarUi.Widget.Toolbar.Tab" parent="TextAppearance.CarUi.Body3">
<item name="android:textColor">@color/car_ui_toolbar_tab_item_selector</item>
<item name="android:textStyle">normal</item>
<item name="android:textFontWeight">400</item>
@@ -274,20 +282,15 @@
<item name="android:textFontWeight">500</item>
</style>
- <style name="TextAppearance.CarUi.ListItem.Header">
- <item name="android:fontFamily">@string/car_ui_list_item_header_font_family</item>
- <item name="android:textColor">@color/car_ui_list_item_header_text_color</item>
- <item name="android:textSize">@dimen/car_ui_list_item_header_text_size</item>
+ <style name="TextAppearance.CarUi.ListItem.Header" parent="TextAppearance.CarUi.Body3">
+ <item name="android:fontFamily">sans-serif-medium</item>
+ <item name="android:textColor">@color/car_ui_color_accent</item>
</style>
- <style name="TextAppearance.CarUi.ListItem">
- <item name="android:textColor">@color/car_ui_list_item_title_text_color</item>
- <item name="android:textSize">@dimen/car_ui_list_item_title_text_size</item>
- </style>
+ <style name="TextAppearance.CarUi.ListItem" parent="TextAppearance.CarUi.Body1"/>
- <style name="TextAppearance.CarUi.ListItem.Body">
- <item name="android:textSize">@dimen/car_ui_list_item_body_text_size</item>
- <item name="android:textColor">@color/car_ui_list_item_body_text_color</item>
+ <style name="TextAppearance.CarUi.ListItem.Body" parent="TextAppearance.CarUi.Body3">
+ <item name="android:textColor">@color/car_ui_text_color_secondary</item>
</style>
</resources>
diff --git a/car-ui-lib/res/values/values.xml b/car-ui-lib/res/values/values.xml
index 2ad44fa..82a4d65 100644
--- a/car-ui-lib/res/values/values.xml
+++ b/car-ui-lib/res/values/values.xml
@@ -20,4 +20,5 @@
<!-- Layout to be used for toolbar tabs -->
<item name="car_ui_toolbar_tab_item_layout" type="layout">@layout/car_ui_toolbar_tab_item</item>
+ <item name="car_ui_toolbar_tab_item_layout_flexible" type="layout">@layout/car_ui_toolbar_tab_item_flexible</item>
</resources>
diff --git a/car-ui-lib/src/com/android/car/ui/AlertDialogBuilder.java b/car-ui-lib/src/com/android/car/ui/AlertDialogBuilder.java
index 0cbda42..3ffbdd5 100644
--- a/car-ui-lib/src/com/android/car/ui/AlertDialogBuilder.java
+++ b/car-ui-lib/src/com/android/car/ui/AlertDialogBuilder.java
@@ -22,6 +22,7 @@
import android.database.Cursor;
import android.graphics.drawable.Drawable;
import android.text.InputFilter;
+import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.View;
@@ -52,6 +53,7 @@
private CharSequence mTitle;
private CharSequence mSubtitle;
private Drawable mIcon;
+ private boolean mIconTinted;
public AlertDialogBuilder(Context context) {
// Resource id specified as 0 uses the parent contexts resolved value for alertDialogTheme.
@@ -149,7 +151,18 @@
*/
public AlertDialogBuilder setIcon(Drawable icon) {
mIcon = icon;
- mBuilder.setIcon(icon);
+ return this;
+ }
+
+ /**
+ * Whether the icon provided by {@link #setIcon(Drawable)} should be
+ * tinted with the default system color.
+ *
+ * @return this Builder object to allow for chaining of calls to set
+ * methods.
+ */
+ public AlertDialogBuilder setIconTinted(boolean tinted) {
+ mIconTinted = tinted;
return this;
}
@@ -157,8 +170,7 @@
* Set an icon as supplied by a theme attribute. e.g.
* {@link android.R.attr#alertDialogIcon}.
* <p>
- * Takes precedence over values set using {@link #setIcon(int)} or
- * {@link #setIcon(Drawable)}.
+ * Takes precedence over values set using {@link #setIcon(Drawable)}.
*
* @param attrId ID of a theme attribute that points to a drawable resource.
*/
@@ -574,21 +586,24 @@
/** Final steps common to both {@link #create()} and {@link #show()} */
private void prepareDialog() {
- if (mSubtitle != null) {
+ View customTitle = LayoutInflater.from(mContext).inflate(
+ R.layout.car_ui_alert_dialog_title_with_subtitle, null);
- View customTitle = LayoutInflater.from(mContext).inflate(
- R.layout.car_ui_alert_dialog_title_with_subtitle, null);
+ TextView mTitleView = customTitle.requireViewById(R.id.alertTitle);
+ TextView mSubtitleView = customTitle.requireViewById(R.id.alertSubtitle);
+ ImageView mIconView = customTitle.requireViewById(R.id.icon);
- TextView mTitleView = customTitle.requireViewById(R.id.alertTitle);
- TextView mSubtitleView = customTitle.requireViewById(R.id.alertSubtitle);
- ImageView mIconView = customTitle.requireViewById(R.id.icon);
-
- mTitleView.setText(mTitle);
- mSubtitleView.setText(mSubtitle);
- mIconView.setImageDrawable(mIcon);
- mIconView.setVisibility(mIcon != null ? View.VISIBLE : View.GONE);
- mBuilder.setCustomTitle(customTitle);
+ mTitleView.setText(mTitle);
+ mTitleView.setVisibility(TextUtils.isEmpty(mTitle) ? View.GONE : View.VISIBLE);
+ mSubtitleView.setText(mSubtitle);
+ mSubtitleView.setVisibility(TextUtils.isEmpty(mSubtitle) ? View.GONE : View.VISIBLE);
+ mIconView.setImageDrawable(mIcon);
+ mIconView.setVisibility(mIcon != null ? View.VISIBLE : View.GONE);
+ if (mIconTinted) {
+ mIconView.setImageTintList(
+ mContext.getColorStateList(R.color.car_ui_dialog_icon_color));
}
+ mBuilder.setCustomTitle(customTitle);
if (!mNeutralButtonSet && !mNegativeButtonSet && !mPositiveButtonSet) {
String mDefaultButtonText = mContext.getString(
diff --git a/car-ui-lib/src/com/android/car/ui/preference/CarUiEditTextPreference.java b/car-ui-lib/src/com/android/car/ui/preference/CarUiEditTextPreference.java
index 4480714..8774491 100644
--- a/car-ui-lib/src/com/android/car/ui/preference/CarUiEditTextPreference.java
+++ b/car-ui-lib/src/com/android/car/ui/preference/CarUiEditTextPreference.java
@@ -18,8 +18,11 @@
import android.content.Context;
import android.util.AttributeSet;
+import android.view.View;
+import androidx.annotation.VisibleForTesting;
import androidx.preference.EditTextPreference;
+import androidx.preference.PreferenceViewHolder;
import com.android.car.ui.R;
@@ -53,6 +56,18 @@
mContext = context;
}
+ protected void setTwoActionLayout() {
+ setLayoutResource(R.layout.car_ui_two_action_preference);
+ }
+
+ /**
+ * Returns the widget container if {@link #setTwoActionLayout) was called, otherwise null.
+ */
+ @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
+ public View getWidgetActionContainer(PreferenceViewHolder holder) {
+ return holder.findViewById(R.id.action_widget_container);
+ }
+
@Override
public void onAttached() {
super.onAttached();
diff --git a/car-ui-lib/src/com/android/car/ui/preference/CarUiMultiSelectListPreference.java b/car-ui-lib/src/com/android/car/ui/preference/CarUiMultiSelectListPreference.java
index 4752082..bc626a0 100644
--- a/car-ui-lib/src/com/android/car/ui/preference/CarUiMultiSelectListPreference.java
+++ b/car-ui-lib/src/com/android/car/ui/preference/CarUiMultiSelectListPreference.java
@@ -52,6 +52,11 @@
mContext = context;
}
+ /**
+ * This is to make getSelectedItems() visible from other classes in
+ * com.android.car.ui.preference.
+ */
+ @Override
protected boolean[] getSelectedItems() {
return super.getSelectedItems();
}
diff --git a/car-ui-lib/src/com/android/car/ui/preference/CarUiPreference.java b/car-ui-lib/src/com/android/car/ui/preference/CarUiPreference.java
index 5db22cf..2fbbacb 100644
--- a/car-ui-lib/src/com/android/car/ui/preference/CarUiPreference.java
+++ b/car-ui-lib/src/com/android/car/ui/preference/CarUiPreference.java
@@ -18,9 +18,15 @@
import android.content.Context;
import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Toast;
+import androidx.core.view.ViewCompat;
import androidx.preference.Preference;
+import androidx.preference.PreferenceViewHolder;
import com.android.car.ui.R;
@@ -32,6 +38,12 @@
private Context mContext;
private boolean mShowChevron;
+ private String mMessageToShowWhenDisabledPreferenceClicked;
+
+ private boolean mShouldShowRippleOnDisabledPreference;
+ private boolean mEnabledAppearance = true;
+ private Drawable mBackground;
+ private View mPreference;
public CarUiPreference(Context context, AttributeSet attrs,
int defStyleAttr, int defStyleRes) {
@@ -61,6 +73,46 @@
defStyleRes);
mShowChevron = a.getBoolean(R.styleable.CarUiPreference_showChevron, true);
+ mShouldShowRippleOnDisabledPreference = a.getBoolean(
+ R.styleable.CarUiPreference_showRippleOnDisabledPreference, false);
+ }
+
+
+ @Override
+ public void onBindViewHolder(PreferenceViewHolder holder) {
+ super.onBindViewHolder(holder);
+ boolean viewEnabled = isEnabled();
+ if (viewEnabled) {
+ if (mBackground != null) {
+ ViewCompat.setBackground(holder.itemView, mBackground);
+ }
+ enableView(holder.itemView, true, false);
+ } else {
+ holder.itemView.setEnabled(true);
+ mPreference = holder.itemView;
+ if (mBackground == null) {
+ // store the original background.
+ mBackground = mPreference.getBackground();
+ }
+ if (!mShouldShowRippleOnDisabledPreference) {
+ ViewCompat.setBackground(mPreference, null);
+ } else if (mBackground != null) {
+ ViewCompat.setBackground(mPreference, mBackground);
+ }
+ enableView(holder.itemView, false, true);
+ }
+ }
+
+ private void enableView(View view, boolean enabled, boolean isRootView) {
+ if (!isRootView) {
+ view.setEnabled(enabled);
+ }
+ if (view instanceof ViewGroup) {
+ ViewGroup grp = (ViewGroup) view;
+ for (int index = 0; index < grp.getChildCount(); index++) {
+ enableView(grp.getChildAt(index), enabled, false);
+ }
+ }
}
@Override
@@ -80,7 +132,46 @@
}
}
+ /**
+ * This is similar to {@link Preference#performClick()} with the only difference that we do not
+ * return when view is not enabled.
+ */
+ @Override
+ public void performClick() {
+ if (isEnabled()) {
+ super.performClick();
+ } else if (mMessageToShowWhenDisabledPreferenceClicked != null
+ && !mMessageToShowWhenDisabledPreferenceClicked.isEmpty()) {
+ Toast toast = Toast.makeText(mContext, mMessageToShowWhenDisabledPreferenceClicked,
+ Toast.LENGTH_LONG);
+ toast.show();
+ }
+ }
+
public void setShowChevron(boolean showChevron) {
mShowChevron = showChevron;
}
+
+ /**
+ * Sets the ripple on the disabled preference.
+ */
+ public void setShouldShowRippleOnDisabledPreference(boolean showRipple) {
+ mShouldShowRippleOnDisabledPreference = showRipple;
+ updateRippleStateOnDisabledPreference();
+ }
+
+ private void updateRippleStateOnDisabledPreference() {
+ if (isEnabled()) {
+ return;
+ }
+ if (mShouldShowRippleOnDisabledPreference && mPreference != null) {
+ ViewCompat.setBackground(mPreference, mBackground);
+ } else if (mPreference != null) {
+ ViewCompat.setBackground(mPreference, null);
+ }
+ }
+
+ public void setMessageToShowWhenDisabledPreferenceClicked(String message) {
+ mMessageToShowWhenDisabledPreferenceClicked = message;
+ }
}
diff --git a/car-ui-lib/src/com/android/car/ui/preference/CarUiRadioButtonPreference.java b/car-ui-lib/src/com/android/car/ui/preference/CarUiRadioButtonPreference.java
new file mode 100644
index 0000000..288ec95
--- /dev/null
+++ b/car-ui-lib/src/com/android/car/ui/preference/CarUiRadioButtonPreference.java
@@ -0,0 +1,64 @@
+/*
+ * 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.car.ui.preference;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.RadioButton;
+
+import androidx.preference.PreferenceViewHolder;
+import androidx.preference.TwoStatePreference;
+
+import com.android.car.ui.R;
+
+/** A preference which shows a radio button at the start of the preference. */
+public class CarUiRadioButtonPreference extends TwoStatePreference {
+
+ public CarUiRadioButtonPreference(Context context, AttributeSet attrs,
+ int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ init();
+ }
+
+ public CarUiRadioButtonPreference(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init();
+ }
+
+ public CarUiRadioButtonPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+ public CarUiRadioButtonPreference(Context context) {
+ super(context);
+ init();
+ }
+
+ private void init() {
+ setLayoutResource(R.layout.car_ui_preference);
+ setWidgetLayoutResource(R.layout.car_ui_radio_button_preference_widget);
+ }
+
+ @Override
+ public void onBindViewHolder(PreferenceViewHolder holder) {
+ super.onBindViewHolder(holder);
+
+ RadioButton radioButton = (RadioButton) holder.findViewById(R.id.radio_button);
+ radioButton.setChecked(isChecked());
+ }
+}
diff --git a/car-ui-lib/src/com/android/car/ui/preference/CarUiSeekBarDialogPreference.java b/car-ui-lib/src/com/android/car/ui/preference/CarUiSeekBarDialogPreference.java
new file mode 100644
index 0000000..1f084cc
--- /dev/null
+++ b/car-ui-lib/src/com/android/car/ui/preference/CarUiSeekBarDialogPreference.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright 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.ui.preference;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.SeekBar;
+import android.widget.TextView;
+
+import androidx.preference.DialogPreference;
+
+import com.android.car.ui.R;
+
+/** A class implements some basic methods of a seekbar dialog preference. */
+public class CarUiSeekBarDialogPreference extends DialogPreference
+ implements IDialogFragmentCallbacks {
+
+ private int mSeekBarProgress;
+ private SeekBar mSeekBar;
+
+ private int mSeekBarTopTextViewVisibility;
+ private TextView mSeekBarTopTextView;
+ private String mSeekBarTopText;
+
+ private int mSeekBarLeftTextViewVisibility;
+ private TextView mSeekBarLeftTextView;
+ private String mSeekBarLeftText;
+
+ private int mSeekBarRightTextViewVisibility;
+ private TextView mSeekBarRightTextView;
+ private String mSeekBarRightText;
+
+ private SeekBar.OnSeekBarChangeListener mOnSeekBarChangeListener;
+ int mMaxProgress = 100;
+
+ public CarUiSeekBarDialogPreference(Context context, AttributeSet attrs,
+ int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ init(context);
+ }
+
+ public CarUiSeekBarDialogPreference(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init(context);
+ }
+
+ public CarUiSeekBarDialogPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init(context);
+ }
+
+ public CarUiSeekBarDialogPreference(Context context) {
+ super(context);
+ init(context);
+ }
+
+ private void init(Context context) {
+ setDialogLayoutResource(R.layout.car_ui_seekbar_dialog);
+ setPositiveButtonText(R.string.car_ui_dialog_preference_positive);
+ setNegativeButtonText(R.string.car_ui_dialog_preference_negative);
+ }
+
+ @Override
+ public void onAttached() {
+ super.onAttached();
+ mSeekBarProgress = getPersistedInt(0);
+ }
+
+ @Override
+ public void onBindDialogView(View view) {
+ mSeekBar = view.findViewById(R.id.seek_bar);
+ mSeekBarTopTextView = view.findViewById(R.id.seek_bar_text_top);
+ mSeekBarLeftTextView = view.findViewById(R.id.seek_bar_text_left);
+ mSeekBarRightTextView = view.findViewById(R.id.seek_bar_text_right);
+
+ setProgress(mSeekBarProgress);
+
+ setSeekBarTopTextViewVisibility(mSeekBarTopTextViewVisibility);
+ setSeekBarTopTextViewText(mSeekBarTopText);
+
+ setSeekBarLeftTextViewVisibility(mSeekBarLeftTextViewVisibility);
+ setSeekBarLeftTextViewText(mSeekBarLeftText);
+
+ setSeekBarRightTextViewVisibility(mSeekBarRightTextViewVisibility);
+ setSeekBarRightTextViewText(mSeekBarRightText);
+
+ setMaxProgress(mMaxProgress);
+ setOnSeekBarChangeListener(mOnSeekBarChangeListener);
+ }
+
+ /**
+ * Get the progress bar's current level of progress. Return 0 when the
+ * progress bar is in indeterminate mode.
+ */
+ public int getProgress() {
+ return mSeekBarProgress;
+ }
+
+ @Override
+ public void onDialogClosed(boolean positiveResult) {
+ if (positiveResult) {
+ mSeekBarProgress = mSeekBar.getProgress();
+ persistInt(mSeekBarProgress);
+ notifyChanged();
+ }
+
+ mSeekBarTopTextView = null;
+ mSeekBarRightTextView = null;
+ mSeekBarLeftTextView = null;
+ mSeekBar = null;
+ }
+
+ /**
+ * Sets the current progress to the specified value.
+ */
+ public void setProgress(int progress) {
+ if (mSeekBar != null) {
+ mSeekBar.setProgress(progress);
+ }
+ mSeekBarProgress = progress;
+ }
+
+ /**
+ * Sets the text view visibility on top of the seekbar.
+ */
+ public void setSeekBarTopTextViewVisibility(int visibility) {
+ if (mSeekBarTopTextView != null) {
+ mSeekBarTopTextView.setVisibility(visibility);
+ }
+ mSeekBarTopTextViewVisibility = visibility;
+ }
+
+ /**
+ * Sets the text on top of the seekbar.
+ */
+ public void setSeekBarTopTextViewText(String text) {
+ if (mSeekBarTopTextView != null) {
+ mSeekBarTopTextView.setText(text);
+ }
+ mSeekBarTopText = text;
+ }
+
+ /**
+ * Sets the text view visibility on left of the seekbar.
+ */
+ public void setSeekBarLeftTextViewVisibility(int visibility) {
+ if (mSeekBarLeftTextView != null) {
+ mSeekBarLeftTextView.setVisibility(visibility);
+ }
+ mSeekBarLeftTextViewVisibility = visibility;
+ }
+
+ /**
+ * Sets the text on Left of the seekbar.
+ */
+ public void setSeekBarLeftTextViewText(String text) {
+ if (mSeekBarLeftTextView != null) {
+ mSeekBarLeftTextView.setText(text);
+ }
+ mSeekBarLeftText = text;
+ }
+
+
+ /**
+ * Sets the text view visibility on right of the seekbar.
+ */
+ public void setSeekBarRightTextViewVisibility(int visibility) {
+ if (mSeekBarRightTextView != null) {
+ mSeekBarRightTextView.setVisibility(visibility);
+ }
+ mSeekBarRightTextViewVisibility = visibility;
+ }
+
+ /**
+ * Sets the text on right of the seekbar.
+ */
+ public void setSeekBarRightTextViewText(String text) {
+ if (mSeekBarRightTextView != null) {
+ mSeekBarRightTextView.setText(text);
+ }
+ mSeekBarRightText = text;
+ }
+
+ /**
+ * Sets a listener to receive notifications of changes to the SeekBar's progress level. Also
+ * provides notifications of when the user starts and stops a touch gesture within the SeekBar.
+ *
+ * @param listener The seek bar notification listener
+ * @see SeekBar.OnSeekBarChangeListener
+ */
+ public void setOnSeekBarChangeListener(SeekBar.OnSeekBarChangeListener listener) {
+ if (mSeekBar != null) {
+ mSeekBar.setOnSeekBarChangeListener(listener);
+ }
+ mOnSeekBarChangeListener = listener;
+ }
+
+ /** Set the upper range of the progress bar */
+ public void setMaxProgress(int maxProgress) {
+ if (mSeekBar != null) {
+ mSeekBar.setMax(maxProgress);
+ }
+ mMaxProgress = maxProgress;
+ }
+}
diff --git a/car-ui-lib/src/com/android/car/ui/preference/CarUiTwoActionPreference.java b/car-ui-lib/src/com/android/car/ui/preference/CarUiTwoActionPreference.java
new file mode 100644
index 0000000..a96cef1
--- /dev/null
+++ b/car-ui-lib/src/com/android/car/ui/preference/CarUiTwoActionPreference.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2018 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.ui.preference;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.view.View;
+
+import androidx.preference.PreferenceViewHolder;
+
+import com.android.car.ui.R;
+
+/**
+ * A preference which can perform two actions. The secondary action is shown by default.
+ * {@link #showAction(boolean)} may be used to manually set the visibility of the action.
+ */
+public class CarUiTwoActionPreference extends CarUiPreference {
+
+ private boolean mIsActionShown;
+
+ public CarUiTwoActionPreference(Context context, AttributeSet attrs,
+ int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ init(attrs);
+ }
+
+ public CarUiTwoActionPreference(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init(attrs);
+ }
+
+ public CarUiTwoActionPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init(attrs);
+ }
+
+ public CarUiTwoActionPreference(Context context) {
+ super(context);
+ init(/* attrs= */ null);
+ }
+
+ /**
+ * Sets the custom two action preference layout and attributes.
+ * Check {@link #setLayoutResource} for layout requirements.
+ */
+ private void init(AttributeSet attrs) {
+ setLayoutResource(R.layout.car_ui_two_action_preference);
+ TypedArray preferenceAttributes = getContext().obtainStyledAttributes(attrs,
+ R.styleable.CarUiTwoActionPreference);
+ mIsActionShown = preferenceAttributes.getBoolean(
+ R.styleable.CarUiTwoActionPreference_actionShown, true);
+ setShowChevron(false);
+ }
+
+ /**
+ * Sets whether the secondary action is visible in the preference.
+ *
+ * @param isShown {@code true} if the secondary action should be shown.
+ */
+ public void showAction(boolean isShown) {
+ mIsActionShown = isShown;
+ notifyChanged();
+ }
+
+ /** Returns {@code true} if action is shown. */
+ public boolean isActionShown() {
+ return mIsActionShown;
+ }
+
+ @Override
+ public void onBindViewHolder(PreferenceViewHolder holder) {
+ super.onBindViewHolder(holder);
+ View actionContainer = holder.findViewById(R.id.action_widget_container);
+ View widgetFrame = holder.findViewById(android.R.id.widget_frame);
+ if (mIsActionShown) {
+ actionContainer.setVisibility(View.VISIBLE);
+ onBindWidgetFrame(widgetFrame);
+ } else {
+ actionContainer.setVisibility(View.GONE);
+ }
+ }
+
+ /**
+ * Binds the created View for the second action.
+ *
+ * <p>This is a good place to set properties on any custom view.
+ *
+ * @param widgetFrame The widget frame which controls the 2nd action.
+ */
+ protected void onBindWidgetFrame(View widgetFrame) {
+ }
+}
diff --git a/car-ui-lib/src/com/android/car/ui/preference/IDialogFragmentCallbacks.java b/car-ui-lib/src/com/android/car/ui/preference/IDialogFragmentCallbacks.java
new file mode 100644
index 0000000..3e3efee
--- /dev/null
+++ b/car-ui-lib/src/com/android/car/ui/preference/IDialogFragmentCallbacks.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 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.ui.preference;
+
+import android.app.AlertDialog;
+import android.view.View;
+
+import androidx.preference.DialogPreference;
+
+/**
+ * Interface for preferences to handle their own dialogs.
+ *
+ * A {@link androidx.preference.Preference} should implement this, and its {@link DialogPreference}
+ * will call these methods on the Preference.
+ */
+public interface IDialogFragmentCallbacks {
+
+ /**
+ * @see CarUiDialogFragment#onPrepareDialogBuilder(AlertDialog.Builder)
+ */
+ default void onPrepareDialogBuilder(AlertDialog.Builder builder) {
+ }
+
+ /**
+ * @see CarUiDialogFragment#onDialogClosed(boolean)
+ */
+ default void onDialogClosed(boolean positiveResult) {
+ }
+
+ /**
+ * @see CarUiDialogFragment#onBindDialogView(View)
+ */
+ default void onBindDialogView(View view) {
+ }
+}
diff --git a/car-ui-lib/src/com/android/car/ui/preference/PreferenceFragment.java b/car-ui-lib/src/com/android/car/ui/preference/PreferenceFragment.java
index de25cf8..e828b63 100644
--- a/car-ui-lib/src/com/android/car/ui/preference/PreferenceFragment.java
+++ b/car-ui-lib/src/com/android/car/ui/preference/PreferenceFragment.java
@@ -119,6 +119,8 @@
f = ListPreferenceFragment.newInstance(preference.getKey());
} else if (preference instanceof MultiSelectListPreference) {
f = MultiSelectListPreferenceFragment.newInstance(preference.getKey());
+ } else if (preference instanceof CarUiSeekBarDialogPreference) {
+ f = SeekbarPreferenceDialogFragment.newInstance(preference.getKey());
} else {
throw new IllegalArgumentException(
"Cannot display dialog for an unknown Preference type: "
diff --git a/car-ui-lib/src/com/android/car/ui/preference/SeekbarPreferenceDialogFragment.java b/car-ui-lib/src/com/android/car/ui/preference/SeekbarPreferenceDialogFragment.java
new file mode 100644
index 0000000..7beea63
--- /dev/null
+++ b/car-ui-lib/src/com/android/car/ui/preference/SeekbarPreferenceDialogFragment.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 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.ui.preference;
+
+import android.app.AlertDialog;
+import android.os.Bundle;
+import android.view.View;
+
+/**
+ * A fragment that provides a layout with a seekbar within a dialog.
+ */
+public class SeekbarPreferenceDialogFragment extends PreferenceDialogFragment {
+
+ /**
+ * Returns a new instance of {@link SeekbarPreferenceDialogFragment} for the {@link
+ * CarUiSeekBarDialogPreference} with the given {@code key}.
+ */
+ public static SeekbarPreferenceDialogFragment newInstance(String key) {
+ SeekbarPreferenceDialogFragment fragment =
+ new SeekbarPreferenceDialogFragment();
+ Bundle b = new Bundle(/* capacity= */ 1);
+ b.putString(ARG_KEY, key);
+ fragment.setArguments(b);
+ return fragment;
+ }
+
+ @Override
+ protected void onBindDialogView(View view) {
+ super.onBindDialogView(view);
+
+ IDialogFragmentCallbacks dialogPreference = (IDialogFragmentCallbacks) getPreference();
+ dialogPreference.onBindDialogView(view);
+ }
+
+ @Override
+ protected void onDialogClosed(boolean positiveResult) {
+ IDialogFragmentCallbacks dialogPreference = (IDialogFragmentCallbacks) getPreference();
+ dialogPreference.onDialogClosed(positiveResult);
+ }
+
+ @Override
+ protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {
+ IDialogFragmentCallbacks dialogPreference = (IDialogFragmentCallbacks) getPreference();
+ dialogPreference.onPrepareDialogBuilder(builder);
+ }
+}
diff --git a/car-ui-lib/src/com/android/car/ui/recyclerview/CarUiContentListItem.java b/car-ui-lib/src/com/android/car/ui/recyclerview/CarUiContentListItem.java
index 88255c8..ee4e490 100644
--- a/car-ui-lib/src/com/android/car/ui/recyclerview/CarUiContentListItem.java
+++ b/car-ui-lib/src/com/android/car/ui/recyclerview/CarUiContentListItem.java
@@ -34,10 +34,22 @@
/**
* Called when the checked state of a list item has changed.
*
- * @param item The item whose checked state changed.
+ * @param item whose checked state changed.
* @param isChecked new checked state of list item.
*/
- void onCheckedChanged(CarUiContentListItem item, boolean isChecked);
+ void onCheckedChanged(@NonNull CarUiContentListItem item, boolean isChecked);
+ }
+
+ /**
+ * Callback to be invoked when an item is clicked.
+ */
+ public interface OnClickListener {
+ /**
+ * Called when the item has been clicked.
+ *
+ * @param item whose checked state changed.
+ */
+ void onClick(@NonNull CarUiContentListItem item);
}
public enum IconType {
@@ -93,6 +105,7 @@
private IconType mPrimaryIconType;
private boolean mIsActionDividerVisible;
private boolean mIsChecked;
+ private OnClickListener mOnClickListener;
private OnCheckedChangedListener mOnCheckedChangedListener;
private View.OnClickListener mSupplementalIconOnClickListener;
@@ -271,6 +284,20 @@
}
/**
+ * Registers a callback to be invoked when the item is clicked.
+ *
+ * @param listener callback to be invoked when item is clicked.
+ */
+ public void setOnItemClickedListener(@Nullable OnClickListener listener) {
+ mOnClickListener = listener;
+ }
+
+ @Nullable
+ OnClickListener getOnClickListener() {
+ return mOnClickListener;
+ }
+
+ /**
* Registers a callback to be invoked when the checked state of list item changes.
*
* <p>Checked state changes can take place when the action type is {@code Action.SWITCH} or
@@ -279,7 +306,7 @@
* @param listener callback to be invoked when the checked state shown in the UI changes.
*/
public void setOnCheckedChangedListener(
- @NonNull OnCheckedChangedListener listener) {
+ @Nullable OnCheckedChangedListener listener) {
mOnCheckedChangedListener = listener;
}
diff --git a/car-ui-lib/src/com/android/car/ui/recyclerview/CarUiListItemAdapter.java b/car-ui-lib/src/com/android/car/ui/recyclerview/CarUiListItemAdapter.java
index 865722c..765d21d 100644
--- a/car-ui-lib/src/com/android/car/ui/recyclerview/CarUiListItemAdapter.java
+++ b/car-ui-lib/src/com/android/car/ui/recyclerview/CarUiListItemAdapter.java
@@ -238,6 +238,8 @@
mRadioButton.setVisibility(View.GONE);
mSupplementalIcon.setVisibility(View.GONE);
+ CarUiContentListItem.OnClickListener itemOnClickListener = item.getOnClickListener();
+
switch (item.getAction()) {
case NONE:
mActionContainer.setVisibility(View.GONE);
@@ -245,6 +247,11 @@
// Display ripple effects across entire item when clicked by using full-sized
// touch interceptor.
mTouchInterceptor.setVisibility(View.VISIBLE);
+ mTouchInterceptor.setOnClickListener(v -> {
+ if (itemOnClickListener != null) {
+ itemOnClickListener.onClick(item);
+ }
+ });
mReducedTouchInterceptor.setVisibility(View.GONE);
mActionContainerTouchInterceptor.setVisibility(View.GONE);
break;
@@ -265,7 +272,12 @@
// Clicks anywhere on the item should toggle the switch state. Use full touch
// interceptor.
mTouchInterceptor.setVisibility(View.VISIBLE);
- mTouchInterceptor.setOnClickListener(v -> mSwitch.toggle());
+ mTouchInterceptor.setOnClickListener(v -> {
+ mSwitch.toggle();
+ if (itemOnClickListener != null) {
+ itemOnClickListener.onClick(item);
+ }
+ });
mReducedTouchInterceptor.setVisibility(View.GONE);
mActionContainerTouchInterceptor.setVisibility(View.GONE);
@@ -289,7 +301,12 @@
// Clicks anywhere on the item should toggle the checkbox state. Use full touch
// interceptor.
mTouchInterceptor.setVisibility(View.VISIBLE);
- mTouchInterceptor.setOnClickListener(v -> mCheckBox.toggle());
+ mTouchInterceptor.setOnClickListener(v -> {
+ mCheckBox.toggle();
+ if (itemOnClickListener != null) {
+ itemOnClickListener.onClick(item);
+ }
+ });
mReducedTouchInterceptor.setVisibility(View.GONE);
mActionContainerTouchInterceptor.setVisibility(View.GONE);
@@ -313,7 +330,12 @@
// Clicks anywhere on the item should toggle the switch state. Use full touch
// interceptor.
mTouchInterceptor.setVisibility(View.VISIBLE);
- mTouchInterceptor.setOnClickListener(v -> mRadioButton.toggle());
+ mTouchInterceptor.setOnClickListener(v -> {
+ mRadioButton.toggle();
+ if (itemOnClickListener != null) {
+ itemOnClickListener.onClick(item);
+ }
+ });
mReducedTouchInterceptor.setVisibility(View.GONE);
mActionContainerTouchInterceptor.setVisibility(View.GONE);
@@ -329,6 +351,9 @@
if (item.getSupplementalIconOnClickListener() != null) {
item.getSupplementalIconOnClickListener().onClick(mIcon);
}
+ if (itemOnClickListener != null) {
+ itemOnClickListener.onClick(item);
+ }
});
// If the icon has a click listener, use a reduced touch interceptor to create
@@ -337,11 +362,20 @@
// click listener, it shouldn't be clickable.
if (item.getSupplementalIconOnClickListener() == null) {
mTouchInterceptor.setVisibility(View.VISIBLE);
- mTouchInterceptor.setOnClickListener(null);
+ mTouchInterceptor.setOnClickListener(v -> {
+ if (itemOnClickListener != null) {
+ itemOnClickListener.onClick(item);
+ }
+ });
mReducedTouchInterceptor.setVisibility(View.GONE);
mActionContainerTouchInterceptor.setVisibility(View.GONE);
} else {
mReducedTouchInterceptor.setVisibility(View.VISIBLE);
+ mReducedTouchInterceptor.setOnClickListener(v -> {
+ if (itemOnClickListener != null) {
+ itemOnClickListener.onClick(item);
+ }
+ });
mActionContainerTouchInterceptor.setVisibility(View.VISIBLE);
mTouchInterceptor.setVisibility(View.GONE);
}
diff --git a/car-ui-lib/src/com/android/car/ui/toolbar/MenuItem.java b/car-ui-lib/src/com/android/car/ui/toolbar/MenuItem.java
index ef142ec..20d6847 100644
--- a/car-ui-lib/src/com/android/car/ui/toolbar/MenuItem.java
+++ b/car-ui-lib/src/com/android/car/ui/toolbar/MenuItem.java
@@ -309,8 +309,8 @@
public static final class Builder {
private final Context mContext;
- private CharSequence mSearchTitle;
- private CharSequence mSettingsTitle;
+ private String mSearchTitle;
+ private String mSettingsTitle;
private Drawable mSearchIcon;
private Drawable mSettingsIcon;
@@ -353,7 +353,7 @@
throw new IllegalStateException("Can't have both a search and settings MenuItem");
}
- if (mIsSearch && (!mSearchTitle.equals(mTitle)
+ if (mIsSearch && (!mSearchTitle.contentEquals(mTitle)
|| !mSearchIcon.equals(mIcon)
|| mIsCheckable
|| mIsActivatable
@@ -363,14 +363,13 @@
throw new IllegalStateException("Invalid search MenuItem");
}
- if (mIsSettings && (!mSettingsTitle.equals(mTitle)
+ if (mIsSettings && (!mSettingsTitle.contentEquals(mTitle)
|| !mSettingsIcon.equals(mIcon)
|| mIsCheckable
|| mIsActivatable
|| !mIsTinted
|| mShowIconAndTitle
- || mDisplayBehavior != DisplayBehavior.ALWAYS
- || mUxRestrictions != CarUxRestrictions.UX_RESTRICTIONS_NO_SETUP)) {
+ || mDisplayBehavior != DisplayBehavior.ALWAYS)) {
throw new IllegalStateException("Invalid settings MenuItem");
}
diff --git a/car-ui-lib/src/com/android/car/ui/toolbar/MenuItemRenderer.java b/car-ui-lib/src/com/android/car/ui/toolbar/MenuItemRenderer.java
index b6ba3fc..8f8ae33 100644
--- a/car-ui-lib/src/com/android/car/ui/toolbar/MenuItemRenderer.java
+++ b/car-ui-lib/src/com/android/car/ui/toolbar/MenuItemRenderer.java
@@ -32,6 +32,7 @@
import androidx.annotation.XmlRes;
import androidx.asynclayoutinflater.view.AsyncLayoutInflater;
+import androidx.core.util.Consumer;
import com.android.car.ui.R;
import com.android.car.ui.utils.CarUiUtils;
@@ -45,7 +46,6 @@
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
-import java.util.concurrent.CompletableFuture;
class MenuItemRenderer implements MenuItem.Listener {
@@ -90,8 +90,7 @@
updateView();
}
- CompletableFuture<View> createView() {
- CompletableFuture<View> future = new CompletableFuture<>();
+ void createView(Consumer<View> callback) {
AsyncLayoutInflater inflater = new AsyncLayoutInflater(mParentView.getContext());
inflater.inflate(R.layout.car_ui_toolbar_menu_item, mParentView, (View view, int resid,
ViewGroup parent) -> {
@@ -102,10 +101,8 @@
mTextView = mView.requireViewById(R.id.car_ui_toolbar_menu_item_text);
mTextWithIconView = mView.requireViewById(R.id.car_ui_toolbar_menu_item_text_with_icon);
updateView();
- future.complete(view);
+ callback.accept(mView);
});
-
- return future;
}
private void updateView() {
diff --git a/car-ui-lib/src/com/android/car/ui/toolbar/SearchView.java b/car-ui-lib/src/com/android/car/ui/toolbar/SearchView.java
index d7240eb..cf7a2fc 100644
--- a/car-ui-lib/src/com/android/car/ui/toolbar/SearchView.java
+++ b/car-ui-lib/src/com/android/car/ui/toolbar/SearchView.java
@@ -28,6 +28,7 @@
import android.widget.EditText;
import android.widget.ImageView;
+import androidx.annotation.NonNull;
import androidx.constraintlayout.widget.ConstraintLayout;
import com.android.car.ui.R;
@@ -95,6 +96,7 @@
mEndPadding = context.getResources().getDimensionPixelSize(
R.dimen.car_ui_toolbar_search_close_icon_container_width);
+ mSearchText.setSaveEnabled(false);
mSearchText.setPaddingRelative(mStartPadding, 0, mEndPadding, 0);
mSearchText.setOnFocusChangeListener(
@@ -120,20 +122,19 @@
});
}
+ private boolean mWasShown = false;
+
@Override
- public void setVisibility(int visibility) {
- boolean showing = visibility == View.VISIBLE && getVisibility() != View.VISIBLE;
+ public void onVisibilityChanged(@NonNull View changedView, int visibility) {
+ super.onVisibilityChanged(changedView, visibility);
- super.setVisibility(visibility);
-
- if (showing) {
- mSearchText.removeTextChangedListener(mTextWatcher);
- mSearchText.getText().clear();
- mSearchText.addTextChangedListener(mTextWatcher);
- mCloseIcon.setVisibility(View.GONE);
-
+ boolean isShown = isShown();
+ if (isShown && !mWasShown) {
+ boolean hasQuery = mSearchText.getText().length() > 0;
+ mCloseIcon.setVisibility(hasQuery ? View.VISIBLE : View.GONE);
mSearchText.requestFocus();
}
+ mWasShown = isShown;
}
/**
diff --git a/car-ui-lib/src/com/android/car/ui/toolbar/TabLayout.java b/car-ui-lib/src/com/android/car/ui/toolbar/TabLayout.java
index b30c370..2f56c13 100644
--- a/car-ui-lib/src/com/android/car/ui/toolbar/TabLayout.java
+++ b/car-ui-lib/src/com/android/car/ui/toolbar/TabLayout.java
@@ -77,9 +77,6 @@
}
}
- // View attributes
- private final boolean mTabFlexibleLayout;
-
private final Set<Listener> mListeners = new ArraySet<>();
private final TabAdapter mTabAdapter;
@@ -96,9 +93,11 @@
super(context, attrs, defStyle);
Resources resources = context.getResources();
- mTabFlexibleLayout = resources.getBoolean(R.bool.car_ui_toolbar_tab_flexible_layout);
-
- mTabAdapter = new TabAdapter(context, R.layout.car_ui_toolbar_tab_item_layout, this);
+ boolean tabFlexibleLayout = resources.getBoolean(R.bool.car_ui_toolbar_tab_flexible_layout);
+ @LayoutRes int tabLayoutRes = tabFlexibleLayout
+ ? R.layout.car_ui_toolbar_tab_item_layout_flexible
+ : R.layout.car_ui_toolbar_tab_item_layout;
+ mTabAdapter = new TabAdapter(context, tabLayoutRes, this);
}
/**
@@ -172,15 +171,7 @@
}
private void addTabView(View tabView, int position) {
- LayoutParams layoutParams;
- if (mTabFlexibleLayout) {
- layoutParams = new LayoutParams(0, ViewGroup.LayoutParams.MATCH_PARENT);
- layoutParams.weight = 1;
- } else {
- layoutParams = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
- ViewGroup.LayoutParams.MATCH_PARENT);
- }
- addView(tabView, position, layoutParams);
+ addView(tabView, position);
}
private static class TabAdapter extends BaseAdapter {
diff --git a/car-ui-lib/src/com/android/car/ui/toolbar/Toolbar.java b/car-ui-lib/src/com/android/car/ui/toolbar/Toolbar.java
index 3ad5704..a999d9b 100644
--- a/car-ui-lib/src/com/android/car/ui/toolbar/Toolbar.java
+++ b/car-ui-lib/src/com/android/car/ui/toolbar/Toolbar.java
@@ -48,7 +48,7 @@
import java.util.List;
import java.util.Objects;
import java.util.Set;
-import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.atomic.AtomicInteger;
/**
* A toolbar for Android Automotive OS apps.
@@ -167,7 +167,7 @@
private List<MenuItem> mMenuItems = Collections.emptyList();
private List<MenuItem> mOverflowItems = new ArrayList<>();
private final List<MenuItemRenderer> mMenuItemRenderers = new ArrayList<>();
- private CompletableFuture<Void> mMenuItemViewsFuture;
+ private View[] mMenuItemViews;
private int mMenuItemsXmlId = 0;
private AlertDialog mOverflowDialog;
private boolean mNavIconSpaceReserved;
@@ -460,11 +460,9 @@
/** Sets the hint for the search bar. */
public void setSearchHint(CharSequence hint) {
- if (!Objects.equals(hint, mSearchHint)) {
- mSearchHint = hint;
- if (mSearchView != null) {
- mSearchView.setHint(mSearchHint);
- }
+ mSearchHint = hint;
+ if (mSearchView != null) {
+ mSearchView.setHint(mSearchHint);
}
}
@@ -553,50 +551,61 @@
items = Collections.emptyList();
}
- if (items.equals(mMenuItems)) {
- return;
- }
+ List<MenuItem> visibleMenuItems = new ArrayList<>();
+ List<MenuItem> overflowItems = new ArrayList<>();
+ AtomicInteger loadedMenuItems = new AtomicInteger(0);
- // Copy the list so that if the list is modified and setMenuItems is called again,
- // the equals() check will fail. Note that the MenuItems are not copied here.
- mMenuItems = new ArrayList<>(items);
+ synchronized (this) {
+ if (items.equals(mMenuItems)) {
+ return;
+ }
- mOverflowItems.clear();
- mMenuItemRenderers.clear();
- mMenuItemsContainer.removeAllViews();
+ for (MenuItem item : items) {
+ if (item.getDisplayBehavior() == MenuItem.DisplayBehavior.NEVER) {
+ overflowItems.add(item);
+ item.setListener(mOverflowItemListener);
+ } else {
+ visibleMenuItems.add(item);
+ }
+ }
- List<CompletableFuture<View>> viewFutures = new ArrayList<>();
- for (MenuItem item : mMenuItems) {
- if (item.getDisplayBehavior() == MenuItem.DisplayBehavior.NEVER) {
- mOverflowItems.add(item);
- item.setListener(mOverflowItemListener);
- } else {
+ // Copy the list so that if the list is modified and setMenuItems is called again,
+ // the equals() check will fail. Note that the MenuItems are not copied here.
+ mMenuItems = new ArrayList<>(items);
+ mOverflowItems = overflowItems;
+ mMenuItemRenderers.clear();
+ mMenuItemsContainer.removeAllViews();
+
+ if (!overflowItems.isEmpty()) {
+ visibleMenuItems.add(mOverflowButton);
+ createOverflowDialog();
+ }
+
+ View[] menuItemViews = new View[visibleMenuItems.size()];
+ mMenuItemViews = menuItemViews;
+
+ for (int i = 0; i < visibleMenuItems.size(); ++i) {
+ int index = i;
+ MenuItem item = visibleMenuItems.get(i);
MenuItemRenderer renderer = new MenuItemRenderer(item, mMenuItemsContainer);
mMenuItemRenderers.add(renderer);
- viewFutures.add(renderer.createView());
+ renderer.createView(view -> {
+ synchronized (Toolbar.this) {
+ if (menuItemViews != mMenuItemViews) {
+ return;
+ }
+
+ menuItemViews[index] = view;
+ if (loadedMenuItems.addAndGet(1) == menuItemViews.length) {
+ for (View v : menuItemViews) {
+ mMenuItemsContainer.addView(v);
+ }
+ }
+ }
+ });
}
}
- if (!mOverflowItems.isEmpty()) {
- MenuItemRenderer renderer = new MenuItemRenderer(mOverflowButton, mMenuItemsContainer);
- mMenuItemRenderers.add(renderer);
- viewFutures.add(renderer.createView());
- createOverflowDialog();
- }
-
- if (mMenuItemViewsFuture != null) {
- mMenuItemViewsFuture.cancel(false);
- }
-
- mMenuItemViewsFuture = CompletableFuture.allOf(
- viewFutures.toArray(new CompletableFuture[0]));
- mMenuItemViewsFuture.thenRunAsync(() -> {
- for (CompletableFuture<View> future : viewFutures) {
- mMenuItemsContainer.addView(future.join());
- }
- mMenuItemViewsFuture = null;
- }, getContext().getMainExecutor());
-
setState(mState);
}
@@ -729,14 +738,12 @@
* Sets the search query.
*/
public void setSearchQuery(String query) {
- if (!Objects.equals(mSearchQuery, query)) {
+ if (mSearchView != null) {
+ mSearchView.setSearchQuery(query);
+ } else {
mSearchQuery = query;
- if (mSearchView != null) {
- mSearchView.setSearchQuery(query);
- } else {
- for (OnSearchListener listener : mOnSearchListeners) {
- listener.onSearch(query);
- }
+ for (OnSearchListener listener : mOnSearchListeners) {
+ listener.onSearch(query);
}
}
}
@@ -752,9 +759,9 @@
SearchView searchView = new SearchView(getContext());
searchView.setHint(mSearchHint);
searchView.setIcon(mSearchIcon);
+ searchView.setSearchQuery(mSearchQuery);
searchView.setSearchListeners(mOnSearchListeners);
searchView.setSearchCompletedListeners(mOnSearchCompletedListeners);
- searchView.setSearchQuery(mSearchQuery);
searchView.setVisibility(View.GONE);
FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(
diff --git a/car-ui-lib/tests/apitest/current.xml b/car-ui-lib/tests/apitest/current.xml
index d29307a..7e24e4d 100644
--- a/car-ui-lib/tests/apitest/current.xml
+++ b/car-ui-lib/tests/apitest/current.xml
@@ -17,16 +17,10 @@
<public type="bool" name="car_ui_toolbar_tabs_on_second_row"/>
<public type="color" name="car_ui_activity_background_color"/>
<public type="color" name="car_ui_color_accent"/>
- <public type="color" name="car_ui_list_item_body_text_color"/>
+ <public type="color" name="car_ui_dialog_icon_color"/>
<public type="color" name="car_ui_list_item_divider"/>
- <public type="color" name="car_ui_list_item_header_text_color"/>
- <public type="color" name="car_ui_list_item_title_text_color"/>
- <public type="color" name="car_ui_preference_category_title_text_color"/>
- <public type="color" name="car_ui_preference_edit_text_dialog_message_text_color"/>
<public type="color" name="car_ui_preference_icon_color"/>
- <public type="color" name="car_ui_preference_summary_text_color"/>
- <public type="color" name="car_ui_preference_switch_track_text_color"/>
- <public type="color" name="car_ui_preference_title_text_color"/>
+ <public type="color" name="car_ui_preference_two_action_divider_color"/>
<public type="color" name="car_ui_recyclerview_divider_color"/>
<public type="color" name="car_ui_ripple_color"/>
<public type="color" name="car_ui_scrollbar_thumb"/>
@@ -51,17 +45,15 @@
<public type="dimen" name="car_ui_dialog_edittext_margin_top"/>
<public type="dimen" name="car_ui_dialog_icon_size"/>
<public type="dimen" name="car_ui_dialog_title_margin"/>
+ <public type="dimen" name="car_ui_divider_width"/>
<public type="dimen" name="car_ui_keyline_1"/>
<public type="dimen" name="car_ui_keyline_2"/>
<public type="dimen" name="car_ui_keyline_3"/>
<public type="dimen" name="car_ui_keyline_4"/>
- <public type="dimen" name="car_ui_letter_spacing_body1"/>
- <public type="dimen" name="car_ui_letter_spacing_body3"/>
<public type="dimen" name="car_ui_list_item_action_divider_height"/>
<public type="dimen" name="car_ui_list_item_action_divider_width"/>
<public type="dimen" name="car_ui_list_item_avatar_icon_height"/>
<public type="dimen" name="car_ui_list_item_avatar_icon_width"/>
- <public type="dimen" name="car_ui_list_item_body_text_size"/>
<public type="dimen" name="car_ui_list_item_check_box_end_inset"/>
<public type="dimen" name="car_ui_list_item_check_box_height"/>
<public type="dimen" name="car_ui_list_item_check_box_icon_container_width"/>
@@ -71,7 +63,6 @@
<public type="dimen" name="car_ui_list_item_end_inset"/>
<public type="dimen" name="car_ui_list_item_header_height"/>
<public type="dimen" name="car_ui_list_item_header_start_inset"/>
- <public type="dimen" name="car_ui_list_item_header_text_size"/>
<public type="dimen" name="car_ui_list_item_height"/>
<public type="dimen" name="car_ui_list_item_icon_container_width"/>
<public type="dimen" name="car_ui_list_item_icon_size"/>
@@ -83,7 +74,6 @@
<public type="dimen" name="car_ui_list_item_supplemental_icon_size"/>
<public type="dimen" name="car_ui_list_item_text_no_icon_start_margin"/>
<public type="dimen" name="car_ui_list_item_text_start_margin"/>
- <public type="dimen" name="car_ui_list_item_title_text_size"/>
<public type="dimen" name="car_ui_margin"/>
<public type="dimen" name="car_ui_padding_0"/>
<public type="dimen" name="car_ui_padding_1"/>
@@ -95,7 +85,6 @@
<public type="dimen" name="car_ui_preference_category_icon_margin_end"/>
<public type="dimen" name="car_ui_preference_category_icon_size"/>
<public type="dimen" name="car_ui_preference_category_min_height"/>
- <public type="dimen" name="car_ui_preference_category_text_size"/>
<public type="dimen" name="car_ui_preference_content_margin_bottom"/>
<public type="dimen" name="car_ui_preference_content_margin_top"/>
<public type="dimen" name="car_ui_preference_dropdown_padding_start"/>
@@ -104,17 +93,10 @@
<public type="dimen" name="car_ui_preference_edit_text_dialog_message_margin_bottom"/>
<public type="dimen" name="car_ui_preference_edit_text_dialog_message_margin_end"/>
<public type="dimen" name="car_ui_preference_edit_text_dialog_message_margin_start"/>
- <public type="dimen" name="car_ui_preference_edit_text_dialog_message_text_size"/>
<public type="dimen" name="car_ui_preference_edit_text_dialog_text_margin_end"/>
<public type="dimen" name="car_ui_preference_edit_text_dialog_text_margin_start"/>
<public type="dimen" name="car_ui_preference_icon_margin_end"/>
<public type="dimen" name="car_ui_preference_icon_size"/>
- <public type="dimen" name="car_ui_preference_summary_text_size"/>
- <public type="dimen" name="car_ui_preference_switch_height"/>
- <public type="dimen" name="car_ui_preference_switch_text_size"/>
- <public type="dimen" name="car_ui_preference_switch_width"/>
- <public type="dimen" name="car_ui_preference_switch_width_half"/>
- <public type="dimen" name="car_ui_preference_title_text_size"/>
<public type="dimen" name="car_ui_primary_icon_size"/>
<public type="dimen" name="car_ui_recyclerview_divider_bottom_margin"/>
<public type="dimen" name="car_ui_recyclerview_divider_end_margin"/>
@@ -164,10 +146,12 @@
<public type="dimen" name="wrap_content"/>
<public type="drawable" name="car_ui_activity_background"/>
<public type="drawable" name="car_ui_divider"/>
+ <public type="drawable" name="car_ui_icon_add"/>
<public type="drawable" name="car_ui_icon_arrow_back"/>
<public type="drawable" name="car_ui_icon_close"/>
<public type="drawable" name="car_ui_icon_down"/>
<public type="drawable" name="car_ui_icon_overflow_menu"/>
+ <public type="drawable" name="car_ui_icon_save"/>
<public type="drawable" name="car_ui_icon_search"/>
<public type="drawable" name="car_ui_icon_search_nav_icon"/>
<public type="drawable" name="car_ui_icon_settings"/>
@@ -197,8 +181,6 @@
<public type="string" name="car_ui_dialog_preference_negative"/>
<public type="string" name="car_ui_dialog_preference_positive"/>
<public type="string" name="car_ui_ellipsis"/>
- <public type="string" name="car_ui_list_item_header_font_family"/>
- <public type="string" name="car_ui_preference_category_title_font_family"/>
<public type="string" name="car_ui_preference_switch_off"/>
<public type="string" name="car_ui_preference_switch_on"/>
<public type="string" name="car_ui_restricted_while_driving"/>
@@ -215,6 +197,12 @@
<public type="style" name="Preference.CarUi.CheckBoxPreference"/>
<public type="style" name="Preference.CarUi.DialogPreference"/>
<public type="style" name="Preference.CarUi.DialogPreference.EditTextPreference"/>
+ <public type="style" name="Preference.CarUi.DialogSeekBarPreference"/>
+ <public type="style" name="Preference.CarUi.DialogSeekBarPreference.LeftText"/>
+ <public type="style" name="Preference.CarUi.DialogSeekBarPreference.RightText"/>
+ <public type="style" name="Preference.CarUi.DialogSeekBarPreference.Seekbar"/>
+ <public type="style" name="Preference.CarUi.DialogSeekBarPreference.TopText"/>
+ <public type="style" name="Preference.CarUi.Divider"/>
<public type="style" name="Preference.CarUi.DropDown"/>
<public type="style" name="Preference.CarUi.Icon"/>
<public type="style" name="Preference.CarUi.Information"/>
@@ -226,6 +214,8 @@
<public type="style" name="PreferenceFragmentList.CarUi"/>
<public type="style" name="TextAppearance.CarUi"/>
<public type="style" name="TextAppearance.CarUi.AlertDialog.Subtitle"/>
+ <public type="style" name="TextAppearance.CarUi.Body1"/>
+ <public type="style" name="TextAppearance.CarUi.Body3"/>
<public type="style" name="TextAppearance.CarUi.ListItem"/>
<public type="style" name="TextAppearance.CarUi.ListItem.Body"/>
<public type="style" name="TextAppearance.CarUi.ListItem.Header"/>
diff --git a/car-ui-lib/tests/paintbooth/Android.bp b/car-ui-lib/tests/paintbooth/Android.bp
index c8ced10..bd9ed79 100644
--- a/car-ui-lib/tests/paintbooth/Android.bp
+++ b/car-ui-lib/tests/paintbooth/Android.bp
@@ -19,12 +19,15 @@
srcs: ["src/**/*.java"],
- resource_dirs: ["res"],
+ required: ["privapp_whitelist_com.android.car.ui.paintbooth"],
+
+ resource_dirs: ["res", "res-public"],
platform_apis: true,
certificate: "platform",
+ privileged: true,
static_libs: [
"car-ui-lib",
@@ -44,4 +47,5 @@
enabled: false,
},
},
+ export_package_resources: true,
}
diff --git a/car-ui-lib/tests/paintbooth/AndroidManifest-gradle.xml b/car-ui-lib/tests/paintbooth/AndroidManifest-gradle.xml
index e16428f..db91b77 100644
--- a/car-ui-lib/tests/paintbooth/AndroidManifest-gradle.xml
+++ b/car-ui-lib/tests/paintbooth/AndroidManifest-gradle.xml
@@ -40,10 +40,6 @@
android:exported="false"
android:parentActivityName=".MainActivity"/>
<activity
- android:name=".caruirecyclerview.CarUiListItemActivity"
- android:exported="false"
- android:parentActivityName=".MainActivity"/>
- <activity
android:name=".caruirecyclerview.GridCarUiRecyclerViewActivity"
android:exported="false"
android:parentActivityName=".MainActivity"/>
@@ -57,5 +53,32 @@
android:parentActivityName=".MainActivity">
<meta-data android:name="distractionOptimized" android:value="true"/>
</activity>
+ <activity
+ android:name=".overlays.OverlayActivity"
+ android:exported="false"
+ android:parentActivityName=".MainActivity">
+ <meta-data android:name="distractionOptimized" android:value="true"/>
+ </activity>
+ <activity
+ android:name=".widgets.WidgetActivity"
+ android:exported="false"
+ android:parentActivityName=".MainActivity"/>
+ <activity
+ android:name=".caruirecyclerview.CarUiListItemActivity"
+ android:exported="false"
+ android:parentActivityName=".MainActivity"/>
+
+
+ <service
+ android:label="Current Activity Service"
+ android:name=".currentactivity.CurrentActivityService"
+ android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
+ <intent-filter>
+ <action android:name="android.accessibilityservice.AccessibilityService"/>
+ </intent-filter>
+ <meta-data
+ android:name="android.accessibilityservice"
+ android:resource="@xml/current_activity_service"/>
+ </service>
</application>
</manifest>
diff --git a/car-ui-lib/tests/paintbooth/AndroidManifest.xml b/car-ui-lib/tests/paintbooth/AndroidManifest.xml
index ca7dec7..fe8929a 100644
--- a/car-ui-lib/tests/paintbooth/AndroidManifest.xml
+++ b/car-ui-lib/tests/paintbooth/AndroidManifest.xml
@@ -26,6 +26,12 @@
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"/>
<uses-permission android:name="android.permission.CHANGE_OVERLAY_PACKAGES"/>
<uses-permission android:name="android.permission.MANAGE_USERS"/>
+ <!-- Required to use the TYPE_DISPLAY_OVERLAY layout param for the current activity overlay -->
+ <uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW" />
+ <!-- Required for listening to android task stack changes -->
+ <uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS" />
+ <uses-permission android:name="android.permission.REAL_GET_TASKS" />
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<application
android:icon="@drawable/ic_launcher"
@@ -76,5 +82,15 @@
android:name=".caruirecyclerview.CarUiListItemActivity"
android:exported="false"
android:parentActivityName=".MainActivity"/>
+
+ <service
+ android:label="Current Activity Service"
+ android:exported="false"
+ android:name=".currentactivity.CurrentActivityService">
+ <intent-filter>
+ <action android:name="com.android.car.ui.paintbooth.StopService" />
+ </intent-filter>
+ </service>
+
</application>
</manifest>
diff --git a/car-ui-lib/tests/paintbooth/build.gradle b/car-ui-lib/tests/paintbooth/build.gradle
index 0ef3514..2891586 100644
--- a/car-ui-lib/tests/paintbooth/build.gradle
+++ b/car-ui-lib/tests/paintbooth/build.gradle
@@ -36,9 +36,12 @@
manifest.srcFile 'AndroidManifest-gradle.xml'
java {
srcDirs = ['src']
- filter.excludes = ["com/android/car/ui/paintbooth/overlays/OverlayManagerImpl.java"]
+ filter.excludes = [
+ "com/android/car/ui/paintbooth/overlays/OverlayManagerImpl.java",
+ "com/android/car/ui/paintbooth/currentactivity/ActivityTaskManagerImpl.java",
+ ]
}
- res.srcDirs = ['res']
+ res.srcDirs = ['res', 'res-public']
}
}
}
diff --git a/car-ui-lib/tests/paintbooth/res-public/values/public.xml b/car-ui-lib/tests/paintbooth/res-public/values/public.xml
new file mode 100644
index 0000000..5f00a8e
--- /dev/null
+++ b/car-ui-lib/tests/paintbooth/res-public/values/public.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <public type="color" name="dialog_activity_background_color" id="0x7f050040" />
+</resources>
\ No newline at end of file
diff --git a/car-ui-lib/tests/paintbooth/res/drawable/ic_settings_gear.xml b/car-ui-lib/tests/paintbooth/res/drawable/ic_settings_gear.xml
new file mode 100644
index 0000000..d1557f4
--- /dev/null
+++ b/car-ui-lib/tests/paintbooth/res/drawable/ic_settings_gear.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2017 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.
+-->
+
+<vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportHeight="48.0"
+ android:viewportWidth="48.0">
+ <path
+ android:fillColor="#fff"
+ android:pathData="M38.86,25.95c0.08,-0.64 0.14,-1.29 0.14,-1.95s-0.06,-1.31 -0.14,-1.95l4.23,-3.31c0.38,-0.3 0.49,-0.84 0.24,-1.28l-4,-6.93c-0.25,-0.43 -0.77,-0.61 -1.22,-0.43l-4.98,2.01c-1.03,-0.79 -2.16,-1.46 -3.38,-1.97L29,4.84c-0.09,-0.47 -0.5,-0.84 -1,-0.84h-8c-0.5,0 -0.91,0.37 -0.99,0.84l-0.75,5.3c-1.22,0.51 -2.35,1.17 -3.38,1.97L9.9,10.1c-0.45,-0.17 -0.97,0 -1.22,0.43l-4,6.93c-0.25,0.43 -0.14,0.97 0.24,1.28l4.22,3.31C9.06,22.69 9,23.34 9,24s0.06,1.31 0.14,1.95l-4.22,3.31c-0.38,0.3 -0.49,0.84 -0.24,1.28l4,6.93c0.25,0.43 0.77,0.61 1.22,0.43l4.98,-2.01c1.03,0.79 2.16,1.46 3.38,1.97l0.75,5.3c0.08,0.47 0.49,0.84 0.99,0.84h8c0.5,0 0.91,-0.37 0.99,-0.84l0.75,-5.3c1.22,-0.51 2.35,-1.17 3.38,-1.97l4.98,2.01c0.45,0.17 0.97,0 1.22,-0.43l4,-6.93c0.25,-0.43 0.14,-0.97 -0.24,-1.28l-4.22,-3.31zM24,31c-3.87,0 -7,-3.13 -7,-7s3.13,-7 7,-7 7,3.13 7,7 -3.13,7 -7,7z"/>
+</vector>
diff --git a/car-settings-lib/tests/robotests/AndroidManifest.xml b/car-ui-lib/tests/paintbooth/res/layout/details_preference_widget.xml
similarity index 67%
rename from car-settings-lib/tests/robotests/AndroidManifest.xml
rename to car-ui-lib/tests/paintbooth/res/layout/details_preference_widget.xml
index dd1a985..4f9fc41 100644
--- a/car-settings-lib/tests/robotests/AndroidManifest.xml
+++ b/car-ui-lib/tests/paintbooth/res/layout/details_preference_widget.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (C) 2018 Google Inc.
+ Copyright 2018 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.
@@ -15,7 +15,9 @@
limitations under the License.
-->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.car.settingslib.robotests">
-
-</manifest>
+<ImageView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:src="@drawable/ic_settings_gear"/>
diff --git a/car-ui-lib/tests/paintbooth/res/layout/list_item_switch.xml b/car-ui-lib/tests/paintbooth/res/layout/list_item_switch.xml
new file mode 100644
index 0000000..499f3e4
--- /dev/null
+++ b/car-ui-lib/tests/paintbooth/res/layout/list_item_switch.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright 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.
+ -->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <Switch
+ android:id="@+id/button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true"
+ android:textSize="25sp"
+ android:layout_marginTop="20dp"/>
+</RelativeLayout>
diff --git a/car-ui-lib/tests/paintbooth/res/values/overlayable.xml b/car-ui-lib/tests/paintbooth/res/values/overlayable.xml
new file mode 100644
index 0000000..7e62819
--- /dev/null
+++ b/car-ui-lib/tests/paintbooth/res/values/overlayable.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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.
+-->
+
+<resources>
+ <overlayable name="MyOverlayableResources">
+ <policy type="public">
+ <item type="drawable" name="ic_launcher" />
+ <item type="string" name="app_name" />
+ <item type="layout" name="main_activity" />
+ <item type="id" name="home" />
+ <item type="id" name="toolbar" />
+ <item type="id" name="activities" />
+ <item type="attr" name="title" />
+ <item type="attr" name="logo" />
+ <item type="attr" name="layout_constraintTop_toTopOf" />
+ <item type="attr" name="layout_constraintTop_toBottomOf" />
+ <item type="attr" name="layout_constraintLeft_toLeftOf" />
+ <item type="attr" name="layout_constraintBottom_toTopOf" />
+ <item type="attr" name="layout_constraintBottom_toBottomOf" />
+ <item type="attr" name="layout_constraintRight_toRightOf" />
+ <item type="attr" name="numOfColumns" />
+ <item type="attr" name="layoutStyle" />
+ </policy>
+ </overlayable>
+</resources>
\ No newline at end of file
diff --git a/car-ui-lib/tests/paintbooth/res/values/strings.xml b/car-ui-lib/tests/paintbooth/res/values/strings.xml
index 1022731..8ab0a68 100644
--- a/car-ui-lib/tests/paintbooth/res/values/strings.xml
+++ b/car-ui-lib/tests/paintbooth/res/values/strings.xml
@@ -18,6 +18,9 @@
<!-- Application name [CHAR LIMIT=30] -->
<string name="app_name" translatable="false">Paint Booth (Gerrit)</string>
+ <!-- Description of the CurrentActivityService. [CHAR_LIMIT=200] -->
+ <string name="current_activity_service_description">Shows the current activity</string>
+
<!-- Strings for Preference Samples -->
<eat-comment/>
@@ -56,6 +59,11 @@
<!-- Category title for preferences with widgets [CHAR_LIMIT=12]-->
<string name="widgets">Widgets</string>
+ <!-- Title of a two action preference [CHAR_LIMIT=31]-->
+ <string name="title_twoaction_preference">TwoAction preference</string>
+ <!-- Summary of a two action preference [CHAR_LIMIT=70]-->
+ <string name="summary_twoaction_preference">A widget should be visible on the right</string>
+
<!-- Title of a checkbox preference [CHAR_LIMIT=31]-->
<string name="title_checkbox_preference">Checkbox preference</string>
<!-- Summary of a checkbox preference [CHAR_LIMIT=78]-->
@@ -71,6 +79,8 @@
<!-- Title of a seekbar preference [CHAR_LIMIT=30]-->
<string name="title_seekbar_preference">Seekbar preference</string>
+ <!-- Summary of an seekbar preference [CHAR_LIMIT=32]-->
+ <string name="summary_seekbar_preference">Seekbar summary</string>
<!--This section is for preferences that launch a dialog to edit the preference -->
<eat-comment/>
@@ -254,5 +264,5 @@
<string name="widget_checkbox_text">I\'m a check box</string>
<!-- Text for switch [CHAR_LIMIT=25]-->
<string name="widget_switch_text">I\'m a switch</string>
-
+
</resources>
diff --git a/car-ui-lib/tests/paintbooth/res/xml/current_activity_service.xml b/car-ui-lib/tests/paintbooth/res/xml/current_activity_service.xml
new file mode 100644
index 0000000..f6143cd
--- /dev/null
+++ b/car-ui-lib/tests/paintbooth/res/xml/current_activity_service.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<accessibility-service
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:accessibilityEventTypes="typeWindowStateChanged"
+ android:accessibilityFeedbackType="feedbackGeneric"
+ android:accessibilityFlags="flagIncludeNotImportantViews"
+ android:description="@string/current_activity_service_description"/>
diff --git a/car-ui-lib/tests/paintbooth/res/xml/preference_samples.xml b/car-ui-lib/tests/paintbooth/res/xml/preference_samples.xml
index b49dd0d..0a0836a 100644
--- a/car-ui-lib/tests/paintbooth/res/xml/preference_samples.xml
+++ b/car-ui-lib/tests/paintbooth/res/xml/preference_samples.xml
@@ -19,132 +19,155 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
app:title="@string/preferences_screen_title">
- <PreferenceCategory
- android:title="@string/basic_preferences">
+ <PreferenceCategory
+ android:title="@string/basic_preferences">
- <Preference
- android:key="preference"
- android:title="@string/title_basic_preference"
- android:summary="@string/summary_basic_preference"/>
+ <Preference
+ android:key="preference"
+ android:summary="@string/summary_basic_preference"
+ android:title="@string/title_basic_preference"/>
- <Preference
- android:key="stylized"
- android:title="@string/title_stylish_preference"
- android:summary="@string/summary_stylish_preference"/>
+ <Preference
+ android:key="preference_disabled_without_ripple"
+ android:summary="Without ripple"
+ android:title="@string/title_basic_preference"/>
- <Preference
- android:key="icon"
- android:title="@string/title_icon_preference"
- android:summary="@string/summary_icon_preference"
- android:icon="@drawable/ic_settings_wifi"/>
+ <Preference
+ android:key="preference_disabled_with_ripple"
+ android:summary="With ripple"
+ android:title="@string/title_basic_preference"/>
- <Preference
- android:key="single_line_title"
- android:title="@string/title_single_line_title_preference"
- android:summary="@string/summary_single_line_title_preference"
- app:singleLineTitle="true"/>
+ <Preference
+ android:key="stylized"
+ android:dependency="preference"
+ android:summary="@string/summary_stylish_preference"
+ android:title="@string/title_stylish_preference"/>
- <Preference
- android:key="single_line_no_summary"
- android:title="@string/title_single_line_no_summary"
- app:singleLineTitle="true"/>
- </PreferenceCategory>
+ <Preference
+ android:icon="@drawable/ic_settings_wifi"
+ android:key="icon"
+ android:summary="@string/summary_icon_preference"
+ android:title="@string/title_icon_preference"/>
- <PreferenceCategory
- android:title="@string/widgets">
+ <Preference
+ android:key="single_line_title"
+ android:summary="@string/summary_single_line_title_preference"
+ android:title="@string/title_single_line_title_preference"
+ app:singleLineTitle="true"/>
- <CheckBoxPreference
- android:key="checkbox"
- android:title="@string/title_checkbox_preference"
- android:summary="@string/summary_checkbox_preference"/>
+ <Preference
+ android:key="single_line_no_summary"
+ android:title="@string/title_single_line_no_summary"
+ app:singleLineTitle="true"/>
+ </PreferenceCategory>
- <SwitchPreference
- android:key="switch"
- android:title="@string/title_switch_preference"
- android:summary="@string/summary_switch_preference"/>
+ <PreferenceCategory
+ android:title="@string/widgets">
- <DropDownPreference
- android:key="dropdown"
- android:title="@string/title_dropdown_preference"
- android:entries="@array/entries"
- app:useSimpleSummaryProvider="true"
- android:entryValues="@array/entry_values"/>
+ <CheckBoxPreference
+ android:key="checkbox"
+ android:summary="@string/summary_checkbox_preference"
+ android:title="@string/title_checkbox_preference"/>
- <SeekBarPreference
- android:key="seekbar"
- android:title="@string/title_seekbar_preference"
- android:max="10"
- android:defaultValue="5"/>
- </PreferenceCategory>
+ <DropDownPreference
+ android:entries="@array/entries"
+ android:entryValues="@array/entry_values"
+ android:key="dropdown"
+ android:title="@string/title_dropdown_preference"
+ app:useSimpleSummaryProvider="true"/>
- <PreferenceCategory
- android:title="@string/dialogs">
+ <SeekBarPreference
+ android:defaultValue="5"
+ android:key="seekbar"
+ android:max="10"
+ android:title="@string/title_seekbar_preference"/>
- <EditTextPreference
- android:key="edittext"
- android:title="@string/title_edittext_preference"
- app:useSimpleSummaryProvider="true"
- android:dialogTitle="@string/dialog_title_edittext_preference"/>
+ <SwitchPreference
+ android:key="switch"
+ android:summary="@string/summary_switch_preference"
+ android:title="@string/title_switch_preference"/>
- <ListPreference
- android:key="list"
- android:title="@string/title_list_preference"
- app:useSimpleSummaryProvider="true"
- android:entries="@array/entries"
- android:entryValues="@array/entry_values"
- android:dialogTitle="@string/dialog_title_list_preference"/>
+ <com.android.car.ui.preference.CarUiTwoActionPreference
+ android:key="twoaction"
+ android:summary="@string/summary_twoaction_preference"
+ android:title="@string/title_twoaction_preference"
+ android:widgetLayout="@layout/details_preference_widget"/>
+ </PreferenceCategory>
- <MultiSelectListPreference
- android:key="multi_select_list"
- android:title="@string/title_multi_list_preference"
- android:summary="@string/summary_multi_list_preference"
- android:entries="@array/entries"
- android:entryValues="@array/entry_values"
- android:dialogTitle="@string/dialog_title_multi_list_preference"/>
- </PreferenceCategory>
+ <PreferenceCategory
+ android:title="@string/dialogs">
- <PreferenceCategory
- android:key="@string/advanced_preference"
- android:title="@string/advanced_attributes"
- app:initialExpandedChildrenCount="1">
+ <EditTextPreference
+ android:dialogTitle="@string/dialog_title_edittext_preference"
+ android:key="edittext"
+ android:title="@string/title_edittext_preference"
+ app:useSimpleSummaryProvider="true"/>
- <Preference
- android:key="expandable"
- android:title="@string/title_expandable_preference"
- android:summary="@string/summary_expandable_preference"/>
+ <ListPreference
+ android:dialogTitle="@string/dialog_title_list_preference"
+ android:entries="@array/entries"
+ android:entryValues="@array/entry_values"
+ android:key="list"
+ android:title="@string/title_list_preference"
+ app:useSimpleSummaryProvider="true"/>
- <Preference
- android:title="@string/title_intent_preference"
- android:summary="@string/summary_intent_preference">
+ <MultiSelectListPreference
+ android:dialogTitle="@string/dialog_title_multi_list_preference"
+ android:entries="@array/entries"
+ android:entryValues="@array/entry_values"
+ android:key="multi_select_list"
+ android:summary="@string/summary_multi_list_preference"
+ android:title="@string/title_multi_list_preference"/>
- <intent android:action="android.intent.action.VIEW"
- android:data="http://www.android.com"/>
+ <com.android.car.ui.preference.CarUiSeekBarDialogPreference
+ android:dialogTitle="Seekbar Dialog"
+ android:key="seekbarDialog"
+ android:summary="@string/summary_seekbar_preference"
+ android:title="@string/title_seekbar_preference"/>
+ </PreferenceCategory>
- </Preference>
+ <PreferenceCategory
+ android:key="@string/advanced_preference"
+ android:title="@string/advanced_attributes"
+ app:initialExpandedChildrenCount="1">
- <SwitchPreference
- android:key="parent"
- android:title="@string/title_parent_preference"
- android:summary="@string/summary_parent_preference"/>
+ <Preference
+ android:key="expandable"
+ android:summary="@string/summary_expandable_preference"
+ android:title="@string/title_expandable_preference"/>
- <SwitchPreference
- android:key="child"
- android:dependency="parent"
- android:title="@string/title_child_preference"
- android:summary="@string/summary_child_preference"/>
+ <Preference
+ android:summary="@string/summary_intent_preference"
+ android:title="@string/title_intent_preference">
- <SwitchPreference
- android:key="toggle_summary"
- android:title="@string/title_toggle_summary_preference"
- android:summaryOn="@string/summary_on_toggle_summary_preference"
- android:summaryOff="@string/summary_off_toggle_summary_preference"/>
+ <intent android:action="android.intent.action.VIEW"
+ android:data="http://www.android.com"/>
- <Preference
- android:key="copyable"
- android:title="@string/title_copyable_preference"
- android:summary="@string/summary_copyable_preference"
- android:selectable="false"
- app:enableCopying="true"/>
- </PreferenceCategory>
+ </Preference>
+
+ <Preference
+ android:key="copyable"
+ android:selectable="false"
+ android:summary="@string/summary_copyable_preference"
+ android:title="@string/title_copyable_preference"
+ app:enableCopying="true"/>
+
+ <SwitchPreference
+ android:dependency="parent"
+ android:key="child"
+ android:summary="@string/summary_child_preference"
+ android:title="@string/title_child_preference"/>
+
+ <SwitchPreference
+ android:key="toggle_summary"
+ android:summaryOff="@string/summary_off_toggle_summary_preference"
+ android:summaryOn="@string/summary_on_toggle_summary_preference"
+ android:title="@string/title_toggle_summary_preference"/>
+
+ <SwitchPreference
+ android:key="parent"
+ android:summary="@string/summary_parent_preference"
+ android:title="@string/title_parent_preference"/>
+ </PreferenceCategory>
</PreferenceScreen>
\ No newline at end of file
diff --git a/car-ui-lib/tests/paintbooth/src/com/android/car/ui/paintbooth/MainActivity.java b/car-ui-lib/tests/paintbooth/src/com/android/car/ui/paintbooth/MainActivity.java
index f05a827..31c8f94 100644
--- a/car-ui-lib/tests/paintbooth/src/com/android/car/ui/paintbooth/MainActivity.java
+++ b/car-ui-lib/tests/paintbooth/src/com/android/car/ui/paintbooth/MainActivity.java
@@ -17,6 +17,8 @@
package com.android.car.ui.paintbooth;
import android.app.Activity;
+import android.app.ActivityManager;
+import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
@@ -25,6 +27,7 @@
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
+import android.widget.Switch;
import android.widget.Toast;
import androidx.annotation.NonNull;
@@ -33,6 +36,7 @@
import com.android.car.ui.paintbooth.caruirecyclerview.CarUiListItemActivity;
import com.android.car.ui.paintbooth.caruirecyclerview.CarUiRecyclerViewActivity;
import com.android.car.ui.paintbooth.caruirecyclerview.GridCarUiRecyclerViewActivity;
+import com.android.car.ui.paintbooth.currentactivity.CurrentActivityService;
import com.android.car.ui.paintbooth.dialogs.DialogsActivity;
import com.android.car.ui.paintbooth.overlays.OverlayActivity;
import com.android.car.ui.paintbooth.preferences.PreferenceActivity;
@@ -63,6 +67,16 @@
Pair.create("ListItem sample", CarUiListItemActivity.class)
);
+ private final List<Pair<String, View.OnClickListener>> mSwitches = Arrays.asList(
+ Pair.create("Show foreground activities", v -> {
+ Intent intent = new Intent(this, CurrentActivityService.class);
+ if (isCurrentActivityServiceRunning()) {
+ intent.setAction(CurrentActivityService.STOP_SERVICE);
+ }
+ startForegroundService(intent);
+ })
+ );
+
private class ViewHolder extends RecyclerView.ViewHolder {
private Button mButton;
@@ -71,36 +85,60 @@
mButton = itemView.findViewById(R.id.button);
}
- void update(String title, Class<? extends Activity> activityClass) {
- mButton.setText(title);
- mButton.setOnClickListener(e -> {
- Intent intent = new Intent(mButton.getContext(), activityClass);
- startActivity(intent);
- });
+ void bind(String text, View.OnClickListener listener) {
+ mButton.setText(text);
+ mButton.setOnClickListener(listener);
+
+ if (mButton instanceof Switch) {
+ ((Switch) mButton).setChecked(isCurrentActivityServiceRunning());
+ }
}
}
private final RecyclerView.Adapter<ViewHolder> mAdapter =
new RecyclerView.Adapter<ViewHolder>() {
- @NonNull
- @Override
- public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
- View item = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item, parent,
- false);
- return new ViewHolder(item);
- }
- @Override
- public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
- Pair<String, Class<? extends Activity>> item = mActivities.get(position);
- holder.update(item.first, item.second);
- }
+ private static final int TYPE_SWITCH = 0;
+ private static final int TYPE_ACTIVITY = 1;
- @Override
- public int getItemCount() {
- return mActivities.size();
- }
- };
+ @NonNull
+ @Override
+ public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ View item = LayoutInflater.from(parent.getContext()).inflate(
+ viewType == TYPE_SWITCH ? R.layout.list_item_switch
+ : R.layout.list_item,
+ parent, false);
+ return new ViewHolder(item);
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
+ if (getItemViewType(position) == TYPE_SWITCH) {
+ Pair<String, View.OnClickListener> item = mSwitches.get(position);
+ holder.bind(item.first, item.second);
+ } else {
+ Pair<String, Class<? extends Activity>> item =
+ mActivities.get(position - mSwitches.size());
+ holder.bind(item.first, v -> {
+ Intent intent = new Intent(holder.itemView.getContext(), item.second);
+ startActivity(intent);
+ });
+ }
+ }
+
+ @Override
+ public int getItemCount() {
+ return mSwitches.size() + mActivities.size();
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ if (position < mSwitches.size()) {
+ return TYPE_SWITCH;
+ }
+ return TYPE_ACTIVITY;
+ }
+ };
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -189,4 +227,15 @@
// LeakCanary is not used in this build, do nothing.
}
}
+
+ private boolean isCurrentActivityServiceRunning() {
+ ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
+ for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(
+ Integer.MAX_VALUE)) {
+ if (CurrentActivityService.class.getName().equals(service.service.getClassName())) {
+ return true;
+ }
+ }
+ return false;
+ }
}
diff --git a/car-ui-lib/tests/paintbooth/src/com/android/car/ui/paintbooth/caruirecyclerview/CarUiListItemActivity.java b/car-ui-lib/tests/paintbooth/src/com/android/car/ui/paintbooth/caruirecyclerview/CarUiListItemActivity.java
index c2d78ca..10aef44 100644
--- a/car-ui-lib/tests/paintbooth/src/com/android/car/ui/paintbooth/caruirecyclerview/CarUiListItemActivity.java
+++ b/car-ui-lib/tests/paintbooth/src/com/android/car/ui/paintbooth/caruirecyclerview/CarUiListItemActivity.java
@@ -94,6 +94,14 @@
item.setBody("With avatar icon.");
item.setIcon(getDrawable(R.drawable.ic_sample_logo));
item.setPrimaryIconType(CarUiContentListItem.IconType.AVATAR);
+
+ item = new CarUiContentListItem();
+ item.setTitle("Test Title");
+ item.setBody("Displays toast on click");
+ item.setIcon(getDrawable(R.drawable.ic_launcher));
+ item.setOnItemClickedListener(item1 -> {
+ Toast.makeText(context, "Item clicked" , Toast.LENGTH_SHORT).show();
+ });
mData.add(item);
item = new CarUiContentListItem();
@@ -108,8 +116,11 @@
item = new CarUiContentListItem();
item.setIcon(getDrawable(R.drawable.ic_launcher));
- item.setBody("Body -- Item with switch");
+ item.setBody("Body -- Item with switch -- with click listener");
item.setAction(CarUiContentListItem.Action.SWITCH);
+ item.setOnItemClickedListener(item1 -> {
+ Toast.makeText(context, "Click on item with switch" , Toast.LENGTH_SHORT).show();
+ });
mData.add(item);
item = new CarUiContentListItem();
diff --git a/car-ui-lib/tests/paintbooth/src/com/android/car/ui/paintbooth/currentactivity/ActivityTaskManager.java b/car-ui-lib/tests/paintbooth/src/com/android/car/ui/paintbooth/currentactivity/ActivityTaskManager.java
new file mode 100644
index 0000000..ec26665
--- /dev/null
+++ b/car-ui-lib/tests/paintbooth/src/com/android/car/ui/paintbooth/currentactivity/ActivityTaskManager.java
@@ -0,0 +1,84 @@
+/*
+ * 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.car.ui.paintbooth.currentactivity;
+
+import android.app.ActivityManager;
+import android.app.ActivityManager.RunningTaskInfo;
+import android.content.ComponentName;
+import android.os.RemoteException;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.List;
+
+/**
+ * Interface for wrappers around {@link android.app.ActivityTaskManager} so that we can exclude them
+ * from non-system builds like gradle and google3.
+ */
+interface ActivityTaskManager {
+
+ interface TaskStackListener {
+ void onTaskCreated(int taskId, ComponentName componentName);
+
+ void onTaskRemoved(int taskId);
+
+ void onTaskDescriptionChanged(ActivityManager.RunningTaskInfo taskInfo);
+
+ void onTaskMovedToFront(ActivityManager.RunningTaskInfo taskInfo);
+ }
+
+ List<RunningTaskInfo> getTasks(int maxNum) throws RemoteException;
+
+ void registerTaskStackListener(TaskStackListener listener) throws RemoteException;
+
+ void unregisterTaskStackListener(TaskStackListener listener) throws RemoteException;
+
+ final class ActivityTaskManagerStub implements ActivityTaskManager {
+ @Override
+ public List<RunningTaskInfo> getTasks(int num) throws RemoteException {
+ throw new RemoteException("ActivityTaskManager is not available");
+ }
+
+ @Override
+ public void registerTaskStackListener(TaskStackListener listener) throws RemoteException {
+ throw new RemoteException("ActivityTaskManager is not available");
+ }
+
+ @Override
+ public void unregisterTaskStackListener(TaskStackListener listener) throws RemoteException {
+ throw new RemoteException("ActivityTaskManager is not available");
+ }
+ }
+
+ @NonNull
+ static ActivityTaskManager getService() {
+ try {
+ Class clazz = Class.forName(
+ "com.android.car.ui.paintbooth.currentactivity.ActivityTaskManagerImpl");
+ Constructor constructor = clazz.getDeclaredConstructor();
+ constructor.setAccessible(true);
+ return (ActivityTaskManager) constructor.newInstance();
+ } catch (ClassNotFoundException | IllegalAccessException | InstantiationException
+ | NoSuchMethodException | InvocationTargetException e) {
+ Log.e("paintbooth", "ActivityTaskManager is not available", e);
+ return new ActivityTaskManagerStub();
+ }
+ }
+}
diff --git a/car-ui-lib/tests/paintbooth/src/com/android/car/ui/paintbooth/currentactivity/ActivityTaskManagerImpl.java b/car-ui-lib/tests/paintbooth/src/com/android/car/ui/paintbooth/currentactivity/ActivityTaskManagerImpl.java
new file mode 100644
index 0000000..8adbdad
--- /dev/null
+++ b/car-ui-lib/tests/paintbooth/src/com/android/car/ui/paintbooth/currentactivity/ActivityTaskManagerImpl.java
@@ -0,0 +1,77 @@
+/*
+ * 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.car.ui.paintbooth.currentactivity;
+
+import android.app.ActivityManager;
+import android.app.ActivityManager.RunningTaskInfo;
+import android.app.IActivityTaskManager;
+import android.content.ComponentName;
+import android.os.RemoteException;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * This class is a wrapper around {@link android.app.ActivityTaskManager} that is excluded from
+ * the gradle and google3 builds.
+ */
+class ActivityTaskManagerImpl implements ActivityTaskManager {
+
+ IActivityTaskManager mActivityTaskManager = android.app.ActivityTaskManager.getService();
+
+ Map<TaskStackListener, android.app.TaskStackListener> mListenerMapping = new HashMap<>();
+
+ @Override
+ public List<RunningTaskInfo> getTasks(int maxNum) throws RemoteException {
+ return mActivityTaskManager.getTasks(maxNum);
+ }
+
+ @Override
+ public void registerTaskStackListener(TaskStackListener listener) throws RemoteException {
+ mListenerMapping.put(listener, new android.app.TaskStackListener() {
+ @Override
+ public void onTaskCreated(int taskId, ComponentName componentName) {
+ listener.onTaskCreated(taskId, componentName);
+ }
+
+ @Override
+ public void onTaskRemoved(int taskId) {
+ listener.onTaskRemoved(taskId);
+ }
+
+ @Override
+ public void onTaskDescriptionChanged(ActivityManager.RunningTaskInfo taskInfo) {
+ listener.onTaskDescriptionChanged(taskInfo);
+ }
+
+ @Override
+ public void onTaskMovedToFront(ActivityManager.RunningTaskInfo taskInfo) {
+ listener.onTaskMovedToFront(taskInfo);
+ }
+ });
+
+ mActivityTaskManager.registerTaskStackListener(mListenerMapping.get(listener));
+ }
+
+ @Override
+ public void unregisterTaskStackListener(TaskStackListener listener) throws RemoteException {
+ mActivityTaskManager.unregisterTaskStackListener(mListenerMapping.get(listener));
+ mListenerMapping.remove(listener);
+ }
+
+}
diff --git a/car-ui-lib/tests/paintbooth/src/com/android/car/ui/paintbooth/currentactivity/CurrentActivityService.java b/car-ui-lib/tests/paintbooth/src/com/android/car/ui/paintbooth/currentactivity/CurrentActivityService.java
new file mode 100644
index 0000000..aa26a92
--- /dev/null
+++ b/car-ui-lib/tests/paintbooth/src/com/android/car/ui/paintbooth/currentactivity/CurrentActivityService.java
@@ -0,0 +1,231 @@
+/*
+ * 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.car.ui.paintbooth.currentactivity;
+
+import android.app.ActivityManager;
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.app.Service;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.graphics.Color;
+import android.graphics.PixelFormat;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.view.Gravity;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import androidx.core.app.NotificationCompat;
+import androidx.core.content.ContextCompat;
+
+import com.android.car.ui.paintbooth.R;
+import com.android.car.ui.paintbooth.currentactivity.ActivityTaskManager.TaskStackListener;
+
+import java.util.List;
+
+/**
+ * To start the service:
+ * adb shell am start-foreground-service -n com.android.car.ui.paintbooth/.CurrentActivityService
+ *
+ * To stop the service:
+ * adb shell am start-foreground-service -n com.android.car.ui.paintbooth/.CurrentActivityService -a
+ * com.android.car.ui.paintbooth.StopService
+ */
+public class CurrentActivityService extends Service {
+
+ public static final String STOP_SERVICE = "com.android.car.ui.paintbooth.StopService";
+ private static final int FOREGROUND_SERVICE_ID = 111;
+
+ private WindowManager mWindowManager;
+ private TextView mTextView;
+ private Handler mHandler;
+
+ @Override
+ public void onCreate() {
+ mHandler = new Handler(Looper.getMainLooper());
+
+ if (ContextCompat.checkSelfPermission(this, "android.permission.REAL_GET_TASKS")
+ != PackageManager.PERMISSION_GRANTED) {
+ Toast.makeText(this, "android.permission.REAL_GET_TASKS is not granted!",
+ Toast.LENGTH_LONG).show();
+ }
+
+ Intent notificationIntent = new Intent(this, CurrentActivityService.class);
+
+ PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
+ notificationIntent, 0);
+
+ NotificationChannel channel = new NotificationChannel("CurrentActivityService",
+ "Show current activity",
+ NotificationManager.IMPORTANCE_DEFAULT);
+ NotificationManager notificationManager =
+ (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
+ notificationManager.createNotificationChannel(channel);
+
+ Notification notification =
+ new NotificationCompat.Builder(this, "CurrentActivityService")
+ .setSmallIcon(R.drawable.ic_launcher)
+ .setContentTitle("CurrentActivityService")
+ .setContentText("Show current activity")
+ .setContentIntent(pendingIntent).build();
+
+ startForeground(FOREGROUND_SERVICE_ID, notification);
+
+ try {
+ ActivityTaskManager.getService().registerTaskStackListener(mTaskStackListener);
+ } catch (RemoteException e) {
+ Toast.makeText(this, e.getLocalizedMessage(), Toast.LENGTH_LONG).show();
+ }
+
+ mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
+ final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(
+ WindowManager.LayoutParams.WRAP_CONTENT,
+ WindowManager.LayoutParams.WRAP_CONTENT,
+ WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
+ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
+ PixelFormat.TRANSLUCENT);
+
+ mTextView = new TextView(this);
+ layoutParams.gravity = Gravity.TOP | Gravity.LEFT;
+ layoutParams.x = 0;
+ layoutParams.y = 100;
+ mTextView.setLayoutParams(layoutParams);
+ mTextView.setBackgroundColor(Color.argb(50, 0, 255, 0));
+
+ mTextView.setOnTouchListener(new View.OnTouchListener() {
+
+ private int mInitialX = 0;
+ private int mInitialY = 0;
+ private float mInitialTouchX;
+ private float mInitialTouchY;
+
+ @Override
+ public boolean onTouch(View view, MotionEvent event) {
+ switch (event.getAction() & MotionEvent.ACTION_MASK) {
+ case MotionEvent.ACTION_DOWN:
+ mInitialX = layoutParams.x;
+ mInitialY = layoutParams.y;
+ mInitialTouchX = event.getRawX();
+ mInitialTouchY = event.getRawY();
+ break;
+ case MotionEvent.ACTION_MOVE:
+ WindowManager.LayoutParams layoutParams =
+ (WindowManager.LayoutParams) view.getLayoutParams();
+ layoutParams.x = mInitialX + (int) (event.getRawX() - mInitialTouchX);
+ layoutParams.y = mInitialY + (int) (event.getRawY() - mInitialTouchY);
+ mWindowManager.updateViewLayout(view, layoutParams);
+ return true;
+ default:
+ break;
+ }
+
+ return false;
+ }
+ });
+
+ try {
+ mWindowManager.addView(mTextView, layoutParams);
+ } catch (RuntimeException e) {
+ Toast.makeText(this, "Couldn't display overlay", Toast.LENGTH_SHORT)
+ .show();
+ }
+
+ showCurrentTask();
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ if (STOP_SERVICE.equals(intent.getAction())) {
+ stopSelf();
+ }
+
+ return START_STICKY;
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+
+ @Override
+ public void onDestroy() {
+ mHandler.removeCallbacksAndMessages(null);
+ mWindowManager.removeView(mTextView);
+ try {
+ ActivityTaskManager.getService().unregisterTaskStackListener(mTaskStackListener);
+ } catch (RemoteException e) {
+ Toast.makeText(this, e.getLocalizedMessage(), Toast.LENGTH_LONG).show();
+ }
+ }
+
+ /**
+ * This requires system permissions or else it will only fetch the current app and the launcher
+ * app
+ */
+ private void showCurrentTask() {
+ try {
+ List<ActivityManager.RunningTaskInfo> tasks =
+ ActivityTaskManager.getService().getTasks(1);
+ if (!tasks.isEmpty()) {
+ updateComponentName(tasks.get(0).topActivity);
+ }
+ } catch (RemoteException e) {
+ Toast.makeText(this, e.getLocalizedMessage(), Toast.LENGTH_LONG).show();
+ }
+ }
+
+ private void updateComponentName(ComponentName componentName) {
+ mHandler.post(() -> {
+ if (mTextView != null && componentName != null) {
+ mTextView.setText(componentName.flattenToShortString().replace('/', '\n'));
+ }
+ });
+ }
+
+ private final TaskStackListener mTaskStackListener = new TaskStackListener() {
+ @Override
+ public void onTaskCreated(int taskId, ComponentName componentName) {
+ updateComponentName(componentName);
+ }
+
+ @Override
+ public void onTaskRemoved(int taskId) {
+ showCurrentTask();
+ }
+
+ @Override
+ public void onTaskDescriptionChanged(ActivityManager.RunningTaskInfo taskInfo) {
+ updateComponentName(taskInfo.topActivity);
+ }
+
+ @Override
+ public void onTaskMovedToFront(ActivityManager.RunningTaskInfo taskInfo) {
+ updateComponentName(taskInfo.topActivity);
+ }
+ };
+}
diff --git a/car-ui-lib/tests/paintbooth/src/com/android/car/ui/paintbooth/dialogs/DialogsActivity.java b/car-ui-lib/tests/paintbooth/src/com/android/car/ui/paintbooth/dialogs/DialogsActivity.java
index 37c9a42..ed125bc 100644
--- a/car-ui-lib/tests/paintbooth/src/com/android/car/ui/paintbooth/dialogs/DialogsActivity.java
+++ b/car-ui-lib/tests/paintbooth/src/com/android/car/ui/paintbooth/dialogs/DialogsActivity.java
@@ -26,6 +26,7 @@
import android.widget.Toast;
import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
import com.android.car.ui.AlertDialogBuilder;
import com.android.car.ui.paintbooth.R;
@@ -161,7 +162,7 @@
.show();
}
- private static class ViewHolder extends CarUiRecyclerView.ViewHolder {
+ private static class ViewHolder extends RecyclerView.ViewHolder {
private final Button mButton;
@@ -176,8 +177,8 @@
}
}
- private final CarUiRecyclerView.Adapter<ViewHolder> mAdapter =
- new CarUiRecyclerView.Adapter<ViewHolder>() {
+ private final RecyclerView.Adapter<ViewHolder> mAdapter =
+ new RecyclerView.Adapter<ViewHolder>() {
@Override
public int getItemCount() {
return mButtons.size();
diff --git a/car-ui-lib/tests/paintbooth/src/com/android/car/ui/paintbooth/overlays/OverlayManagerImpl.java b/car-ui-lib/tests/paintbooth/src/com/android/car/ui/paintbooth/overlays/OverlayManagerImpl.java
index 32fcbc9..3a27534 100644
--- a/car-ui-lib/tests/paintbooth/src/com/android/car/ui/paintbooth/overlays/OverlayManagerImpl.java
+++ b/car-ui-lib/tests/paintbooth/src/com/android/car/ui/paintbooth/overlays/OverlayManagerImpl.java
@@ -16,7 +16,7 @@
package com.android.car.ui.paintbooth.overlays;
-import android.car.userlib.CarUserManagerHelper;
+import android.app.ActivityManager;
import android.content.Context;
import android.content.om.IOverlayManager;
import android.os.RemoteException;
@@ -35,11 +35,9 @@
* image.
*/
public class OverlayManagerImpl implements OverlayManager {
- private final CarUserManagerHelper mCarUserManagerHelper;
private final IOverlayManager mOverlayManager;
public OverlayManagerImpl(Context context) {
- mCarUserManagerHelper = new CarUserManagerHelper(context);
mOverlayManager = IOverlayManager.Stub.asInterface(
ServiceManager.getService(Context.OVERLAY_SERVICE));
}
@@ -62,8 +60,8 @@
@Override
@NonNull
public Map<String, List<OverlayManager.OverlayInfo>> getOverlays() throws RemoteException {
- Map<String, List<android.content.om.OverlayInfo>> overlays = mOverlayManager
- .getAllOverlays(mCarUserManagerHelper.getCurrentForegroundUserId());
+ Map<String, List<android.content.om.OverlayInfo>> overlays =
+ mOverlayManager.getAllOverlays(ActivityManager.getCurrentUser());
return overlays.entrySet()
.stream()
.collect(toMap(Map.Entry::getKey, e -> e.getValue()
@@ -74,7 +72,6 @@
@Override
public void applyOverlay(@NonNull String packageName, boolean enable) throws RemoteException {
- mOverlayManager.setEnabled(packageName, enable,
- mCarUserManagerHelper.getCurrentForegroundUserId());
+ mOverlayManager.setEnabled(packageName, enable, ActivityManager.getCurrentUser());
}
}
diff --git a/car-ui-lib/tests/paintbooth/src/com/android/car/ui/paintbooth/preferences/PreferenceDemoFragment.java b/car-ui-lib/tests/paintbooth/src/com/android/car/ui/paintbooth/preferences/PreferenceDemoFragment.java
index ccd21ef..e9f990d 100644
--- a/car-ui-lib/tests/paintbooth/src/com/android/car/ui/paintbooth/preferences/PreferenceDemoFragment.java
+++ b/car-ui-lib/tests/paintbooth/src/com/android/car/ui/paintbooth/preferences/PreferenceDemoFragment.java
@@ -19,6 +19,7 @@
import android.os.Bundle;
import com.android.car.ui.paintbooth.R;
+import com.android.car.ui.preference.CarUiPreference;
import com.android.car.ui.preference.PreferenceFragment;
/**
@@ -30,5 +31,18 @@
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
// Load the preferences from an XML resource
setPreferencesFromResource(R.xml.preference_samples, rootKey);
+ CarUiPreference preferenceDisabledWithoutRipple = findPreference(
+ "preference_disabled_without_ripple");
+ preferenceDisabledWithoutRipple.setEnabled(false);
+ preferenceDisabledWithoutRipple.setMessageToShowWhenDisabledPreferenceClicked(
+ "I am disabled because...");
+ preferenceDisabledWithoutRipple.setShouldShowRippleOnDisabledPreference(false);
+
+ CarUiPreference preferenceDisabledWithRipple = findPreference(
+ "preference_disabled_with_ripple");
+ preferenceDisabledWithRipple.setEnabled(false);
+ preferenceDisabledWithRipple.setMessageToShowWhenDisabledPreferenceClicked(
+ "I am disabled because...");
+ preferenceDisabledWithRipple.setShouldShowRippleOnDisabledPreference(true);
}
}
diff --git a/car-ui-lib/tests/paintbooth/src/com/android/car/ui/paintbooth/toolbar/ToolbarActivity.java b/car-ui-lib/tests/paintbooth/src/com/android/car/ui/paintbooth/toolbar/ToolbarActivity.java
index f71b5ac..161092e 100644
--- a/car-ui-lib/tests/paintbooth/src/com/android/car/ui/paintbooth/toolbar/ToolbarActivity.java
+++ b/car-ui-lib/tests/paintbooth/src/com/android/car/ui/paintbooth/toolbar/ToolbarActivity.java
@@ -29,6 +29,7 @@
import android.widget.Toast;
import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
import com.android.car.ui.AlertDialogBuilder;
import com.android.car.ui.paintbooth.R;
@@ -315,7 +316,7 @@
}).show();
}
- private static class ViewHolder extends CarUiRecyclerView.ViewHolder {
+ private static class ViewHolder extends RecyclerView.ViewHolder {
private final Button mButton;
@@ -330,8 +331,8 @@
}
}
- private CarUiRecyclerView.Adapter<ViewHolder> mAdapter =
- new CarUiRecyclerView.Adapter<ViewHolder>() {
+ private final RecyclerView.Adapter<ViewHolder> mAdapter =
+ new RecyclerView.Adapter<ViewHolder>() {
@Override
public int getItemCount() {
return mButtons.size();
diff --git a/car-ui-lib/tests/robotests/build.gradle b/car-ui-lib/tests/robotests/build.gradle
index 8553359..b741419 100644
--- a/car-ui-lib/tests/robotests/build.gradle
+++ b/car-ui-lib/tests/robotests/build.gradle
@@ -20,10 +20,10 @@
repositories {
google()
jcenter()
-
}
+
dependencies {
- classpath 'com.android.tools.build:gradle:3.5.0'
+ classpath 'com.android.tools.build:gradle:3.5.3'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
@@ -72,13 +72,12 @@
includeAndroidResources = true
}
}
-
}
dependencies {
implementation project(':')
testImplementation "androidx.test.ext:junit:1.1.1"
- testImplementation "org.robolectric:robolectric:4.0-alpha-3"
+ testImplementation 'org.robolectric:robolectric:4.2'
testImplementation "org.mockito:mockito-core:2.19.0"
testImplementation "com.google.truth:truth:0.29"
testImplementation "org.testng:testng:6.9.9"
diff --git a/car-ui-lib/tests/robotests/src/com/android/car/ui/CarUiRobolectricTestRunner.java b/car-ui-lib/tests/robotests/src/com/android/car/ui/CarUiRobolectricTestRunner.java
deleted file mode 100644
index 0a3474b..0000000
--- a/car-ui-lib/tests/robotests/src/com/android/car/ui/CarUiRobolectricTestRunner.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright 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.car.ui;
-
-import androidx.annotation.NonNull;
-
-import org.junit.runners.model.InitializationError;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-import org.robolectric.manifest.AndroidManifest;
-import org.robolectric.res.Fs;
-import org.robolectric.res.ResourcePath;
-
-import java.io.File;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Custom test runner for CarUi. This is needed because the default behavior for
- * robolectric is just to grab the resource directory in the target package.
- * We want to override this to add several spanning different projects.
- */
-public class CarUiRobolectricTestRunner extends RobolectricTestRunner {
- private static final Map<String, String> AAR_VERSIONS;
- private static final String SUPPORT_RESOURCE_PATH_TEMPLATE =
- "jar:file:%3$s/prebuilts/sdk/current/androidx/m2repository/androidx/"
- + "%1$s/%1$s/%2$s/%1$s-%2$s.aar!/res";
- // contraint-layout aar lives in separate path.
- // Note its path contains a hyphen.
- private static final String CONSTRAINT_LAYOUT_RESOURCE_PATH_TEMPLATE =
- "jar:file:%3$s/prebuilts/sdk/current/extras/constraint-layout-x/"
- + "%1$s/%2$s/%1$s-%2$s.aar!/res";
-
- static {
- AAR_VERSIONS = new HashMap<>();
- AAR_VERSIONS.put("appcompat", "1.1.0-alpha01");
- AAR_VERSIONS.put("constraintlayout", "1.1.2");
- AAR_VERSIONS.put("preference", "1.1.0-alpha02");
- }
-
- public CarUiRobolectricTestRunner(Class<?> testClass) throws InitializationError {
- super(testClass);
- }
-
- private static ResourcePath createResourcePath(@NonNull String filePath) {
- try {
- return new ResourcePath(null, Fs.fromURL(new URL(filePath)), null);
- } catch (MalformedURLException e) {
- throw new RuntimeException("CarUiRobolectricTestRunner failure", e);
- }
- }
-
- /**
- * Create the resource path for a support library component's JAR.
- */
- private static String createSupportResourcePathFromJar(@NonNull String pathRoot,
- @NonNull String componentId) {
- if (!AAR_VERSIONS.containsKey(componentId)) {
- throw new IllegalArgumentException("Unknown component " + componentId
- + ". Update test with appropriate component name and version.");
- }
- if (componentId.equals("constraintlayout")) {
- return String.format(CONSTRAINT_LAYOUT_RESOURCE_PATH_TEMPLATE, componentId,
- AAR_VERSIONS.get(componentId), pathRoot);
- }
- return String.format(SUPPORT_RESOURCE_PATH_TEMPLATE, componentId,
- AAR_VERSIONS.get(componentId), pathRoot);
- }
-
- /**
- * We modify the AndroidManifest such that we can add required resources.
- */
- @Override
- protected AndroidManifest getAppManifest(Config config) {
- try {
- final URL appRoot;
- final String rootRelativePath;
- // Root path is workspace root when run from command line and module root when run from
- // Android Studio.
- if (new File(System.getProperty("user.dir")).getName().equals("robotests")) {
- rootRelativePath = "../../../../../../../.";
- appRoot = new File("../../.").toURI().toURL();
- } else {
- appRoot = new URL("file:packages/apps/Car/libs/car-ui-lib/");
- rootRelativePath = "./";
- }
-
- // Using the manifest file's relative path, we can figure out the application directory.
- URL manifestPath = new URL(appRoot, "AndroidManifest.xml");
- URL resDir = new URL(appRoot, "tests/robotests/res");
- URL assetsDir = new URL(appRoot, config.assetDir());
-
- // By adding any resources from libraries we need to the AndroidManifest, we can access
- // them from within the parallel universe's resource loader.
- return new AndroidManifest(Fs.fromURL(manifestPath), Fs.fromURL(resDir),
- Fs.fromURL(assetsDir)) {
- @Override
- public List<ResourcePath> getIncludedResourcePaths() {
- List<ResourcePath> paths = super.getIncludedResourcePaths();
- paths.add(createResourcePath(
- String.format("file:%s/packages/apps/Car/libs/car-ui-lib/res",
- rootRelativePath)));
-
- // Support library resources. These need to point to the prebuilts of support
- // library and not the source.
- paths.add(createResourcePath(
- createSupportResourcePathFromJar(rootRelativePath, "appcompat")));
- paths.add(createResourcePath(createSupportResourcePathFromJar(rootRelativePath,
- "constraintlayout")));
- paths.add(createResourcePath(
- createSupportResourcePathFromJar(rootRelativePath, "preference")));
-
- return paths;
- }
- };
- } catch (MalformedURLException e) {
- throw new RuntimeException("CarUiRobolectricTestRunner failure", e);
- }
- }
-}
diff --git a/car-ui-lib/tests/robotests/src/com/android/car/ui/recyclerview/CarUiListItemTest.java b/car-ui-lib/tests/robotests/src/com/android/car/ui/recyclerview/CarUiListItemTest.java
index 3689d3c..7a01af3 100644
--- a/car-ui-lib/tests/robotests/src/com/android/car/ui/recyclerview/CarUiListItemTest.java
+++ b/car-ui-lib/tests/robotests/src/com/android/car/ui/recyclerview/CarUiListItemTest.java
@@ -27,7 +27,6 @@
import android.widget.Switch;
import android.widget.TextView;
-import com.android.car.ui.CarUiRobolectricTestRunner;
import com.android.car.ui.R;
import org.junit.Before;
@@ -35,12 +34,13 @@
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import java.util.ArrayList;
import java.util.List;
-@RunWith(CarUiRobolectricTestRunner.class)
+@RunWith(RobolectricTestRunner.class)
public class CarUiListItemTest {
private CarUiRecyclerView mListView;
diff --git a/car-ui-lib/tests/robotests/src/com/android/car/ui/recyclerview/CarUiRecyclerViewAdapterTest.java b/car-ui-lib/tests/robotests/src/com/android/car/ui/recyclerview/CarUiRecyclerViewAdapterTest.java
index 842ef44..4d21851 100644
--- a/car-ui-lib/tests/robotests/src/com/android/car/ui/recyclerview/CarUiRecyclerViewAdapterTest.java
+++ b/car-ui-lib/tests/robotests/src/com/android/car/ui/recyclerview/CarUiRecyclerViewAdapterTest.java
@@ -24,16 +24,15 @@
import android.content.Context;
import android.view.ViewGroup;
-import com.android.car.ui.CarUiRobolectricTestRunner;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
-@RunWith(CarUiRobolectricTestRunner.class)
+@RunWith(RobolectricTestRunner.class)
public class CarUiRecyclerViewAdapterTest {
private Context mContext;
diff --git a/car-ui-lib/tests/robotests/src/com/android/car/ui/recyclerview/CarUiRecyclerViewTest.java b/car-ui-lib/tests/robotests/src/com/android/car/ui/recyclerview/CarUiRecyclerViewTest.java
index 5cf9e85..4385913 100644
--- a/car-ui-lib/tests/robotests/src/com/android/car/ui/recyclerview/CarUiRecyclerViewTest.java
+++ b/car-ui-lib/tests/robotests/src/com/android/car/ui/recyclerview/CarUiRecyclerViewTest.java
@@ -30,7 +30,6 @@
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
-import com.android.car.ui.CarUiRobolectricTestRunner;
import com.android.car.ui.R;
import org.junit.Before;
@@ -39,9 +38,10 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.Robolectric;
+import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
-@RunWith(CarUiRobolectricTestRunner.class)
+@RunWith(RobolectricTestRunner.class)
public class CarUiRecyclerViewTest {
private Context mContext;
diff --git a/car-ui-lib/tests/robotests/src/com/android/car/ui/recyclerview/CarUiSmoothScrollerTest.java b/car-ui-lib/tests/robotests/src/com/android/car/ui/recyclerview/CarUiSmoothScrollerTest.java
index eb54f31..c5dc78b 100644
--- a/car-ui-lib/tests/robotests/src/com/android/car/ui/recyclerview/CarUiSmoothScrollerTest.java
+++ b/car-ui-lib/tests/robotests/src/com/android/car/ui/recyclerview/CarUiSmoothScrollerTest.java
@@ -22,14 +22,13 @@
import android.content.Context;
-import com.android.car.ui.CarUiRobolectricTestRunner;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
-@RunWith(CarUiRobolectricTestRunner.class)
+@RunWith(RobolectricTestRunner.class)
public class CarUiSmoothScrollerTest {
private Context mContext;
diff --git a/car-ui-lib/tests/robotests/src/com/android/car/ui/recyclerview/CarUiSnapHelperTest.java b/car-ui-lib/tests/robotests/src/com/android/car/ui/recyclerview/CarUiSnapHelperTest.java
index 3fc7a71..989c716 100644
--- a/car-ui-lib/tests/robotests/src/com/android/car/ui/recyclerview/CarUiSnapHelperTest.java
+++ b/car-ui-lib/tests/robotests/src/com/android/car/ui/recyclerview/CarUiSnapHelperTest.java
@@ -29,16 +29,15 @@
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
-import com.android.car.ui.CarUiRobolectricTestRunner;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
-@RunWith(CarUiRobolectricTestRunner.class)
+@RunWith(RobolectricTestRunner.class)
public class CarUiSnapHelperTest {
private Context mContext;
diff --git a/car-ui-lib/tests/robotests/src/com/android/car/ui/recyclerview/DefaultScrollBarTest.java b/car-ui-lib/tests/robotests/src/com/android/car/ui/recyclerview/DefaultScrollBarTest.java
index 4c64c07..b38a7ee 100644
--- a/car-ui-lib/tests/robotests/src/com/android/car/ui/recyclerview/DefaultScrollBarTest.java
+++ b/car-ui-lib/tests/robotests/src/com/android/car/ui/recyclerview/DefaultScrollBarTest.java
@@ -29,16 +29,15 @@
import androidx.recyclerview.widget.RecyclerView;
-import com.android.car.ui.CarUiRobolectricTestRunner;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
-@RunWith(CarUiRobolectricTestRunner.class)
+@RunWith(RobolectricTestRunner.class)
public class DefaultScrollBarTest {
private Context mContext;
diff --git a/car-ui-lib/tests/robotests/src/com/android/car/ui/toolbar/ExtendedShadowTypeface.java b/car-ui-lib/tests/robotests/src/com/android/car/ui/toolbar/ExtendedShadowTypeface.java
new file mode 100644
index 0000000..a5bc1b1
--- /dev/null
+++ b/car-ui-lib/tests/robotests/src/com/android/car/ui/toolbar/ExtendedShadowTypeface.java
@@ -0,0 +1,34 @@
+/*
+ * 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.car.ui.toolbar;
+
+import android.graphics.Typeface;
+
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.shadows.ShadowTypeface;
+
+@Implements(Typeface.class)
+public class ExtendedShadowTypeface extends ShadowTypeface {
+ @Implementation
+ protected static Typeface create(Typeface family, int weight, boolean italic) {
+ // Increment style by 10 to distinguish when a style has been italicized. This a workaround
+ // for ShadowTypeface not supporting italicization for Typeface.
+ int style = italic ? weight + 10 : weight;
+ return ShadowTypeface.create(family, style);
+ }
+}
diff --git a/car-ui-lib/tests/robotests/src/com/android/car/ui/toolbar/ShadowAsyncLayoutInflater.java b/car-ui-lib/tests/robotests/src/com/android/car/ui/toolbar/ShadowAsyncLayoutInflater.java
new file mode 100644
index 0000000..817ab97
--- /dev/null
+++ b/car-ui-lib/tests/robotests/src/com/android/car/ui/toolbar/ShadowAsyncLayoutInflater.java
@@ -0,0 +1,45 @@
+/*
+ * 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.ui.toolbar;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.LayoutRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.asynclayoutinflater.view.AsyncLayoutInflater;
+
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+
+/**
+ * Shadow of {@link AsyncLayoutInflater} that inflates synchronously, so that tests
+ * don't have to have complicated code to wait for these inflations.
+ */
+@Implements(AsyncLayoutInflater.class)
+public class ShadowAsyncLayoutInflater {
+ @Implementation
+ public void inflate(@LayoutRes int resid, @Nullable ViewGroup parent,
+ @NonNull AsyncLayoutInflater.OnInflateFinishedListener callback) {
+ View result = LayoutInflater.from(parent.getContext())
+ .inflate(resid, parent, false);
+
+ callback.onInflateFinished(result, resid, parent);
+ }
+}
diff --git a/car-ui-lib/tests/robotests/src/com/android/car/ui/toolbar/ToolbarTest.java b/car-ui-lib/tests/robotests/src/com/android/car/ui/toolbar/ToolbarTest.java
index cea19e3..5d99f95 100644
--- a/car-ui-lib/tests/robotests/src/com/android/car/ui/toolbar/ToolbarTest.java
+++ b/car-ui-lib/tests/robotests/src/com/android/car/ui/toolbar/ToolbarTest.java
@@ -26,13 +26,13 @@
import android.view.View;
import android.view.ViewGroup;
-import com.android.car.ui.CarUiRobolectricTestRunner;
import com.android.car.ui.R;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
+import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.android.controller.ActivityController;
import org.robolectric.annotation.Config;
@@ -41,8 +41,9 @@
import java.util.Collections;
import java.util.List;
-@RunWith(CarUiRobolectricTestRunner.class)
-@Config(qualifiers = "land")
+@RunWith(RobolectricTestRunner.class)
+@Config(shadows = {ExtendedShadowTypeface.class, ShadowAsyncLayoutInflater.class},
+ qualifiers = "land")
public class ToolbarTest {
private Context mContext;
diff --git a/car-ui-lib/tests/tools/quick_rro.py b/car-ui-lib/tests/tools/quick_rro.py
index 3d7d9ea..aaf186b 100755
--- a/car-ui-lib/tests/tools/quick_rro.py
+++ b/car-ui-lib/tests/tools/quick_rro.py
@@ -142,11 +142,11 @@
if len(packages) == 0:
print('No quick RROs to uninstall')
-def delete_arsc_flat_files(path):
- """Deletes all .arsc.flat files under `path`"""
+def delete_flat_files(path):
+ """Deletes all .flat files under `path`"""
for filename in os.listdir(path):
- if filename.endswith('.arsc.flat'):
- run_command(['rm', os.path.join(path, filename)])
+ if filename.endswith('.flat'):
+ os.remove(os.path.join(path, filename))
def build(args, package_name):
"""Builds the RRO apk"""
@@ -200,7 +200,7 @@
run_command(['aapt2', 'compile', '-o', os.path.join(root_folder, 'compiled.zip'),
'--dir', resource_folder])
- delete_arsc_flat_files(root_folder)
+ delete_flat_files(root_folder)
run_command(['unzip', os.path.join(root_folder, 'compiled.zip'),
'-d', root_folder])
@@ -209,14 +209,14 @@
'-o', unsigned_apk, '--manifest', manifest_file,
'-I', android_jar_path]
for filename in os.listdir(root_folder):
- if filename.endswith('.arsc.flat'):
+ if filename.endswith('.flat'):
link_command.extend(['-R', os.path.join(root_folder, filename)])
run_command(link_command)
- # For some reason signapk.jar requires a relative path to out/host/linux-x86/lib64
+ # For some reason signapk.jar requires a relative path to out/soong/host/linux-x86/lib64
os.chdir(os.environ['ANDROID_BUILD_TOP'])
- run_command(['java', '-Djava.library.path=out/host/linux-x86/lib64',
- '-jar', 'out/host/linux-x86/framework/signapk.jar',
+ run_command(['java', '-Djava.library.path=out/soong/host/linux-x86/lib64',
+ '-jar', 'out/soong/host/linux-x86/framework/signapk.jar',
'build/target/product/security/platform.x509.pem',
'build/target/product/security/platform.pk8',
unsigned_apk, signed_apk])
@@ -281,8 +281,8 @@
sys.exit(1)
if not os.path.isfile(os.path.join(
- os.environ['ANDROID_BUILD_TOP'], 'out/host/linux-x86/framework/signapk.jar')):
- print('out/host/linux-x86/framework/signapk.jar missing, please do an android build first')
+ os.environ['ANDROID_BUILD_TOP'], 'out/soong/host/linux-x86/framework/signapk.jar')):
+ print('out/soong/host/linux-x86/framework/signapk.jar missing, please do an android build first')
sys.exit(1)
package_name = get_package_name(args)
@@ -299,7 +299,7 @@
print('Enabling...')
# Enabling RROs sometimes fails shortly after installing them
time.sleep(1)
- run_command(['adb', 'shell', 'cmd', 'overlay', 'enable', '--user', '10', package_name])
+ run_command(['adb', 'shell', 'cmd', 'overlay', 'enable', '--user', 'current', package_name])
print('Done!')
diff --git a/car-settings-lib/Android.bp b/connected-device-lib/Android.bp
similarity index 71%
copy from car-settings-lib/Android.bp
copy to connected-device-lib/Android.bp
index 9c4dbd5..192aa25 100644
--- a/car-settings-lib/Android.bp
+++ b/connected-device-lib/Android.bp
@@ -1,3 +1,4 @@
+//
// Copyright (C) 2019 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -11,22 +12,32 @@
// 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.
+//
android_library {
- name: "car-settings-lib",
+ name: "connected-device-lib",
srcs: ["src/**/*.java"],
- resource_dirs: ["res"],
+ manifest: "AndroidManifest.xml",
- static_libs: [
- "androidx.annotation_annotation",
- "androidx.loader_loader",
- ],
+ resource_dirs: ["res"],
optimize: {
enabled: false,
},
- min_sdk_version: "24",
+ libs: ["android.car"],
+
+ static_libs: [
+ "EncryptionRunner",
+ "androidx.room_room-runtime",
+ "connected-device-protos",
+ ],
+
+ plugins: [
+ "androidx.room_room-compiler-plugin",
+ ],
+
+ platform_apis: true,
}
diff --git a/connected-device-lib/AndroidManifest.xml b/connected-device-lib/AndroidManifest.xml
new file mode 100644
index 0000000..d02ffce
--- /dev/null
+++ b/connected-device-lib/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<!--
+ ~ 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.car.connecteddevice">
+
+ <!-- Needed for BLE scanning/advertising -->
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+ <uses-permission android:name="android.permission.BLUETOOTH"/>
+ <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
+
+ <!-- Needed for detecting foreground user -->
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS"/>
+ <uses-permission android:name="android.permission.MANAGE_USERS" />
+</manifest>
diff --git a/connected-device-lib/OWNERS b/connected-device-lib/OWNERS
new file mode 100644
index 0000000..108da4e
--- /dev/null
+++ b/connected-device-lib/OWNERS
@@ -0,0 +1,5 @@
+# People who can approve changes for submission.
+nicksauer@google.com
+ramperry@google.com
+ajchen@google.com
+danharms@google.com
diff --git a/car-settings-lib/Android.bp b/connected-device-lib/proto/Android.bp
similarity index 68%
copy from car-settings-lib/Android.bp
copy to connected-device-lib/proto/Android.bp
index 9c4dbd5..c9dcb73 100644
--- a/car-settings-lib/Android.bp
+++ b/connected-device-lib/proto/Android.bp
@@ -1,3 +1,4 @@
+//
// Copyright (C) 2019 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -11,22 +12,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.
+//
-android_library {
- name: "car-settings-lib",
-
- srcs: ["src/**/*.java"],
-
- resource_dirs: ["res"],
-
- static_libs: [
- "androidx.annotation_annotation",
- "androidx.loader_loader",
- ],
-
- optimize: {
- enabled: false,
+java_library_static {
+ name: "connected-device-protos",
+ host_supported: true,
+ proto: {
+ type: "lite",
},
-
- min_sdk_version: "24",
+ srcs: ["*.proto"],
+ jarjar_rules: "jarjar-rules.txt",
+ sdk_version: "28",
}
diff --git a/connected-device-lib/proto/ble_device_message.proto b/connected-device-lib/proto/ble_device_message.proto
new file mode 100644
index 0000000..581d6a0
--- /dev/null
+++ b/connected-device-lib/proto/ble_device_message.proto
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+syntax = "proto3";
+
+package com.android.car.connecteddevice.proto;
+
+import "packages/apps/Car/libs/connected-device-lib/proto/operation_type.proto";
+
+option java_package = "com.android.car.connecteddevice.BleStreamProtos";
+option java_outer_classname = "BleDeviceMessageProto";
+
+// A message between devices.
+message BleDeviceMessage {
+ // The operation that this message represents.
+ OperationType operation = 1;
+
+ // Whether the payload field is encrypted.
+ bool is_payload_encrypted = 2;
+
+ // Identifier of the intended recipient.
+ bytes recipient = 3;
+
+ // The bytes that represent the content for this message.
+ bytes payload = 4;
+}
\ No newline at end of file
diff --git a/connected-device-lib/proto/ble_packet.proto b/connected-device-lib/proto/ble_packet.proto
new file mode 100644
index 0000000..c2ce262
--- /dev/null
+++ b/connected-device-lib/proto/ble_packet.proto
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+syntax = "proto3";
+
+package com.android.car.connecteddevice.proto;
+
+option java_package = "com.android.car.connecteddevice.BleStreamProtos";
+option java_outer_classname = "BlePacketProto";
+
+// A packet across a BLE channel.
+message BlePacket {
+ // A 1-based packet number. The first message will have a value of "1" rather
+ // than "0".
+ fixed32 packet_number = 1;
+
+ // The total number of packets in the message stream.
+ int32 total_packets = 2;
+
+ // Id of message for reassembly on other side
+ int32 message_id = 3;
+
+ // The bytes that represent the message content for this packet.
+ bytes payload = 4;
+}
diff --git a/connected-device-lib/proto/ble_version_exchange.proto b/connected-device-lib/proto/ble_version_exchange.proto
new file mode 100644
index 0000000..a7e8021
--- /dev/null
+++ b/connected-device-lib/proto/ble_version_exchange.proto
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+syntax = "proto3";
+
+package com.android.car.connecteddevice.proto;
+
+option java_package = "com.android.car.connecteddevice.BleStreamProtos";
+option java_outer_classname = "VersionExchangeProto";
+
+message BleVersionExchange {
+ // Minimum supported protobuf version.
+ int32 minSupportedMessagingVersion = 1;
+
+ // Maximum supported protobuf version.
+ int32 maxSupportedMessagingVersion = 2;
+
+ // Minimum supported version of the encryption engine.
+ int32 minSupportedSecurityVersion = 3;
+
+ // Maximum supported version of the encryption engine.
+ int32 maxSupportedSecurityVersion = 4;
+}
diff --git a/connected-device-lib/proto/jarjar-rules.txt b/connected-device-lib/proto/jarjar-rules.txt
new file mode 100644
index 0000000..d27aecb
--- /dev/null
+++ b/connected-device-lib/proto/jarjar-rules.txt
@@ -0,0 +1 @@
+rule com.google.protobuf.** com.android.car.protobuf.@1
diff --git a/connected-device-lib/proto/operation_type.proto b/connected-device-lib/proto/operation_type.proto
new file mode 100644
index 0000000..d447ccc
--- /dev/null
+++ b/connected-device-lib/proto/operation_type.proto
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+syntax = "proto3";
+
+package com.android.car.connecteddevice.proto;
+
+option java_package = "com.android.car.connecteddevice.BleStreamProtos";
+option java_outer_classname = "BleOperationProto";
+
+// The different message types that indicate the content of the payload.
+//
+// Ensure that these values are positive to reduce incurring too many bytes
+// to encode.
+enum OperationType {
+ // The contents of the payload are unknown.
+ //
+ // Note, this enum name is prefixed. See
+ // go/proto-best-practices-checkers#enum-default-value-name-conflict
+ OPERATION_TYPE_UNKNOWN = 0;
+
+ // The payload contains handshake messages needed to set up encryption.
+ ENCRYPTION_HANDSHAKE = 2;
+
+ // The message is an acknowledgment of a previously received message. The
+ // payload for this type should be empty.
+ ACK = 3;
+
+ // The payload contains a client-specific message.
+ CLIENT_MESSAGE = 4;
+}
diff --git a/connected-device-lib/res/values/config.xml b/connected-device-lib/res/values/config.xml
new file mode 100644
index 0000000..c052264
--- /dev/null
+++ b/connected-device-lib/res/values/config.xml
@@ -0,0 +1,28 @@
+<?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.
+ -->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <string name="car_service_uuid" translatable="false">5e2a68a8-27be-43f9-8d1e-4546976fabd7</string>
+ <string name="car_association_service_uuid" translatable="false">5e2a68a4-27be-43f9-8d1e-4546976fabd7</string>
+ <string name="car_bg_mask" translatable="false">00000000000000000000000000000000</string>
+
+ <string name="car_secure_read_uuid" translatable="false">5e2a68a6-27be-43f9-8d1e-4546976fabd7</string>
+ <string name="car_secure_write_uuid" translatable="false">5e2a68a5-27be-43f9-8d1e-4546976fabd7</string>
+
+ <string name="connected_device_shared_preferences" translatable="false">com.android.car.connecteddevice</string>
+</resources>
diff --git a/connected-device-lib/src/com/android/car/connecteddevice/AssociationCallback.java b/connected-device-lib/src/com/android/car/connecteddevice/AssociationCallback.java
new file mode 100644
index 0000000..fb7000b
--- /dev/null
+++ b/connected-device-lib/src/com/android/car/connecteddevice/AssociationCallback.java
@@ -0,0 +1,56 @@
+/*
+ * 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.car.connecteddevice;
+
+import android.annotation.NonNull;
+
+/** Callbacks that will be invoked during associating a new client. */
+public interface AssociationCallback {
+
+ /**
+ * Invoked when IHU starts advertising with its device name for association successfully.
+ *
+ * @param deviceName The device name to identify the car.
+ */
+ void onAssociationStartSuccess(@NonNull String deviceName);
+
+ /** Invoked when IHU failed to start advertising for association. */
+ void onAssociationStartFailure();
+
+ /**
+ * Invoked when a {@link ConnectedDeviceManager.DeviceError} has been encountered in attempting
+ * to associate a new device.
+ *
+ * @param error The failure indication.
+ */
+ void onAssociationError(@ConnectedDeviceManager.DeviceError int error);
+
+ /**
+ * Invoked when a verification code needs to be displayed. The user needs to confirm, and
+ * then call {@link ConnectedDeviceManager#notifyOutOfBandAccepted()}.
+ *
+ * @param code The verification code.
+ */
+ void onVerificationCodeAvailable(@NonNull String code);
+
+ /**
+ * Invoked when the association has completed.
+ *
+ * @param deviceId The id of the newly associated device.
+ */
+ void onAssociationCompleted(@NonNull String deviceId);
+}
diff --git a/connected-device-lib/src/com/android/car/connecteddevice/ConnectedDeviceManager.java b/connected-device-lib/src/com/android/car/connecteddevice/ConnectedDeviceManager.java
new file mode 100644
index 0000000..20a86ac
--- /dev/null
+++ b/connected-device-lib/src/com/android/car/connecteddevice/ConnectedDeviceManager.java
@@ -0,0 +1,851 @@
+/*
+ * 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.car.connecteddevice;
+
+import static com.android.car.connecteddevice.util.SafeLog.logd;
+import static com.android.car.connecteddevice.util.SafeLog.loge;
+import static com.android.car.connecteddevice.util.SafeLog.logw;
+
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+
+import com.android.car.connecteddevice.ble.BleCentralManager;
+import com.android.car.connecteddevice.ble.BlePeripheralManager;
+import com.android.car.connecteddevice.ble.CarBleCentralManager;
+import com.android.car.connecteddevice.ble.CarBleManager;
+import com.android.car.connecteddevice.ble.CarBlePeripheralManager;
+import com.android.car.connecteddevice.ble.DeviceMessage;
+import com.android.car.connecteddevice.model.AssociatedDevice;
+import com.android.car.connecteddevice.model.ConnectedDevice;
+import com.android.car.connecteddevice.storage.ConnectedDeviceStorage;
+import com.android.car.connecteddevice.storage.ConnectedDeviceStorage.AssociatedDeviceCallback;
+import com.android.car.connecteddevice.util.ByteUtils;
+import com.android.car.connecteddevice.util.ThreadSafeCallbacks;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.lang.annotation.Retention;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Consumer;
+
+/** Manager of devices connected to the car. */
+public class ConnectedDeviceManager {
+
+ private static final String TAG = "ConnectedDeviceManager";
+
+ // Device name length is limited by available bytes in BLE advertisement data packet.
+ //
+ // BLE advertisement limits data packet length to 31
+ // Currently we send:
+ // - 18 bytes for 16 chars UUID: 16 bytes + 2 bytes for header;
+ // - 3 bytes for advertisement being connectable;
+ // which leaves 10 bytes.
+ // Subtracting 2 bytes used by header, we have 8 bytes for device name.
+ private static final int DEVICE_NAME_LENGTH_LIMIT = 8;
+
+ private final ConnectedDeviceStorage mStorage;
+
+ private final CarBleCentralManager mCentralManager;
+
+ private final CarBlePeripheralManager mPeripheralManager;
+
+ private final ThreadSafeCallbacks<DeviceAssociationCallback> mDeviceAssociationCallbacks =
+ new ThreadSafeCallbacks<>();
+
+ private final ThreadSafeCallbacks<ConnectionCallback> mActiveUserConnectionCallbacks =
+ new ThreadSafeCallbacks<>();
+
+ private final ThreadSafeCallbacks<ConnectionCallback> mAllUserConnectionCallbacks =
+ new ThreadSafeCallbacks<>();
+
+ // deviceId -> (recipientId -> callbacks)
+ private final Map<String, Map<UUID, ThreadSafeCallbacks<DeviceCallback>>> mDeviceCallbacks =
+ new ConcurrentHashMap<>();
+
+ // deviceId -> device
+ private final Map<String, InternalConnectedDevice> mConnectedDevices =
+ new ConcurrentHashMap<>();
+
+ // recipientId -> (deviceId -> message bytes)
+ private final Map<UUID, Map<String, byte[]>> mRecipientMissedMessages =
+ new ConcurrentHashMap<>();
+
+ // Recipient ids that received multiple callback registrations indicate that the recipient id
+ // has been compromised. Another party now has access the messages intended for that recipient.
+ // As a safeguard, that recipient id will be added to this list and blocked from further
+ // callback notifications.
+ private final Set<UUID> mBlacklistedRecipients = new CopyOnWriteArraySet<>();
+
+ private final AtomicBoolean mIsConnectingToUserDevice = new AtomicBoolean(false);
+
+ private String mNameForAssociation;
+
+ private AssociationCallback mAssociationCallback;
+
+ @Retention(SOURCE)
+ @IntDef(prefix = { "DEVICE_ERROR_" },
+ value = {
+ DEVICE_ERROR_INVALID_HANDSHAKE,
+ DEVICE_ERROR_INVALID_MSG,
+ DEVICE_ERROR_INVALID_DEVICE_ID,
+ DEVICE_ERROR_INVALID_VERIFICATION,
+ DEVICE_ERROR_INVALID_CHANNEL_STATE,
+ DEVICE_ERROR_INVALID_ENCRYPTION_KEY,
+ DEVICE_ERROR_STORAGE_FAILURE,
+ DEVICE_ERROR_INVALID_SECURITY_KEY,
+ DEVICE_ERROR_INSECURE_RECIPIENT_ID_DETECTED
+ }
+ )
+ public @interface DeviceError {}
+ public static final int DEVICE_ERROR_INVALID_HANDSHAKE = 0;
+ public static final int DEVICE_ERROR_INVALID_MSG = 1;
+ public static final int DEVICE_ERROR_INVALID_DEVICE_ID = 2;
+ public static final int DEVICE_ERROR_INVALID_VERIFICATION = 3;
+ public static final int DEVICE_ERROR_INVALID_CHANNEL_STATE = 4;
+ public static final int DEVICE_ERROR_INVALID_ENCRYPTION_KEY = 5;
+ public static final int DEVICE_ERROR_STORAGE_FAILURE = 6;
+ public static final int DEVICE_ERROR_INVALID_SECURITY_KEY = 7;
+ public static final int DEVICE_ERROR_INSECURE_RECIPIENT_ID_DETECTED = 8;
+
+ public ConnectedDeviceManager(@NonNull Context context) {
+ this(context, new ConnectedDeviceStorage(context), new BleCentralManager(context),
+ new BlePeripheralManager(context),
+ UUID.fromString(context.getString(R.string.car_service_uuid)),
+ UUID.fromString(context.getString(R.string.car_association_service_uuid)),
+ context.getString(R.string.car_bg_mask),
+ UUID.fromString(context.getString(R.string.car_secure_write_uuid)),
+ UUID.fromString(context.getString(R.string.car_secure_read_uuid)));
+ }
+
+ private ConnectedDeviceManager(
+ @NonNull Context context,
+ @NonNull ConnectedDeviceStorage storage,
+ @NonNull BleCentralManager bleCentralManager,
+ @NonNull BlePeripheralManager blePeripheralManager,
+ @NonNull UUID serviceUuid,
+ @NonNull UUID associationServiceUuid,
+ @NonNull String bgMask,
+ @NonNull UUID writeCharacteristicUuid,
+ @NonNull UUID readCharacteristicUuid) {
+ this(storage,
+ new CarBleCentralManager(context, bleCentralManager, storage, serviceUuid, bgMask,
+ writeCharacteristicUuid, readCharacteristicUuid),
+ new CarBlePeripheralManager(blePeripheralManager, storage, associationServiceUuid,
+ writeCharacteristicUuid, readCharacteristicUuid));
+ }
+
+ @VisibleForTesting
+ ConnectedDeviceManager(
+ @NonNull ConnectedDeviceStorage storage,
+ @NonNull CarBleCentralManager centralManager,
+ @NonNull CarBlePeripheralManager peripheralManager) {
+ Executor callbackExecutor = Executors.newSingleThreadExecutor();
+ mStorage = storage;
+ mCentralManager = centralManager;
+ mPeripheralManager = peripheralManager;
+ mCentralManager.registerCallback(generateCarBleCallback(centralManager), callbackExecutor);
+ mPeripheralManager.registerCallback(generateCarBleCallback(peripheralManager),
+ callbackExecutor);
+ mStorage.setAssociatedDeviceCallback(mAssociatedDeviceCallback);
+ }
+
+ /**
+ * Start internal processes and begin discovering devices. Must be called before any
+ * connections can be made using {@link #connectToActiveUserDevice()}.
+ */
+ public void start() {
+ logd(TAG, "Starting ConnectedDeviceManager.");
+ //mCentralManager.start();
+ mPeripheralManager.start();
+ connectToActiveUserDevice();
+ }
+
+ /** Clean up internal processes and disconnect any active connections. */
+ public void cleanup() {
+ logd(TAG, "Cleaning up ConnectedDeviceManager.");
+ mIsConnectingToUserDevice.set(false);
+ mCentralManager.stop();
+ mPeripheralManager.stop();
+ mDeviceCallbacks.clear();
+ mDeviceAssociationCallbacks.clear();
+ mActiveUserConnectionCallbacks.clear();
+ mAllUserConnectionCallbacks.clear();
+ mStorage.clearAssociationDeviceCallback();
+ }
+
+ /** Returns {@link List<ConnectedDevice>} of devices currently connected. */
+ @NonNull
+ public List<ConnectedDevice> getActiveUserConnectedDevices() {
+ List<ConnectedDevice> activeUserConnectedDevices = new ArrayList<>();
+ for (InternalConnectedDevice device : mConnectedDevices.values()) {
+ if (device.mConnectedDevice.isAssociatedWithActiveUser()) {
+ activeUserConnectedDevices.add(device.mConnectedDevice);
+ }
+ }
+ logd(TAG, "Returned " + activeUserConnectedDevices.size() + " active user devices.");
+ return activeUserConnectedDevices;
+ }
+
+ /**
+ * Register a callback for triggered associated device related events.
+ *
+ * @param callback {@link DeviceAssociationCallback} to register.
+ * @param executor {@link Executor} to execute triggers on.
+ */
+ public void registerDeviceAssociationCallback(@NonNull DeviceAssociationCallback callback,
+ @NonNull @CallbackExecutor Executor executor) {
+ mDeviceAssociationCallbacks.add(callback, executor);
+ }
+
+ /**
+ * Unregister a device association callback.
+ *
+ * @param callback {@link DeviceAssociationCallback} to unregister.
+ */
+ public void unregisterDeviceAssociationCallback(@NonNull DeviceAssociationCallback callback) {
+ mDeviceAssociationCallbacks.remove(callback);
+ }
+
+ /**
+ * Register a callback for manager triggered connection events for only the currently active
+ * user's devices.
+ *
+ * @param callback {@link ConnectionCallback} to register.
+ * @param executor {@link Executor} to execute triggers on.
+ */
+ public void registerActiveUserConnectionCallback(@NonNull ConnectionCallback callback,
+ @NonNull @CallbackExecutor Executor executor) {
+ mActiveUserConnectionCallbacks.add(callback, executor);
+ }
+
+ /**
+ * Unregister a connection callback from manager.
+ *
+ * @param callback {@link ConnectionCallback} to unregister.
+ */
+ public void unregisterConnectionCallback(ConnectionCallback callback) {
+ mActiveUserConnectionCallbacks.remove(callback);
+ mAllUserConnectionCallbacks.remove(callback);
+ }
+
+ /** Connect to a device for the active user if available. */
+ @VisibleForTesting
+ void connectToActiveUserDevice() {
+ Executors.defaultThreadFactory().newThread(() -> {
+ logd(TAG, "Received request to connect to active user's device.");
+ connectToActiveUserDeviceInternal();
+ }).start();
+ }
+
+ private void connectToActiveUserDeviceInternal() {
+ try {
+ if (mIsConnectingToUserDevice.get()) {
+ logd(TAG, "A request has already been made to connect to this user's device. "
+ + "Ignoring redundant request.");
+ return;
+ }
+ List<String> userDeviceIds = mStorage.getActiveUserAssociatedDeviceIds();
+ if (userDeviceIds.isEmpty()) {
+ logw(TAG, "No devices associated with active user. Ignoring.");
+ return;
+ }
+
+ // Only currently support one device per user for fast association, so take the
+ // first one.
+ String userDeviceId = userDeviceIds.get(0);
+ if (mConnectedDevices.containsKey(userDeviceId)) {
+ logd(TAG, "Device has already been connected. No need to attempt connection "
+ + "again.");
+ return;
+ }
+ mIsConnectingToUserDevice.set(true);
+ mPeripheralManager.connectToDevice(UUID.fromString(userDeviceId));
+ } catch (Exception e) {
+ loge(TAG, "Exception while attempting connection with active user's device.", e);
+ }
+ }
+
+ /**
+ * Start the association with a new device.
+ *
+ * @param callback Callback for association events.
+ */
+ public void startAssociation(@NonNull AssociationCallback callback) {
+ mAssociationCallback = callback;
+ mPeripheralManager.startAssociation(getNameForAssociation(), mInternalAssociationCallback);
+ }
+
+ /** Stop the association with any device. */
+ public void stopAssociation(@NonNull AssociationCallback callback) {
+ if (mAssociationCallback != callback) {
+ logd(TAG, "Stop association called with unrecognized callback. Ignoring.");
+ return;
+ }
+ mAssociationCallback = null;
+ mPeripheralManager.stopAssociation(mInternalAssociationCallback);
+ }
+
+ /**
+ * Get a list of associated devices for the given user.
+ *
+ * @return Associated device list.
+ */
+ @NonNull
+ public List<AssociatedDevice> getActiveUserAssociatedDevices() {
+ return mStorage.getActiveUserAssociatedDevices();
+ }
+
+ /** Notify that the user has accepted a pairing code or any out-of-band confirmation. */
+ public void notifyOutOfBandAccepted() {
+ mPeripheralManager.notifyOutOfBandAccepted();
+ }
+
+ /**
+ * Remove the associated device with the given device identifier for the current user.
+ *
+ * @param deviceId Device identifier.
+ */
+ public void removeActiveUserAssociatedDevice(@NonNull String deviceId) {
+ if (mConnectedDevices.containsKey(deviceId)) {
+ removeConnectedDevice(deviceId, mPeripheralManager);
+ mPeripheralManager.stop();
+ }
+ mStorage.removeAssociatedDeviceForActiveUser(deviceId);
+ logd(TAG, "Successfully removed associated device " + deviceId + ".");
+ }
+
+ /**
+ * Register a callback for a specific device and recipient.
+ *
+ * @param device {@link ConnectedDevice} to register triggers on.
+ * @param recipientId {@link UUID} to register as recipient of.
+ * @param callback {@link DeviceCallback} to register.
+ * @param executor {@link Executor} on which to execute callback.
+ */
+ public void registerDeviceCallback(@NonNull ConnectedDevice device, @NonNull UUID recipientId,
+ @NonNull DeviceCallback callback, @NonNull @CallbackExecutor Executor executor) {
+ if (isRecipientBlacklisted(recipientId)) {
+ notifyOfBlacklisting(device, recipientId, callback, executor);
+ return;
+ }
+ logd(TAG, "New callback registered on device " + device.getDeviceId() + " for recipient "
+ + recipientId);
+ String deviceId = device.getDeviceId();
+ Map<UUID, ThreadSafeCallbacks<DeviceCallback>> recipientCallbacks =
+ mDeviceCallbacks.computeIfAbsent(deviceId, key -> new HashMap<>());
+
+ // Device already has a callback registered with this recipient UUID. For the
+ // protection of the user, this UUID is now blacklisted from future subscriptions
+ // and the original subscription is notified and removed.
+ if (recipientCallbacks.containsKey(recipientId)) {
+ blacklistRecipient(deviceId, recipientId);
+ notifyOfBlacklisting(device, recipientId, callback, executor);
+ return;
+ }
+
+ ThreadSafeCallbacks<DeviceCallback> newCallbacks = new ThreadSafeCallbacks<>();
+ newCallbacks.add(callback, executor);
+ recipientCallbacks.put(recipientId, newCallbacks);
+
+ byte[] message = popMissedMessage(recipientId, device.getDeviceId());
+ if (message != null) {
+ newCallbacks.invoke(deviceCallback ->
+ deviceCallback.onMessageReceived(device, message));
+ }
+ }
+
+ private void notifyOfBlacklisting(@NonNull ConnectedDevice device, @NonNull UUID recipientId,
+ @NonNull DeviceCallback callback, @NonNull Executor executor) {
+ loge(TAG, "Multiple callbacks registered for recipient " + recipientId + "! Your "
+ + "recipient id is no longer secure and has been blocked from future use.");
+ executor.execute(() ->
+ callback.onDeviceError(device, DEVICE_ERROR_INSECURE_RECIPIENT_ID_DETECTED));
+ }
+
+ private void saveMissedMessage(@NonNull String deviceId, @NonNull UUID recipientId,
+ @NonNull byte[] message) {
+ // Store last message in case recipient registers callbacks in the future.
+ logd(TAG, "No recipient registered for device " + deviceId + " and recipient "
+ + recipientId + " combination. Saving message.");
+ mRecipientMissedMessages.putIfAbsent(recipientId, new HashMap<>());
+ mRecipientMissedMessages.get(recipientId).putIfAbsent(deviceId, message);
+ }
+
+ /**
+ * Remove the last message sent for this device prior to a {@link DeviceCallback} being
+ * registered.
+ *
+ * @param recipientId Recipient's id
+ * @param deviceId Device id
+ * @return The last missed {@code byte[]} of the message, or {@code null} if no messages were
+ * missed.
+ */
+ @Nullable
+ private byte[] popMissedMessage(@NonNull UUID recipientId, @NonNull String deviceId) {
+ Map<String, byte[]> missedMessages = mRecipientMissedMessages.get(recipientId);
+ if (missedMessages == null) {
+ return null;
+ }
+
+ return missedMessages.remove(deviceId);
+ }
+
+ /**
+ * Unregister callback from device events.
+ *
+ * @param device {@link ConnectedDevice} callback was registered on.
+ * @param recipientId {@link UUID} callback was registered under.
+ * @param callback {@link DeviceCallback} to unregister.
+ */
+ public void unregisterDeviceCallback(@NonNull ConnectedDevice device,
+ @NonNull UUID recipientId, @NonNull DeviceCallback callback) {
+ logd(TAG, "Device callback unregistered on device " + device.getDeviceId() + " for "
+ + "recipient " + recipientId + ".");
+
+ Map<UUID, ThreadSafeCallbacks<DeviceCallback>> recipientCallbacks =
+ mDeviceCallbacks.get(device.getDeviceId());
+ if (recipientCallbacks == null) {
+ return;
+ }
+ ThreadSafeCallbacks<DeviceCallback> callbacks = recipientCallbacks.get(recipientId);
+ if (callbacks == null) {
+ return;
+ }
+
+ callbacks.remove(callback);
+ if (callbacks.size() == 0) {
+ recipientCallbacks.remove(recipientId);
+ }
+ }
+
+ /**
+ * Securely send message to a device.
+ *
+ * @param device {@link ConnectedDevice} to send the message to.
+ * @param recipientId Recipient {@link UUID}.
+ * @param message Message to send.
+ * @throws IllegalStateException Secure channel has not been established.
+ */
+ public void sendMessageSecurely(@NonNull ConnectedDevice device, @NonNull UUID recipientId,
+ @NonNull byte[] message) throws IllegalStateException {
+ sendMessage(device, recipientId, message, /* isEncrypted = */ true);
+ }
+
+ /**
+ * Send an unencrypted message to a device.
+ *
+ * @param device {@link ConnectedDevice} to send the message to.
+ * @param recipientId Recipient {@link UUID}.
+ * @param message Message to send.
+ */
+ public void sendMessageUnsecurely(@NonNull ConnectedDevice device, @NonNull UUID recipientId,
+ @NonNull byte[] message) {
+ sendMessage(device, recipientId, message, /* isEncrypted = */ false);
+ }
+
+ private void sendMessage(@NonNull ConnectedDevice device, @NonNull UUID recipientId,
+ @NonNull byte[] message, boolean isEncrypted) throws IllegalStateException {
+ String deviceId = device.getDeviceId();
+ logd(TAG, "Sending new message to device " + deviceId + " for " + recipientId
+ + " containing " + message.length + ". Message will be sent securely: "
+ + isEncrypted + ".");
+
+ InternalConnectedDevice connectedDevice = mConnectedDevices.get(deviceId);
+ if (connectedDevice == null) {
+ loge(TAG, "Attempted to send message to unknown device " + deviceId + ". Ignoring.");
+ return;
+ }
+
+ if (isEncrypted && !connectedDevice.mConnectedDevice.hasSecureChannel()) {
+ throw new IllegalStateException("Cannot send a message securely to device that has not "
+ + "established a secure channel.");
+ }
+
+ connectedDevice.mCarBleManager.sendMessage(deviceId,
+ new DeviceMessage(recipientId, isEncrypted, message));
+ }
+
+ private boolean isRecipientBlacklisted(UUID recipientId) {
+ return mBlacklistedRecipients.contains(recipientId);
+ }
+
+ private void blacklistRecipient(@NonNull String deviceId, @NonNull UUID recipientId) {
+ Map<UUID, ThreadSafeCallbacks<DeviceCallback>> recipientCallbacks =
+ mDeviceCallbacks.get(deviceId);
+ if (recipientCallbacks == null) {
+ // Should never happen, but null-safety check.
+ return;
+ }
+
+ ThreadSafeCallbacks<DeviceCallback> existingCallback = recipientCallbacks.get(recipientId);
+ if (existingCallback == null) {
+ // Should never happen, but null-safety check.
+ return;
+ }
+
+ InternalConnectedDevice connectedDevice = mConnectedDevices.get(deviceId);
+ if (connectedDevice != null) {
+ recipientCallbacks.get(recipientId).invoke(
+ callback ->
+ callback.onDeviceError(connectedDevice.mConnectedDevice,
+ DEVICE_ERROR_INSECURE_RECIPIENT_ID_DETECTED)
+ );
+ }
+
+ recipientCallbacks.remove(recipientId);
+ mBlacklistedRecipients.add(recipientId);
+ }
+
+ @VisibleForTesting
+ void addConnectedDevice(@NonNull String deviceId, @NonNull CarBleManager bleManager) {
+ if (mConnectedDevices.containsKey(deviceId)) {
+ // Device already connected. No-op until secure channel established.
+ return;
+ }
+ logd(TAG, "New device with id " + deviceId + " connected.");
+ ConnectedDevice connectedDevice = new ConnectedDevice(
+ deviceId,
+ /* deviceName = */ null,
+ mStorage.getActiveUserAssociatedDeviceIds().contains(deviceId),
+ /* hasSecureChannel = */ false
+ );
+
+ mConnectedDevices.put(deviceId, new InternalConnectedDevice(connectedDevice, bleManager));
+ invokeConnectionCallbacks(connectedDevice.isAssociatedWithActiveUser(),
+ callback -> callback.onDeviceConnected(connectedDevice));
+ }
+
+ @VisibleForTesting
+ void removeConnectedDevice(@NonNull String deviceId, @NonNull CarBleManager bleManager) {
+ logd(TAG, "Device " + deviceId + " disconnected from manager " + bleManager);
+ InternalConnectedDevice connectedDevice = getConnectedDeviceForManager(deviceId,
+ bleManager);
+
+ // If disconnect happened on peripheral, open for future requests to connect.
+ if (bleManager == mPeripheralManager) {
+ mIsConnectingToUserDevice.set(false);
+ }
+
+ if (connectedDevice == null) {
+ return;
+ }
+
+ mConnectedDevices.remove(deviceId);
+ boolean isAssociated = connectedDevice.mConnectedDevice.isAssociatedWithActiveUser();
+ invokeConnectionCallbacks(isAssociated,
+ callback -> callback.onDeviceDisconnected(connectedDevice.mConnectedDevice));
+
+ if (isAssociated) {
+ // Try to regain connection to active user's device.
+ connectToActiveUserDevice();
+ }
+ }
+
+ @VisibleForTesting
+ void onSecureChannelEstablished(@NonNull String deviceId,
+ @NonNull CarBleManager bleManager) {
+ if (mConnectedDevices.get(deviceId) == null) {
+ loge(TAG, "Secure channel established on unknown device " + deviceId + ".");
+ return;
+ }
+ ConnectedDevice connectedDevice = mConnectedDevices.get(deviceId).mConnectedDevice;
+ ConnectedDevice updatedConnectedDevice = new ConnectedDevice(connectedDevice.getDeviceId(),
+ connectedDevice.getDeviceName(), connectedDevice.isAssociatedWithActiveUser(),
+ /* hasSecureChannel = */ true);
+
+ boolean notifyCallbacks = getConnectedDeviceForManager(deviceId, bleManager) != null;
+
+ // TODO (b/143088482) Implement interrupt
+ // Ignore if central already holds the active device connection and interrupt the
+ // connection.
+
+ mConnectedDevices.put(deviceId,
+ new InternalConnectedDevice(updatedConnectedDevice, bleManager));
+ logd(TAG, "Secure channel established to " + deviceId + " . Notifying callbacks: "
+ + notifyCallbacks + ".");
+ if (notifyCallbacks) {
+ notifyAllDeviceCallbacks(deviceId,
+ callback -> callback.onSecureChannelEstablished(updatedConnectedDevice));
+ }
+ }
+
+ @VisibleForTesting
+ void onMessageReceived(@NonNull String deviceId, @NonNull DeviceMessage message) {
+ logd(TAG, "New message received from device " + deviceId + " intended for "
+ + message.getRecipient() + " containing " + message.getMessage().length
+ + " bytes.");
+
+ InternalConnectedDevice connectedDevice = mConnectedDevices.get(deviceId);
+ if (connectedDevice == null) {
+ logw(TAG, "Received message from unknown device " + deviceId + "or to unknown "
+ + "recipient " + message.getRecipient() + ".");
+ return;
+ }
+ UUID recipientId = message.getRecipient();
+ Map<UUID, ThreadSafeCallbacks<DeviceCallback>> deviceCallbacks =
+ mDeviceCallbacks.get(deviceId);
+ if (deviceCallbacks == null) {
+ saveMissedMessage(deviceId, recipientId, message.getMessage());
+ return;
+ }
+ ThreadSafeCallbacks<DeviceCallback> recipientCallbacks =
+ deviceCallbacks.get(recipientId);
+ if (recipientCallbacks == null) {
+ saveMissedMessage(deviceId, recipientId, message.getMessage());
+ return;
+ }
+
+ recipientCallbacks.invoke(
+ callback -> callback.onMessageReceived(connectedDevice.mConnectedDevice,
+ message.getMessage()));
+ }
+
+ @VisibleForTesting
+ void deviceErrorOccurred(@NonNull String deviceId) {
+ InternalConnectedDevice connectedDevice = mConnectedDevices.get(deviceId);
+ if (connectedDevice == null) {
+ logw(TAG, "Failed to establish secure channel on unknown device " + deviceId + ".");
+ return;
+ }
+
+ notifyAllDeviceCallbacks(deviceId,
+ callback -> callback.onDeviceError(connectedDevice.mConnectedDevice,
+ DEVICE_ERROR_INVALID_SECURITY_KEY));
+ }
+
+ @VisibleForTesting
+ void onAssociationCompleted(@NonNull String deviceId) {
+ InternalConnectedDevice connectedDevice =
+ getConnectedDeviceForManager(deviceId, mPeripheralManager);
+ if (connectedDevice == null) {
+ return;
+ }
+
+ // The previous device is now obsolete and should be replaced with a new one properly
+ // reflecting the state of belonging to the active user and notify features.
+ if (connectedDevice.mConnectedDevice.isAssociatedWithActiveUser()) {
+ // Device was already marked as belonging to active user. No need to reissue callbacks.
+ return;
+ }
+ removeConnectedDevice(deviceId, mPeripheralManager);
+ addConnectedDevice(deviceId, mPeripheralManager);
+ }
+
+ @NonNull
+ private List<String> getActiveUserDeviceIds() {
+ return mStorage.getActiveUserAssociatedDeviceIds();
+ }
+
+ @Nullable
+ private InternalConnectedDevice getConnectedDeviceForManager(@NonNull String deviceId,
+ @NonNull CarBleManager bleManager) {
+ InternalConnectedDevice connectedDevice = mConnectedDevices.get(deviceId);
+ if (connectedDevice != null && connectedDevice.mCarBleManager == bleManager) {
+ return connectedDevice;
+ }
+
+ return null;
+ }
+
+ private void invokeConnectionCallbacks(boolean belongsToActiveUser,
+ @NonNull Consumer<ConnectionCallback> notification) {
+ logd(TAG, "Notifying connection callbacks for device belonging to active user "
+ + belongsToActiveUser + ".");
+ if (belongsToActiveUser) {
+ mActiveUserConnectionCallbacks.invoke(notification);
+ }
+ mAllUserConnectionCallbacks.invoke(notification);
+ }
+
+ private void notifyAllDeviceCallbacks(@NonNull String deviceId,
+ @NonNull Consumer<DeviceCallback> notification) {
+ logd(TAG, "Notifying all device callbacks for device " + deviceId + ".");
+ Map<UUID, ThreadSafeCallbacks<DeviceCallback>> deviceCallbacks =
+ mDeviceCallbacks.get(deviceId);
+ if (deviceCallbacks == null) {
+ return;
+ }
+
+ for (ThreadSafeCallbacks<DeviceCallback> callbacks : deviceCallbacks.values()) {
+ callbacks.invoke(notification);
+ }
+ }
+
+ /**
+ * Returns the name that should be used for the device during enrollment of a trusted device.
+ *
+ * <p>The returned name will be a combination of a prefix sysprop and randomized digits.
+ */
+ @NonNull
+ private String getNameForAssociation() {
+ if (mNameForAssociation == null) {
+ mNameForAssociation = ByteUtils.generateRandomNumberString(DEVICE_NAME_LENGTH_LIMIT);
+ }
+ return mNameForAssociation;
+ }
+
+ @NonNull
+ private CarBleManager.Callback generateCarBleCallback(@NonNull CarBleManager carBleManager) {
+ return new CarBleManager.Callback() {
+ @Override
+ public void onDeviceConnected(String deviceId) {
+ addConnectedDevice(deviceId, carBleManager);
+ }
+
+ @Override
+ public void onDeviceDisconnected(String deviceId) {
+ removeConnectedDevice(deviceId, carBleManager);
+ }
+
+ @Override
+ public void onSecureChannelEstablished(String deviceId) {
+ ConnectedDeviceManager.this.onSecureChannelEstablished(deviceId, carBleManager);
+ }
+
+ @Override
+ public void onMessageReceived(String deviceId, DeviceMessage message) {
+ ConnectedDeviceManager.this.onMessageReceived(deviceId, message);
+ }
+
+ @Override
+ public void onSecureChannelError(String deviceId) {
+ deviceErrorOccurred(deviceId);
+ }
+ };
+ }
+
+ private final AssociationCallback mInternalAssociationCallback = new AssociationCallback() {
+ @Override
+ public void onAssociationStartSuccess(String deviceName) {
+ if (mAssociationCallback != null) {
+ mAssociationCallback.onAssociationStartSuccess(deviceName);
+ }
+ }
+
+ @Override
+ public void onAssociationStartFailure() {
+ if (mAssociationCallback != null) {
+ mAssociationCallback.onAssociationStartFailure();
+ }
+ }
+
+ @Override
+ public void onAssociationError(int error) {
+ if (mAssociationCallback != null) {
+ mAssociationCallback.onAssociationError(error);
+ }
+ }
+
+ @Override
+ public void onVerificationCodeAvailable(String code) {
+ if (mAssociationCallback != null) {
+ mAssociationCallback.onVerificationCodeAvailable(code);
+ }
+ }
+
+ @Override
+ public void onAssociationCompleted(String deviceId) {
+ if (mAssociationCallback != null) {
+ mAssociationCallback.onAssociationCompleted(deviceId);
+ }
+ ConnectedDeviceManager.this.onAssociationCompleted(deviceId);
+ }
+ };
+
+ private final AssociatedDeviceCallback mAssociatedDeviceCallback =
+ new AssociatedDeviceCallback() {
+ @Override
+ public void onAssociatedDeviceAdded(String deviceId) {
+ mDeviceAssociationCallbacks.invoke(callback ->
+ callback.onAssociatedDeviceAdded(deviceId));
+ }
+
+ @Override
+ public void onAssociatedDeviceRemoved(String deviceId) {
+ mDeviceAssociationCallbacks.invoke(callback ->
+ callback.onAssociatedDeviceRemoved(deviceId));
+ }
+
+ @Override
+ public void onAssociatedDeviceUpdated(AssociatedDevice device) {
+ mDeviceAssociationCallbacks.invoke(callback ->
+ callback.onAssociatedDeviceUpdated(device));
+ }
+ };
+
+ /** Callback for triggered connection events from {@link ConnectedDeviceManager}. */
+ public interface ConnectionCallback {
+ /** Triggered when a new device has connected. */
+ void onDeviceConnected(@NonNull ConnectedDevice device);
+
+ /** Triggered when a device has disconnected. */
+ void onDeviceDisconnected(@NonNull ConnectedDevice device);
+ }
+
+ /** Triggered device events for a connected device from {@link ConnectedDeviceManager}. */
+ public interface DeviceCallback {
+ /**
+ * Triggered when secure channel has been established on a device. Encrypted messaging now
+ * available.
+ */
+ void onSecureChannelEstablished(@NonNull ConnectedDevice device);
+
+ /** Triggered when a new message is received from a device. */
+ void onMessageReceived(@NonNull ConnectedDevice device, @NonNull byte[] message);
+
+ /** Triggered when an error has occurred for a device. */
+ void onDeviceError(@NonNull ConnectedDevice device, @DeviceError int error);
+ }
+
+ /** Callback for association device related events. */
+ public interface DeviceAssociationCallback {
+
+ /** Triggered when an associated device has been added */
+ void onAssociatedDeviceAdded(@NonNull String deviceId);
+
+ /** Triggered when an associated device has been removed. */
+ void onAssociatedDeviceRemoved(@NonNull String deviceId);
+
+ /** Triggered when the name of an associated device has been updated. */
+ void onAssociatedDeviceUpdated(@NonNull AssociatedDevice device);
+ }
+
+ private static class InternalConnectedDevice {
+ private final ConnectedDevice mConnectedDevice;
+ private final CarBleManager mCarBleManager;
+
+ InternalConnectedDevice(@NonNull ConnectedDevice connectedDevice,
+ @NonNull CarBleManager carBleManager) {
+ mConnectedDevice = connectedDevice;
+ mCarBleManager = carBleManager;
+ }
+ }
+}
diff --git a/connected-device-lib/src/com/android/car/connecteddevice/ble/BleCentralManager.java b/connected-device-lib/src/com/android/car/connecteddevice/ble/BleCentralManager.java
new file mode 100644
index 0000000..ca83a05
--- /dev/null
+++ b/connected-device-lib/src/com/android/car/connecteddevice/ble/BleCentralManager.java
@@ -0,0 +1,194 @@
+/*
+ * 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.car.connecteddevice.ble;
+
+import static com.android.car.connecteddevice.util.SafeLog.logd;
+import static com.android.car.connecteddevice.util.SafeLog.loge;
+import static com.android.car.connecteddevice.util.SafeLog.logw;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.le.BluetoothLeScanner;
+import android.bluetooth.le.ScanCallback;
+import android.bluetooth.le.ScanFilter;
+import android.bluetooth.le.ScanResult;
+import android.bluetooth.le.ScanSettings;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Handler;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Class that manages BLE scanning operations.
+ */
+public class BleCentralManager {
+
+ private static final String TAG = "BleCentralManager";
+
+ private static final int RETRY_LIMIT = 5;
+
+ private static final int RETRY_INTERVAL_MS = 1000;
+
+ private final Context mContext;
+
+ private final Handler mHandler;
+
+ private List<ScanFilter> mScanFilters;
+
+ private ScanSettings mScanSettings;
+
+ private ScanCallback mScanCallback;
+
+ private BluetoothLeScanner mScanner;
+
+ private int mScannerStartCount = 0;
+
+ private AtomicInteger mScannerState = new AtomicInteger(STOPPED);
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({
+ STOPPED,
+ STARTED,
+ SCANNING
+ })
+ private @interface ScannerState {}
+ private static final int STOPPED = 0;
+ private static final int STARTED = 1;
+ private static final int SCANNING = 2;
+
+ public BleCentralManager(@NonNull Context context) {
+ mContext = context;
+ mHandler = new Handler(context.getMainLooper());
+ }
+
+ /**
+ * Start the BLE scanning process.
+ *
+ * @param filters Optional list of {@link ScanFilter}s to apply to scan results.
+ * @param settings {@link ScanSettings} to apply to scanner.
+ * @param callback {@link ScanCallback} for scan events.
+ */
+ public void startScanning(@Nullable List<ScanFilter> filters, @NonNull ScanSettings settings,
+ @NonNull ScanCallback callback) {
+ if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
+ loge(TAG, "Attempted start scanning, but system does not support BLE. Ignoring");
+ return;
+ }
+ logd(TAG, "Request received to start scanning.");
+ mScannerStartCount = 0;
+ mScanFilters = filters;
+ mScanSettings = settings;
+ mScanCallback = callback;
+ updateScannerState(STARTED);
+ startScanningInternally();
+ }
+
+ /** Stop the scanner */
+ public void stopScanning() {
+ logd(TAG, "Attempting to stop scanning");
+ if (mScanner != null) {
+ mScanner.stopScan(mInternalScanCallback);
+ }
+ mScanCallback = null;
+ updateScannerState(STOPPED);
+ }
+
+ /** Returns {@code true} if currently scanning, {@code false} otherwise. */
+ public boolean isScanning() {
+ return mScannerState.get() == SCANNING;
+ }
+
+ /** Clean up the scanning process. */
+ public void cleanup() {
+ if (isScanning()) {
+ stopScanning();
+ }
+ }
+
+ private void startScanningInternally() {
+ logd(TAG, "Attempting to start scanning");
+ if (mScanner == null && BluetoothAdapter.getDefaultAdapter() != null) {
+ mScanner = BluetoothAdapter.getDefaultAdapter().getBluetoothLeScanner();
+ }
+ if (mScanner != null) {
+ mScanner.startScan(mScanFilters, mScanSettings, mInternalScanCallback);
+ updateScannerState(SCANNING);
+ } else {
+ mHandler.postDelayed(() -> {
+ // Keep trying
+ logd(TAG, "Scanner unavailable. Trying again.");
+ startScanningInternally();
+ }, RETRY_INTERVAL_MS);
+ }
+ }
+
+ private void updateScannerState(@ScannerState int newState) {
+ mScannerState.set(newState);
+ }
+
+ private final ScanCallback mInternalScanCallback = new ScanCallback() {
+ @Override
+ public void onScanResult(int callbackType, ScanResult result) {
+ if (mScanCallback != null) {
+ mScanCallback.onScanResult(callbackType, result);
+ }
+ }
+
+ @Override
+ public void onBatchScanResults(List<ScanResult> results) {
+ logd(TAG, "Batch scan found " + results.size() + " results.");
+ if (mScanCallback != null) {
+ mScanCallback.onBatchScanResults(results);
+ }
+ }
+
+ @Override
+ public void onScanFailed(int errorCode) {
+ if (mScannerStartCount >= RETRY_LIMIT) {
+ loge(TAG, "Cannot start BLE Scanner. Scanning Retry count: "
+ + mScannerStartCount);
+ if (mScanCallback != null) {
+ mScanCallback.onScanFailed(errorCode);
+ }
+ return;
+ }
+
+ mScannerStartCount++;
+ logw(TAG, "BLE Scanner failed to start. Error: "
+ + errorCode
+ + " Retry: "
+ + mScannerStartCount);
+ switch(errorCode) {
+ case SCAN_FAILED_ALREADY_STARTED:
+ // Scanner already started. Do nothing.
+ break;
+ case SCAN_FAILED_APPLICATION_REGISTRATION_FAILED:
+ case SCAN_FAILED_INTERNAL_ERROR:
+ mHandler.postDelayed(BleCentralManager.this::startScanningInternally,
+ RETRY_INTERVAL_MS);
+ break;
+ default:
+ // Ignore other codes.
+ }
+ }
+ };
+}
diff --git a/connected-device-lib/src/com/android/car/connecteddevice/ble/BleDeviceMessageStream.java b/connected-device-lib/src/com/android/car/connecteddevice/ble/BleDeviceMessageStream.java
new file mode 100644
index 0000000..f91693b
--- /dev/null
+++ b/connected-device-lib/src/com/android/car/connecteddevice/ble/BleDeviceMessageStream.java
@@ -0,0 +1,384 @@
+/*
+ * 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.connecteddevice.ble;
+
+import static com.android.car.connecteddevice.BleStreamProtos.BleOperationProto.OperationType;
+import static com.android.car.connecteddevice.BleStreamProtos.BlePacketProto.BlePacket;
+import static com.android.car.connecteddevice.BleStreamProtos.VersionExchangeProto.BleVersionExchange;
+import static com.android.car.connecteddevice.util.SafeLog.logd;
+import static com.android.car.connecteddevice.util.SafeLog.loge;
+import static com.android.car.connecteddevice.util.SafeLog.logw;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothGattCharacteristic;
+import android.os.Handler;
+import android.os.Looper;
+
+import com.android.car.connecteddevice.BleStreamProtos.BleDeviceMessageProto.BleDeviceMessage;
+import com.android.car.connecteddevice.util.ByteUtils;
+import com.android.car.protobuf.ByteString;
+import com.android.car.protobuf.InvalidProtocolBufferException;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.ArrayDeque;
+import java.util.HashMap;
+import java.util.List;
+import java.util.UUID;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+
+/** BLE message stream to a device. */
+class BleDeviceMessageStream {
+
+ private static final String TAG = "BleDeviceMessageStream";
+
+ // Only version 2 of the messaging and version 1 of the security supported.
+ private static final int MESSAGING_VERSION = 2;
+ private static final int SECURITY_VERSION = 1;
+
+ /*
+ * During bandwidth testing, it was discovered that allowing the stream to send as fast as it
+ * can blocked outgoing notifications from being received by the connected device. Adding a
+ * throttle to the outgoing messages alleviated this block and allowed both sides to
+ * send/receive in parallel successfully.
+ */
+ private static final long THROTTLE_DEFAULT_MS = 10L;
+ private static final long THROTTLE_WAIT_MS = 75L;
+
+ private final ArrayDeque<BlePacket> mPacketQueue = new ArrayDeque<>();
+
+ private final HashMap<Integer, ByteArrayOutputStream> mPendingData =
+ new HashMap<>();
+
+ private final MessageIdGenerator mMessageIdGenerator = new MessageIdGenerator();
+
+ private final Handler mHandler = new Handler(Looper.getMainLooper());
+
+ private final AtomicBoolean mIsVersionExchanged = new AtomicBoolean(false);
+
+ private final AtomicBoolean mIsSendingInProgress = new AtomicBoolean(false);
+
+ private final AtomicLong mThrottleDelay = new AtomicLong(THROTTLE_DEFAULT_MS);
+
+ private final BlePeripheralManager mBlePeripheralManager;
+
+ private final BluetoothDevice mDevice;
+
+ private final BluetoothGattCharacteristic mWriteCharacteristic;
+
+ private final BluetoothGattCharacteristic mReadCharacteristic;
+
+ private MessageReceivedListener mMessageReceivedListener;
+
+ private MessageReceivedErrorListener mMessageReceivedErrorListener;
+
+ /*
+ * This initial value is 20 because BLE has a default write of 23 bytes. However, 3 bytes are
+ * subtracted due to bytes being reserved for the command type and attribute ID.
+ */
+ private int mMaxWriteSize = 20;
+
+ BleDeviceMessageStream(@NonNull BlePeripheralManager blePeripheralManager,
+ @NonNull BluetoothDevice device,
+ @NonNull BluetoothGattCharacteristic writeCharacteristic,
+ @NonNull BluetoothGattCharacteristic readCharacteristic) {
+ mBlePeripheralManager = blePeripheralManager;
+ mDevice = device;
+ mWriteCharacteristic = writeCharacteristic;
+ mReadCharacteristic = readCharacteristic;
+ mBlePeripheralManager.addOnCharacteristicWriteListener(this::onCharacteristicWrite);
+ mBlePeripheralManager.addOnCharacteristicReadListener(this::onCharacteristicRead);
+ }
+
+ /**
+ * Writes the given message to the write characteristic of this stream with operation type
+ * {@code CLIENT_MESSAGE}.
+ *
+ * This method will handle the chunking of messages based on the max write size.
+ *
+ * @param deviceMessage The data object contains recipient, isPayloadEncrypted and message.
+ */
+ void writeMessage(@NonNull DeviceMessage deviceMessage) {
+ writeMessage(deviceMessage, OperationType.CLIENT_MESSAGE);
+ }
+
+ /**
+ * Writes the given message to the write characteristic of this stream.
+ *
+ * This method will handle the chunking of messages based on the max write size. If it is
+ * a handshake message, the message recipient should be {@code null} and it cannot be
+ * encrypted.
+ *
+ * @param deviceMessage The data object contains recipient, isPayloadEncrypted and message.
+ * @param operationType The {@link OperationType} of this message.
+ */
+ void writeMessage(@NonNull DeviceMessage deviceMessage, OperationType operationType) {
+ logd(TAG, "Writing message to device: " + mDevice.getAddress() + ".");
+ BleDeviceMessage.Builder builder = BleDeviceMessage.newBuilder()
+ .setOperation(operationType)
+ .setIsPayloadEncrypted(deviceMessage.isMessageEncrypted())
+ .setPayload(ByteString.copyFrom(deviceMessage.getMessage()));
+
+ UUID recipient = deviceMessage.getRecipient();
+ if (recipient != null) {
+ builder.setRecipient(ByteString.copyFrom(ByteUtils.uuidToBytes(recipient)));
+ }
+
+ BleDeviceMessage bleDeviceMessage = builder.build();
+ byte[] rawBytes = bleDeviceMessage.toByteArray();
+ List<BlePacket> blePackets;
+ try {
+ blePackets = BlePacketFactory.makeBlePackets(rawBytes, mMessageIdGenerator.next(),
+ mMaxWriteSize);
+ } catch (BlePacketFactoryException e) {
+ loge(TAG, "Error while creating message packets.", e);
+ return;
+ }
+ mPacketQueue.addAll(blePackets);
+ writeNextMessageInQueue();
+ }
+
+ private void writeNextMessageInQueue() {
+ mHandler.postDelayed(() -> {
+ if (mPacketQueue.isEmpty()) {
+ logd(TAG, "No more packets to send.");
+ return;
+ }
+ if (mIsSendingInProgress.get()) {
+ logd(TAG, "Unable to send packet at this time.");
+ return;
+ }
+
+ mIsSendingInProgress.set(true);
+ BlePacket packet = mPacketQueue.remove();
+ logd(TAG, "Writing packet " + packet.getPacketNumber() + " of "
+ + packet.getTotalPackets() + " for " + packet.getMessageId() + ".");
+ mWriteCharacteristic.setValue(packet.toByteArray());
+ mBlePeripheralManager.notifyCharacteristicChanged(mDevice, mWriteCharacteristic,
+ /* confirm = */ false);
+ }, mThrottleDelay.get());
+ }
+
+ private void onCharacteristicRead(@NonNull BluetoothDevice device) {
+ if (!mDevice.equals(device)) {
+ logw(TAG, "Received a read notification from a device (" + device.getAddress()
+ + ") that is not the expected device (" + mDevice.getAddress() + ") registered "
+ + "to this stream. Ignoring.");
+ return;
+ }
+
+ logd(TAG, "Releasing lock on characteristic.");
+ mIsSendingInProgress.set(false);
+ writeNextMessageInQueue();
+ }
+
+ private void onCharacteristicWrite(@NonNull BluetoothDevice device,
+ @NonNull BluetoothGattCharacteristic characteristic, @NonNull byte[] value) {
+ logd(TAG, "Received a message from a device (" + device.getAddress() + ").");
+ if (!mDevice.equals(device)) {
+ logw(TAG, "Received a message from a device (" + device.getAddress() + ") that is not "
+ + "the expected device (" + mDevice.getAddress() + ") registered to this "
+ + "stream. Ignoring.");
+ return;
+ }
+
+ if (!characteristic.getUuid().equals(mReadCharacteristic.getUuid())) {
+ logw(TAG, "Received a write to a characteristic (" + characteristic.getUuid() + ") that"
+ + " is not the expected UUID (" + mReadCharacteristic.getUuid() + "). "
+ + "Ignoring.");
+ return;
+ }
+
+ if (!mIsVersionExchanged.get()) {
+ processVersionExchange(device, value);
+ return;
+ }
+
+ BlePacket packet;
+ try {
+ packet = BlePacket.parseFrom(value);
+ } catch (InvalidProtocolBufferException e) {
+ loge(TAG, "Can not parse Ble packet from client.", e);
+ if (mMessageReceivedErrorListener != null) {
+ mMessageReceivedErrorListener.onMessageReceivedError(e);
+ }
+ return;
+ }
+ processPacket(packet);
+ }
+
+ private void processVersionExchange(@NonNull BluetoothDevice device, @NonNull byte[] value) {
+ BleVersionExchange versionExchange;
+ try {
+ versionExchange = BleVersionExchange.parseFrom(value);
+ } catch (InvalidProtocolBufferException e) {
+ loge(TAG, "Could not parse version exchange message", e);
+ if (mMessageReceivedErrorListener != null) {
+ mMessageReceivedErrorListener.onMessageReceivedError(e);
+ }
+ return;
+ }
+ int minMessagingVersion = versionExchange.getMinSupportedMessagingVersion();
+ int maxMessagingVersion = versionExchange.getMaxSupportedMessagingVersion();
+ int minSecurityVersion = versionExchange.getMinSupportedSecurityVersion();
+ int maxSecurityVersion = versionExchange.getMaxSupportedSecurityVersion();
+ if (minMessagingVersion > MESSAGING_VERSION || maxMessagingVersion < MESSAGING_VERSION
+ || minSecurityVersion > SECURITY_VERSION || maxSecurityVersion < SECURITY_VERSION) {
+ loge(TAG, "Unsupported message version for min " + minMessagingVersion + " and max "
+ + maxMessagingVersion + " or security version for " + minSecurityVersion
+ + " and max " + maxSecurityVersion + ".");
+ if (mMessageReceivedErrorListener != null) {
+ mMessageReceivedErrorListener.onMessageReceivedError(
+ new IllegalStateException("Unsupported version."));
+ }
+ return;
+ }
+
+ BleVersionExchange headunitVersion = BleVersionExchange.newBuilder()
+ .setMinSupportedMessagingVersion(MESSAGING_VERSION)
+ .setMaxSupportedMessagingVersion(MESSAGING_VERSION)
+ .setMinSupportedSecurityVersion(SECURITY_VERSION)
+ .setMaxSupportedSecurityVersion(SECURITY_VERSION)
+ .build();
+ mWriteCharacteristic.setValue(headunitVersion.toByteArray());
+ mBlePeripheralManager.notifyCharacteristicChanged(device, mWriteCharacteristic,
+ /* confirm = */ false);
+ mIsVersionExchanged.set(true);
+ logd(TAG, "Sent supported version to the phone.");
+ }
+
+ @VisibleForTesting
+ void processPacket(@NonNull BlePacket packet) {
+ // Messages are coming in. Need to throttle outgoing messages to allow outgoing
+ // notifications to make it to the device.
+ mThrottleDelay.set(THROTTLE_WAIT_MS);
+
+ int messageId = packet.getMessageId();
+ ByteArrayOutputStream currentPayloadStream =
+ mPendingData.getOrDefault(messageId, new ByteArrayOutputStream());
+ mPendingData.putIfAbsent(messageId, currentPayloadStream);
+
+ byte[] payload = packet.getPayload().toByteArray();
+ try {
+ currentPayloadStream.write(payload);
+ } catch (IOException e) {
+ loge(TAG, "Error writing packet to stream.", e);
+ if (mMessageReceivedErrorListener != null) {
+ mMessageReceivedErrorListener.onMessageReceivedError(e);
+ }
+ return;
+ }
+ logd(TAG, "Parsed packet " + packet.getPacketNumber() + " of "
+ + packet.getTotalPackets() + " for message " + messageId + ". Writing "
+ + payload.length + ".");
+
+ if (packet.getPacketNumber() != packet.getTotalPackets()) {
+ return;
+ }
+
+ byte[] messageBytes = currentPayloadStream.toByteArray();
+ mPendingData.remove(messageId);
+
+ // All message packets received. Resetting throttle back to default until next message
+ // started.
+ mThrottleDelay.set(THROTTLE_DEFAULT_MS);
+
+ logd(TAG, "Received complete device message " + messageId + " of " + messageBytes.length
+ + " bytes.");
+ BleDeviceMessage message;
+ try {
+ message = BleDeviceMessage.parseFrom(messageBytes);
+ } catch (InvalidProtocolBufferException e) {
+ loge(TAG, "Cannot parse device message from client.", e);
+ if (mMessageReceivedErrorListener != null) {
+ mMessageReceivedErrorListener.onMessageReceivedError(e);
+ }
+ return;
+ }
+
+ DeviceMessage deviceMessage = new DeviceMessage(
+ ByteUtils.bytesToUUID(message.getRecipient().toByteArray()),
+ message.getIsPayloadEncrypted(), message.getPayload().toByteArray());
+ if (mMessageReceivedListener != null) {
+ mMessageReceivedListener.onMessageReceived(deviceMessage, message.getOperation());
+ }
+ }
+
+ /** The maximum amount of bytes that can be written over BLE. */
+ void setMaxWriteSize(int maxWriteSize) {
+ mMaxWriteSize = maxWriteSize;
+ }
+
+ /**
+ * Set the given listener to be notified when a new message was received from the
+ * client. If listener is {@code null}, clear.
+ */
+ void setMessageReceivedListener(@Nullable MessageReceivedListener listener) {
+ mMessageReceivedListener = listener;
+ }
+
+ /**
+ * Set the given listener to be notified when there was an error during receiving
+ * message from the client. If listener is {@code null}, clear.
+ */
+ void setMessageReceivedErrorListener(
+ @Nullable MessageReceivedErrorListener listener) {
+ mMessageReceivedErrorListener = listener;
+ }
+
+ /**
+ * Listener to be invoked when a complete message is received from the client.
+ */
+ interface MessageReceivedListener {
+
+ /**
+ * Called when a complete message is received from the client.
+ *
+ * @param deviceMessage The message received from the client.
+ * @param operationType The {@link OperationType} of the received message.
+ */
+ void onMessageReceived(@NonNull DeviceMessage deviceMessage, OperationType operationType);
+ }
+
+ /**
+ * Listener to be invoked when there was an error during receiving message from the client.
+ */
+ interface MessageReceivedErrorListener {
+ /**
+ * Called when there was an error during receiving message from the client.
+ *
+ * @param exception The error.
+ */
+ void onMessageReceivedError(@NonNull Exception exception);
+ }
+
+ /** A generator of unique IDs for messages. */
+ private static class MessageIdGenerator {
+ private final AtomicInteger mMessageId = new AtomicInteger(0);
+
+ int next() {
+ int current = mMessageId.getAndIncrement();
+ mMessageId.compareAndSet(Integer.MAX_VALUE, 0);
+ return current;
+ }
+ }
+}
diff --git a/connected-device-lib/src/com/android/car/connecteddevice/ble/BlePacketFactory.java b/connected-device-lib/src/com/android/car/connecteddevice/ble/BlePacketFactory.java
new file mode 100644
index 0000000..a0d0bb1
--- /dev/null
+++ b/connected-device-lib/src/com/android/car/connecteddevice/ble/BlePacketFactory.java
@@ -0,0 +1,155 @@
+/*
+ * 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.car.connecteddevice.ble;
+
+import static com.android.car.connecteddevice.util.SafeLog.loge;
+
+import com.android.car.connecteddevice.BleStreamProtos.BlePacketProto.BlePacket;
+import com.android.car.protobuf.ByteString;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Factory for creating {@link BlePacket} protos.
+ */
+class BlePacketFactory {
+ private static final String TAG = "BlePacketFactory";
+
+ /**
+ * The size in bytes of a {@code fixed32} field in the proto.
+ */
+ private static final int FIXED_32_SIZE = 4;
+
+ /**
+ * The bytes needed to encode the field number in the proto.
+ *
+ * <p>Since the {@link BlePacket} only has 4 fields, it will only take 1 additional byte to
+ * encode.
+ */
+ private static final int FIELD_NUMBER_ENCODING_SIZE = 1;
+
+ /**
+ * The size in bytes of field {@code packet_number}. The proto field is a {@code fixed32}.
+ */
+ private static final int PACKET_NUMBER_ENCODING_SIZE =
+ FIXED_32_SIZE + FIELD_NUMBER_ENCODING_SIZE;
+
+ /**
+ * Split given data if necessary to fit within the given {@code maxSize}.
+ *
+ * @param payload The payload to potentially split across multiple {@link BlePacket}s.
+ * @param messageId The unique id for identifying message.
+ * @param maxSize The maximum size of each chunk.
+ * @return A list of {@link BlePacket}s.
+ * @throws BlePacketFactoryException if an error occurred during the splitting of data.
+ */
+ static List<BlePacket> makeBlePackets(byte[] payload, int messageId, int maxSize)
+ throws BlePacketFactoryException {
+ List<BlePacket> blePackets = new ArrayList<>();
+ int payloadSize = payload.length;
+ int totalPackets = getTotalPacketNumber(messageId, payloadSize, maxSize);
+ int maxPayloadSize = maxSize
+ - getPacketHeaderSize(totalPackets, messageId, Math.min(payloadSize, maxSize));
+
+ int start = 0;
+ int end = Math.min(payloadSize, maxPayloadSize);
+ for (int packetNum = 1; packetNum <= totalPackets; packetNum++) {
+ blePackets.add(BlePacket.newBuilder()
+ .setPacketNumber(packetNum)
+ .setTotalPackets(totalPackets)
+ .setMessageId(messageId)
+ .setPayload(ByteString.copyFrom(Arrays.copyOfRange(payload, start, end)))
+ .build());
+ start = end;
+ end = Math.min(start + maxPayloadSize, payloadSize);
+ }
+ return blePackets;
+ }
+
+ /**
+ * Compute the header size for the {@link BlePacket} proto in bytes. This method assumes that
+ * the proto contains a payload.
+ */
+ @VisibleForTesting
+ static int getPacketHeaderSize(int totalPackets, int messageId, int payloadSize) {
+ return FIXED_32_SIZE + FIELD_NUMBER_ENCODING_SIZE
+ + getEncodedSize(totalPackets) + FIELD_NUMBER_ENCODING_SIZE
+ + getEncodedSize(messageId) + FIELD_NUMBER_ENCODING_SIZE
+ + getEncodedSize(payloadSize) + FIELD_NUMBER_ENCODING_SIZE;
+ }
+
+ /**
+ * Compute the total packets required to encode a payload of the given size.
+ */
+ @VisibleForTesting
+ static int getTotalPacketNumber(int messageId, int payloadSize, int maxSize)
+ throws BlePacketFactoryException {
+ int headerSizeWithoutTotalPackets = FIXED_32_SIZE + FIELD_NUMBER_ENCODING_SIZE
+ + getEncodedSize(messageId) + FIELD_NUMBER_ENCODING_SIZE
+ + getEncodedSize(Math.min(payloadSize, maxSize)) + FIELD_NUMBER_ENCODING_SIZE;
+
+ for (int value = 1; value <= PACKET_NUMBER_ENCODING_SIZE; value++) {
+ int packetHeaderSize = headerSizeWithoutTotalPackets + value
+ + FIELD_NUMBER_ENCODING_SIZE;
+ int maxPayloadSize = maxSize - packetHeaderSize;
+ if (maxPayloadSize < 0) {
+ throw new BlePacketFactoryException("Packet header size too large.");
+ }
+ int totalPackets = (int) Math.ceil(payloadSize / (double) maxPayloadSize);
+ if (getEncodedSize(totalPackets) == value) {
+ return totalPackets;
+ }
+ }
+
+ loge(TAG, "Cannot get valid total packet number for message: messageId: "
+ + messageId + ", payloadSize: " + payloadSize + ", maxSize: " + maxSize);
+ throw new BlePacketFactoryException("No valid total packet number.");
+ }
+
+ /**
+ * This method implements Protocol Buffers encoding algorithm.
+ *
+ * <p>Computes the number of bytes that would be needed to store a 32-bit variant.
+ *
+ * @param value the data that need to be encoded
+ * @return the size of the encoded data
+ * @see <a href="https://developers.google.com/protocol-buffers/docs/encoding#varints">
+ * Protocol Buffers Encoding</a>
+ */
+ private static int getEncodedSize(int value) {
+ if (value < 0) {
+ return 10;
+ }
+ if ((value & (~0 << 7)) == 0) {
+ return 1;
+ }
+ if ((value & (~0 << 14)) == 0) {
+ return 2;
+ }
+ if ((value & (~0 << 21)) == 0) {
+ return 3;
+ }
+ if ((value & (~0 << 28)) == 0) {
+ return 4;
+ }
+ return 5;
+ }
+
+ private BlePacketFactory() {}
+}
diff --git a/car-settings-lib/src/com/android/car/settingslib/util/SettingsConstants.java b/connected-device-lib/src/com/android/car/connecteddevice/ble/BlePacketFactoryException.java
similarity index 66%
rename from car-settings-lib/src/com/android/car/settingslib/util/SettingsConstants.java
rename to connected-device-lib/src/com/android/car/connecteddevice/ble/BlePacketFactoryException.java
index cec6146..690ce28 100644
--- a/car-settings-lib/src/com/android/car/settingslib/util/SettingsConstants.java
+++ b/connected-device-lib/src/com/android/car/connecteddevice/ble/BlePacketFactoryException.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -13,14 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-package com.android.car.settingslib.util;
+package com.android.car.connecteddevice.ble;
/**
- * Contains car specific settings constants.
+ * Exception for signaling {@link BlePacketFactory} errors.
*/
-public class SettingsConstants {
-
- public static final String USER_NAME_SET = "user_name_set";
-
+class BlePacketFactoryException extends Exception {
+ BlePacketFactoryException(String message) {
+ super(message);
+ }
}
diff --git a/connected-device-lib/src/com/android/car/connecteddevice/ble/BlePeripheralManager.java b/connected-device-lib/src/com/android/car/connecteddevice/ble/BlePeripheralManager.java
new file mode 100644
index 0000000..6a064d5
--- /dev/null
+++ b/connected-device-lib/src/com/android/car/connecteddevice/ble/BlePeripheralManager.java
@@ -0,0 +1,535 @@
+/*
+ * 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.car.connecteddevice.ble;
+
+import static android.bluetooth.BluetoothProfile.GATT_SERVER;
+
+import static com.android.car.connecteddevice.util.SafeLog.logd;
+import static com.android.car.connecteddevice.util.SafeLog.loge;
+import static com.android.car.connecteddevice.util.SafeLog.logw;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothGatt;
+import android.bluetooth.BluetoothGattCallback;
+import android.bluetooth.BluetoothGattCharacteristic;
+import android.bluetooth.BluetoothGattDescriptor;
+import android.bluetooth.BluetoothGattServer;
+import android.bluetooth.BluetoothGattServerCallback;
+import android.bluetooth.BluetoothGattService;
+import android.bluetooth.BluetoothManager;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.le.AdvertiseCallback;
+import android.bluetooth.le.AdvertiseData;
+import android.bluetooth.le.AdvertiseSettings;
+import android.bluetooth.le.BluetoothLeAdvertiser;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Handler;
+
+import com.android.car.connecteddevice.util.ByteUtils;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.CopyOnWriteArraySet;
+
+/**
+ * A generic class that manages BLE peripheral operations like start/stop advertising, notifying
+ * connects/disconnects and reading/writing values to GATT characteristics.
+ */
+// TODO(b/123248433) This could move to a separate comms library.
+public class BlePeripheralManager {
+ private static final String TAG = "BlePeripheralManager";
+
+ private static final int BLE_RETRY_LIMIT = 5;
+ private static final int BLE_RETRY_INTERVAL_MS = 1000;
+
+ private static final int GATT_SERVER_RETRY_LIMIT = 20;
+ private static final int GATT_SERVER_RETRY_DELAY_MS = 200;
+
+ // https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth
+ // .service.generic_access.xml
+ private static final UUID GENERIC_ACCESS_PROFILE_UUID =
+ UUID.fromString("00001800-0000-1000-8000-00805f9b34fb");
+ // https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth
+ // .characteristic.gap.device_name.xml
+ private static final UUID DEVICE_NAME_UUID =
+ UUID.fromString("00002a00-0000-1000-8000-00805f9b34fb");
+
+ private final Handler mHandler;
+
+ private final Context mContext;
+ private final Set<Callback> mCallbacks = new CopyOnWriteArraySet<>();
+ private final Set<OnCharacteristicWriteListener> mWriteListeners = new HashSet<>();
+ private final Set<OnCharacteristicReadListener> mReadListeners = new HashSet<>();
+
+ private int mMtuSize = 20;
+
+ private BluetoothManager mBluetoothManager;
+ private BluetoothLeAdvertiser mAdvertiser;
+ private BluetoothGattServer mGattServer;
+ private BluetoothGatt mBluetoothGatt;
+ private int mAdvertiserStartCount;
+ private int mGattServerRetryStartCount;
+ private BluetoothGattService mBluetoothGattService;
+ private AdvertiseCallback mAdvertiseCallback;
+ private AdvertiseData mAdvertiseData;
+
+ public BlePeripheralManager(Context context) {
+ mContext = context;
+ mHandler = new Handler(mContext.getMainLooper());
+ }
+
+ /**
+ * Registers the given callback to be notified of various events within the {@link
+ * BlePeripheralManager}.
+ *
+ * @param callback The callback to be notified.
+ */
+ void registerCallback(@NonNull Callback callback) {
+ mCallbacks.add(callback);
+ }
+
+ /**
+ * Unregisters a previously registered callback.
+ *
+ * @param callback The callback to unregister.
+ */
+ void unregisterCallback(@NonNull Callback callback) {
+ mCallbacks.remove(callback);
+ }
+
+ /**
+ * Adds a listener to be notified of a write to characteristics.
+ *
+ * @param listener The listener to invoke.
+ */
+ void addOnCharacteristicWriteListener(@NonNull OnCharacteristicWriteListener listener) {
+ mWriteListeners.add(listener);
+ }
+
+ /**
+ * Removes the given listener from being notified of characteristic writes.
+ *
+ * @param listener The listener to remove.
+ */
+ void removeOnCharacteristicWriteListener(@NonNull OnCharacteristicWriteListener listener) {
+ mWriteListeners.remove(listener);
+ }
+
+ /**
+ * Adds a listener to be notified of reads to characteristics.
+ *
+ * @param listener The listener to invoke.
+ */
+ void addOnCharacteristicReadListener(@NonNull OnCharacteristicReadListener listener) {
+ mReadListeners.add(listener);
+ }
+
+ /**
+ * Removes the given listener from being notified of characteristic reads.
+ *
+ * @param listener The listener to remove.
+ */
+ void removeOnCharacteristicReadistener(@NonNull OnCharacteristicReadListener listener) {
+ mReadListeners.remove(listener);
+ }
+
+ /**
+ * Returns the current MTU size.
+ *
+ * @return The size of the MTU in bytes.
+ */
+ int getMtuSize() {
+ return mMtuSize;
+ }
+
+ /**
+ * Starts the GATT server with the given {@link BluetoothGattService} and begins advertising.
+ *
+ * <p>It is possible that BLE service is still in TURNING_ON state when this method is invoked.
+ * Therefore, several retries will be made to ensure advertising is started.
+ *
+ * @param service {@link BluetoothGattService} that will be discovered by clients
+ * @param data {@link AdvertiseData} data to advertise
+ * @param advertiseCallback {@link AdvertiseCallback} callback for advertiser
+ */
+ void startAdvertising(
+ BluetoothGattService service, AdvertiseData data, AdvertiseCallback advertiseCallback) {
+ logd(TAG, "startAdvertising: " + service.getUuid());
+ if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
+ loge(TAG, "Attempted start advertising, but system does not support BLE. Ignoring.");
+ return;
+ }
+ // Clears previous session before starting advertising.
+ cleanup();
+ mBluetoothGattService = service;
+ mAdvertiseCallback = advertiseCallback;
+ mAdvertiseData = data;
+ mGattServerRetryStartCount = 0;
+ mBluetoothManager = (BluetoothManager) mContext.getSystemService(Context.BLUETOOTH_SERVICE);
+ mGattServer = mBluetoothManager.openGattServer(mContext, mGattServerCallback);
+ openGattServer();
+ }
+
+ /**
+ * Stops the GATT server from advertising.
+ *
+ * @param advertiseCallback The callback that is associated with the advertisement.
+ */
+ void stopAdvertising(AdvertiseCallback advertiseCallback) {
+ if (mAdvertiser != null) {
+ logd(TAG, "Stop advertising.");
+ mAdvertiser.stopAdvertising(advertiseCallback);
+ }
+ }
+
+ /**
+ * Notifies the characteristic change via {@link BluetoothGattServer}
+ */
+ void notifyCharacteristicChanged(
+ @NonNull BluetoothDevice device,
+ @NonNull BluetoothGattCharacteristic characteristic,
+ boolean confirm) {
+ if (mGattServer == null) {
+ return;
+ }
+
+ if (!mGattServer.notifyCharacteristicChanged(device, characteristic, confirm)) {
+ loge(TAG, "notifyCharacteristicChanged failed");
+ }
+ }
+
+ /**
+ * Connect the Gatt server of the remote device to retrieve device name.
+ */
+ final void retrieveDeviceName(BluetoothDevice device) {
+ mBluetoothGatt = device.connectGatt(mContext, false, mGattCallback);
+ }
+
+ /**
+ * Returns the currently opened GATT server within this manager.
+ *
+ * @return An opened GATT server or {@code null} if none have been opened.
+ */
+ @Nullable
+ BluetoothGattServer getGattServer() {
+ return mGattServer;
+ }
+
+ /**
+ * Cleans up the BLE GATT server state.
+ */
+ void cleanup() {
+ // Stops the advertiser, scanner and GATT server. This needs to be done to avoid leaks.
+ if (mAdvertiser != null) {
+ mAdvertiser.stopAdvertising(mAdvertiseCallback);
+ }
+ // Clears all registered listeners. IHU only supports single connection in peripheral role.
+ mReadListeners.clear();
+ mWriteListeners.clear();
+ mAdvertiser = null;
+
+ if (mGattServer == null) {
+ return;
+ }
+ mGattServer.clearServices();
+ try {
+ for (BluetoothDevice d : mBluetoothManager.getConnectedDevices(GATT_SERVER)) {
+ logd(TAG, "Disconnecting from " + d.getAddress());
+ mGattServer.cancelConnection(d);
+ }
+ } catch (UnsupportedOperationException e) {
+ loge(TAG, "Error getting connected devices", e);
+ } finally {
+ stopGattServer();
+ }
+ }
+
+ /**
+ * Close the GATT Server
+ */
+ void stopGattServer() {
+ if (mGattServer == null) {
+ return;
+ }
+ logd(TAG, "stopGattServer");
+ if (mBluetoothGatt != null) {
+ mGattServer.cancelConnection(mBluetoothGatt.getDevice());
+ mBluetoothGatt.disconnect();
+ }
+ mGattServer.clearServices();
+ mGattServer.close();
+ mGattServer = null;
+ }
+
+ private void openGattServer() {
+ // Only open one Gatt server.
+ if (mGattServer != null) {
+ logd(TAG, "Gatt Server created, retry count: " + mGattServerRetryStartCount);
+ mGattServer.clearServices();
+ mGattServer.addService(mBluetoothGattService);
+ AdvertiseSettings settings =
+ new AdvertiseSettings.Builder()
+ .setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY)
+ .setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH)
+ .setConnectable(true)
+ .build();
+ mAdvertiserStartCount = 0;
+ startAdvertisingInternally(settings, mAdvertiseData, mAdvertiseCallback);
+ mGattServerRetryStartCount = 0;
+ } else if (mGattServerRetryStartCount < GATT_SERVER_RETRY_LIMIT) {
+ mGattServer = mBluetoothManager.openGattServer(mContext, mGattServerCallback);
+ mGattServerRetryStartCount++;
+ mHandler.postDelayed(() -> openGattServer(), GATT_SERVER_RETRY_DELAY_MS);
+ } else {
+ loge(TAG, "Gatt server not created - exceeded retry limit.");
+ }
+ }
+
+ private void startAdvertisingInternally(
+ AdvertiseSettings settings, AdvertiseData data, AdvertiseCallback advertiseCallback) {
+ if (BluetoothAdapter.getDefaultAdapter() != null) {
+ mAdvertiser = BluetoothAdapter.getDefaultAdapter().getBluetoothLeAdvertiser();
+ }
+
+ if (mAdvertiser != null) {
+ logd(TAG, "Advertiser created, retry count: " + mAdvertiserStartCount);
+ mAdvertiser.startAdvertising(settings, data, advertiseCallback);
+ mAdvertiserStartCount = 0;
+ } else if (mAdvertiserStartCount < BLE_RETRY_LIMIT) {
+ mHandler.postDelayed(
+ () -> startAdvertisingInternally(settings, data, advertiseCallback),
+ BLE_RETRY_INTERVAL_MS);
+ mAdvertiserStartCount += 1;
+ } else {
+ loge(
+ TAG,
+ "Cannot start BLE Advertisement. Advertise Retry count: "
+ + mAdvertiserStartCount,
+ null);
+ }
+ }
+
+ private final BluetoothGattServerCallback mGattServerCallback =
+ new BluetoothGattServerCallback() {
+ @Override
+ public void onConnectionStateChange(BluetoothDevice device, int status,
+ int newState) {
+ logd(TAG, "BLE Connection State Change: " + newState);
+ switch (newState) {
+ case BluetoothProfile.STATE_CONNECTED:
+ for (Callback callback : mCallbacks) {
+ callback.onRemoteDeviceConnected(device);
+ }
+ break;
+ case BluetoothProfile.STATE_DISCONNECTED:
+ for (Callback callback : mCallbacks) {
+ callback.onRemoteDeviceDisconnected(device);
+ }
+ break;
+ default:
+ logw(TAG, "Connection state not connecting or disconnecting; ignoring: "
+ + newState);
+ }
+ }
+
+ @Override
+ public void onServiceAdded(int status, BluetoothGattService service) {
+ logd(TAG, "Service added status: " + status + " uuid: " + service.getUuid());
+ }
+
+ @Override
+ public void onCharacteristicWriteRequest(
+ BluetoothDevice device,
+ int requestId,
+ BluetoothGattCharacteristic characteristic,
+ boolean preparedWrite,
+ boolean responseNeeded,
+ int offset,
+ byte[] value) {
+ mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset,
+ value);
+ for (OnCharacteristicWriteListener listener : mWriteListeners) {
+ listener.onCharacteristicWrite(device, characteristic, value);
+ }
+ }
+
+ @Override
+ public void onDescriptorWriteRequest(
+ BluetoothDevice device,
+ int requestId,
+ BluetoothGattDescriptor descriptor,
+ boolean preparedWrite,
+ boolean responseNeeded,
+ int offset,
+ byte[] value) {
+ logd(TAG, "Write request for descriptor: "
+ + descriptor.getUuid()
+ + "; value: "
+ + ByteUtils.byteArrayToHexString(value));
+
+ mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset,
+ value);
+ }
+
+ @Override
+ public void onMtuChanged(BluetoothDevice device, int mtu) {
+ logd(TAG, "onMtuChanged: " + mtu + " for device " + device.getAddress());
+
+ mMtuSize = mtu;
+
+ for (Callback callback : mCallbacks) {
+ callback.onMtuSizeChanged(mtu);
+ }
+ }
+
+ @Override
+ public void onNotificationSent(BluetoothDevice device, int status) {
+ super.onNotificationSent(device, status);
+ if (status == BluetoothGatt.GATT_SUCCESS) {
+ logd(TAG, "Notification sent successfully. Device: " + device.getAddress()
+ + ", Status: " + status + ". Notifying all listeners.");
+ for (OnCharacteristicReadListener listener : mReadListeners) {
+ listener.onCharacteristicRead(device);
+ }
+ } else {
+ loge(TAG, "Notification failed. Device: " + device + ", Status: "
+ + status);
+ }
+ }
+ };
+
+ private final BluetoothGattCallback mGattCallback =
+ new BluetoothGattCallback() {
+ @Override
+ public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
+ logd(TAG, "Gatt Connection State Change: " + newState);
+ switch (newState) {
+ case BluetoothProfile.STATE_CONNECTED:
+ logd(TAG, "Gatt connected");
+ mBluetoothGatt.discoverServices();
+ break;
+ case BluetoothProfile.STATE_DISCONNECTED:
+ logd(TAG, "Gatt Disconnected");
+ break;
+ default:
+ logd(TAG, "Connection state not connecting or disconnecting; ignoring: "
+ + newState);
+ }
+ }
+
+ @Override
+ public void onServicesDiscovered(BluetoothGatt gatt, int status) {
+ logd(TAG, "Gatt Services Discovered");
+ BluetoothGattService gapService = mBluetoothGatt.getService(
+ GENERIC_ACCESS_PROFILE_UUID);
+ if (gapService == null) {
+ loge(TAG, "Generic Access Service is null.");
+ return;
+ }
+ BluetoothGattCharacteristic deviceNameCharacteristic =
+ gapService.getCharacteristic(DEVICE_NAME_UUID);
+ if (deviceNameCharacteristic == null) {
+ loge(TAG, "Device Name Characteristic is null.");
+ return;
+ }
+ mBluetoothGatt.readCharacteristic(deviceNameCharacteristic);
+ }
+
+ @Override
+ public void onCharacteristicRead(
+ BluetoothGatt gatt, BluetoothGattCharacteristic characteristic,
+ int status) {
+ if (status == BluetoothGatt.GATT_SUCCESS) {
+ String deviceName = characteristic.getStringValue(0);
+ logd(TAG, "BLE Device Name: " + deviceName);
+
+ for (Callback callback : mCallbacks) {
+ callback.onDeviceNameRetrieved(deviceName);
+ }
+ } else {
+ loge(TAG, "Reading GAP Failed: " + status);
+ }
+ }
+ };
+
+ /**
+ * Interface to be notified of various events within the {@link BlePeripheralManager}.
+ */
+ interface Callback {
+ /**
+ * Triggered when the name of the remote device is retrieved.
+ *
+ * @param deviceName Name of the remote device.
+ */
+ void onDeviceNameRetrieved(@Nullable String deviceName);
+
+ /**
+ * Triggered if a remote client has requested to change the MTU for a given connection.
+ *
+ * @param size The new MTU size.
+ */
+ void onMtuSizeChanged(int size);
+
+ /**
+ * Triggered when a device (GATT client) connected.
+ *
+ * @param device Remote device that connected on BLE.
+ */
+ void onRemoteDeviceConnected(@NonNull BluetoothDevice device);
+
+ /**
+ * Triggered when a device (GATT client) disconnected.
+ *
+ * @param device Remote device that disconnected on BLE.
+ */
+ void onRemoteDeviceDisconnected(@NonNull BluetoothDevice device);
+ }
+
+ /**
+ * An interface for classes that wish to be notified of writes to a characteristic.
+ */
+ interface OnCharacteristicWriteListener {
+ /**
+ * Triggered when this BlePeripheralManager receives a write request from a remote device.
+ *
+ * @param device The bluetooth device that holds the characteristic.
+ * @param characteristic The characteristic that was written to.
+ * @param value The value that was written.
+ */
+ void onCharacteristicWrite(
+ @NonNull BluetoothDevice device,
+ @NonNull BluetoothGattCharacteristic characteristic,
+ @NonNull byte[] value);
+ }
+
+ /**
+ * An interface for classes that wish to be notified of reads on a characteristic.
+ */
+ interface OnCharacteristicReadListener {
+ /**
+ * Triggered when this BlePeripheralManager receives a read request from a remote device.
+ *
+ * @param device The bluetooth device that holds the characteristic.
+ */
+ void onCharacteristicRead(@NonNull BluetoothDevice device);
+ }
+}
diff --git a/connected-device-lib/src/com/android/car/connecteddevice/ble/CarBleCentralManager.java b/connected-device-lib/src/com/android/car/connecteddevice/ble/CarBleCentralManager.java
new file mode 100644
index 0000000..00b8113
--- /dev/null
+++ b/connected-device-lib/src/com/android/car/connecteddevice/ble/CarBleCentralManager.java
@@ -0,0 +1,332 @@
+/*
+ * 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.connecteddevice.ble;
+
+import static com.android.car.connecteddevice.util.SafeLog.logd;
+import static com.android.car.connecteddevice.util.SafeLog.loge;
+import static com.android.car.connecteddevice.util.SafeLog.logw;
+import static com.android.car.connecteddevice.util.ScanDataAnalyzer.containsUuidsInOverflow;
+
+import android.annotation.NonNull;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothGatt;
+import android.bluetooth.BluetoothGattCallback;
+import android.bluetooth.BluetoothGattCharacteristic;
+import android.bluetooth.BluetoothGattDescriptor;
+import android.bluetooth.BluetoothGattService;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.le.ScanCallback;
+import android.bluetooth.le.ScanRecord;
+import android.bluetooth.le.ScanResult;
+import android.bluetooth.le.ScanSettings;
+import android.content.Context;
+import android.os.ParcelUuid;
+
+import com.android.car.connecteddevice.storage.ConnectedDeviceStorage;
+
+import java.math.BigInteger;
+import java.util.List;
+import java.util.UUID;
+import java.util.concurrent.CopyOnWriteArraySet;
+
+/**
+ * Communication manager for a car that maintains continuous connections with all devices in the car
+ * for the duration of a drive.
+ */
+public class CarBleCentralManager extends CarBleManager {
+
+ private static final String TAG = "CarBleCentralManager";
+
+ // system/bt/internal_include/bt_target.h#GATT_MAX_PHY_CHANNEL
+ private static final int MAX_CONNECTIONS = 7;
+
+ private static final UUID CHARACTERISTIC_CONFIG =
+ UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
+
+ private final ScanSettings mScanSettings = new ScanSettings.Builder()
+ .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
+ .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
+ .setMatchMode(ScanSettings.MATCH_MODE_AGGRESSIVE)
+ .build();
+
+ private final CopyOnWriteArraySet<BleDevice> mIgnoredDevices = new CopyOnWriteArraySet<>();
+
+ private final Context mContext;
+
+ private final BleCentralManager mBleCentralManager;
+
+ private final UUID mServiceUuid;
+
+ private final UUID mWriteCharacteristicUuid;
+
+ private final UUID mReadCharacteristicUuid;
+
+ private final BigInteger mParsedBgServiceBitMask;
+
+ /**
+ * Create a new manager.
+ *
+ * @param context The caller's [Context].
+ * @param bleCentralManager [BleCentralManager] for establishing connections.
+ * @param connectedDeviceStorage Shared [ConnectedDeviceStorage] for companion features.
+ * @param serviceUuid [UUID] of peripheral's service.
+ * @param bgServiceMask iOS overflow bit mask for service UUID.
+ * @param writeCharacteristicUuid [UUID] of characteristic the car will write to.
+ * @param readCharacteristicUuid [UUID] of characteristic the device will write to.
+ */
+ public CarBleCentralManager(
+ @NonNull Context context,
+ @NonNull BleCentralManager bleCentralManager,
+ @NonNull ConnectedDeviceStorage connectedDeviceStorage,
+ @NonNull UUID serviceUuid,
+ @NonNull String bgServiceMask,
+ @NonNull UUID writeCharacteristicUuid,
+ @NonNull UUID readCharacteristicUuid) {
+ super(connectedDeviceStorage);
+ mContext = context;
+ mBleCentralManager = bleCentralManager;
+ mServiceUuid = serviceUuid;
+ mWriteCharacteristicUuid = writeCharacteristicUuid;
+ mReadCharacteristicUuid = readCharacteristicUuid;
+ mParsedBgServiceBitMask = new BigInteger(bgServiceMask, 16);
+ }
+
+ @Override
+ public void start() {
+ super.start();
+ mBleCentralManager.startScanning(/* filters = */ null, mScanSettings, mScanCallback);
+ }
+
+ @Override
+ public void stop() {
+ super.stop();
+ mBleCentralManager.stopScanning();
+ }
+
+ private void ignoreDevice(@NonNull BleDevice device) {
+ mIgnoredDevices.add(device);
+ }
+
+ private boolean isDeviceIgnored(@NonNull BluetoothDevice device) {
+ for (BleDevice bleDevice : mIgnoredDevices) {
+ if (device.equals(bleDevice.mDevice)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean shouldAttemptConnection(@NonNull ScanResult result) {
+ // Ignore any results that are not connectable.
+ if (!result.isConnectable()) {
+ return false;
+ }
+
+ // Do not attempt to connect if we have already hit our max. This should rarely happen
+ // and is protecting against a race condition of scanning stopped and new results coming in.
+ if (getConnectedDevicesCount() >= MAX_CONNECTIONS) {
+ return false;
+ }
+
+ BluetoothDevice device = result.getDevice();
+
+ // Do not connect if device has already been ignored.
+ if (isDeviceIgnored(device)) {
+ return false;
+ }
+
+ // Check if already attempting to connect to this device.
+ if (getConnectedDevice(device) != null) {
+ return false;
+ }
+
+
+ // Ignore any device without a scan record.
+ ScanRecord scanRecord = result.getScanRecord();
+ if (scanRecord == null) {
+ return false;
+ }
+
+ // Connect to any device that is advertising our service UUID.
+ List<ParcelUuid> serviceUuids = scanRecord.getServiceUuids();
+ if (serviceUuids != null) {
+ for (ParcelUuid serviceUuid : serviceUuids) {
+ if (serviceUuid.getUuid().equals(mServiceUuid)) {
+ return true;
+ }
+ }
+ }
+ if (containsUuidsInOverflow(scanRecord.getBytes(), mParsedBgServiceBitMask)) {
+ return true;
+ }
+
+ // Can safely ignore devices advertising unrecognized service uuids.
+ if (serviceUuids != null && !serviceUuids.isEmpty()) {
+ return false;
+ }
+
+ // TODO(b/139066293): Current implementation quickly exhausts connections resulting in
+ // greatly reduced performance for connecting to devices we know we want to connect to.
+ // Return true once fixed.
+ return false;
+ }
+
+ private void startDeviceConnection(@NonNull BluetoothDevice device) {
+ BluetoothGatt gatt = device.connectGatt(mContext, /* autoConnect = */ false,
+ mConnectionCallback, BluetoothDevice.TRANSPORT_LE);
+ if (gatt == null) {
+ return;
+ }
+
+ BleDevice bleDevice = new BleDevice(device, gatt);
+ bleDevice.mState = BleDeviceState.CONNECTING;
+ addConnectedDevice(bleDevice);
+
+ // Stop scanning if we have reached the maximum number of connections.
+ if (getConnectedDevicesCount() >= MAX_CONNECTIONS) {
+ mBleCentralManager.stopScanning();
+ }
+ }
+
+ private void deviceConnected(@NonNull BleDevice device) {
+ if (device.mGatt == null) {
+ loge(TAG, "Device connected with null gatt. Disconnecting.");
+ deviceDisconnected(device, BluetoothProfile.STATE_DISCONNECTED);
+ return;
+ }
+ device.mState = BleDeviceState.PENDING_VERIFICATION;
+ device.mGatt.discoverServices();
+ logd(TAG, "New device connected: " + device.mGatt.getDevice().getAddress()
+ + ". Active connections: " + getConnectedDevicesCount() + ".");
+ }
+
+ private void deviceDisconnected(@NonNull BleDevice device, int status) {
+ removeConnectedDevice(device);
+ if (device.mGatt != null) {
+ device.mGatt.close();
+ }
+ if (device.mDeviceId != null) {
+ mCallbacks.invoke(callback -> callback.onDeviceDisconnected(device.mDeviceId));
+ }
+ logd(TAG, "Device with id " + device.mDeviceId + " disconnected with state " + status
+ + ". Remaining active connections: " + getConnectedDevicesCount() + ".");
+ }
+
+ private final ScanCallback mScanCallback = new ScanCallback() {
+ @Override
+ public void onScanResult(int callbackType, ScanResult result) {
+ super.onScanResult(callbackType, result);
+ if (shouldAttemptConnection(result)) {
+ startDeviceConnection(result.getDevice());
+ }
+ }
+
+ @Override
+ public void onScanFailed(int errorCode) {
+ super.onScanFailed(errorCode);
+ loge(TAG, "BLE scanning failed with error code: " + errorCode);
+ }
+ };
+
+ private final BluetoothGattCallback mConnectionCallback = new BluetoothGattCallback() {
+ @Override
+ public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
+ super.onConnectionStateChange(gatt, status, newState);
+ if (gatt == null) {
+ logw(TAG, "Null gatt passed to onConnectionStateChange. Ignoring.");
+ return;
+ }
+
+ BleDevice connectedDevice = getConnectedDevice(gatt);
+ if (connectedDevice == null) {
+ return;
+ }
+
+ switch (newState) {
+ case BluetoothProfile.STATE_CONNECTED:
+ deviceConnected(connectedDevice);
+ break;
+ case BluetoothProfile.STATE_DISCONNECTED:
+ deviceDisconnected(connectedDevice, status);
+ break;
+ default:
+ logd(TAG, "Connection state changed. New state: " + newState + " status: "
+ + status);
+ }
+ }
+
+ @Override
+ public void onServicesDiscovered(BluetoothGatt gatt, int status) {
+ super.onServicesDiscovered(gatt, status);
+ if (gatt == null) {
+ logw(TAG, "Null gatt passed to onServicesDiscovered. Ignoring.");
+ return;
+ }
+
+ BleDevice connectedDevice = getConnectedDevice(gatt);
+ if (connectedDevice == null) {
+ return;
+ }
+ BluetoothGattService service = gatt.getService(mServiceUuid);
+ if (service == null) {
+ ignoreDevice(connectedDevice);
+ gatt.disconnect();
+ return;
+ }
+
+ connectedDevice.mState = BleDeviceState.CONNECTED;
+ BluetoothGattCharacteristic writeCharacteristic =
+ service.getCharacteristic(mWriteCharacteristicUuid);
+ BluetoothGattCharacteristic readCharacteristic =
+ service.getCharacteristic(mReadCharacteristicUuid);
+ if (writeCharacteristic == null || readCharacteristic == null) {
+ logw(TAG, "Unable to find expected characteristics on peripheral.");
+ gatt.disconnect();
+ return;
+ }
+
+ // Turn on notifications for read characteristic.
+ BluetoothGattDescriptor descriptor =
+ readCharacteristic.getDescriptor(CHARACTERISTIC_CONFIG);
+ descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
+ if (!gatt.writeDescriptor(descriptor)) {
+ loge(TAG, "Write descriptor to read characteristic failed.");
+ gatt.disconnect();
+ return;
+ }
+
+ if (!gatt.setCharacteristicNotification(readCharacteristic, /* enable = */ true)) {
+ loge(TAG, "Set notifications to read characteristic failed.");
+ gatt.disconnect();
+ return;
+ }
+
+ logd(TAG, "Service and characteristics successfully discovered.");
+ }
+
+ @Override
+ public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor,
+ int status) {
+ super.onDescriptorWrite(gatt, descriptor, status);
+ if (gatt == null) {
+ logw(TAG, "Null gatt passed to onDescriptorWrite. Ignoring.");
+ return;
+ }
+ // TODO(b/141312136): Create SecureBleChannel and assign to connectedDevice.
+ }
+ };
+}
diff --git a/connected-device-lib/src/com/android/car/connecteddevice/ble/CarBleManager.java b/connected-device-lib/src/com/android/car/connecteddevice/ble/CarBleManager.java
new file mode 100644
index 0000000..d649d10
--- /dev/null
+++ b/connected-device-lib/src/com/android/car/connecteddevice/ble/CarBleManager.java
@@ -0,0 +1,251 @@
+/*
+ * 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.car.connecteddevice.ble;
+
+import static com.android.car.connecteddevice.util.SafeLog.logd;
+import static com.android.car.connecteddevice.util.SafeLog.logw;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothGatt;
+
+import com.android.car.connecteddevice.storage.ConnectedDeviceStorage;
+import com.android.car.connecteddevice.util.ThreadSafeCallbacks;
+
+import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.concurrent.Executor;
+
+/**
+ * Generic BLE manager for a car that keeps track of connected devices and their associated
+ * callbacks.
+ */
+public abstract class CarBleManager {
+
+ private static final String TAG = "CarBleManager";
+
+ final ConnectedDeviceStorage mStorage;
+
+ final CopyOnWriteArraySet<BleDevice> mConnectedDevices = new CopyOnWriteArraySet<>();
+
+ final ThreadSafeCallbacks<Callback> mCallbacks = new ThreadSafeCallbacks<>();
+
+ protected CarBleManager(@NonNull ConnectedDeviceStorage connectedDeviceStorage) {
+ mStorage = connectedDeviceStorage;
+ }
+
+ /**
+ * Initialize and start the manager.
+ */
+ public void start() {
+ }
+
+ /**
+ * Stop the manager and clean up.
+ */
+ public void stop() {
+ for (BleDevice device : mConnectedDevices) {
+ if (device.mGatt != null) {
+ device.mGatt.close();
+ }
+ }
+ mConnectedDevices.clear();
+ mCallbacks.clear();
+ }
+
+ /**
+ * Register a {@link Callback} to be notified on the {@link Executor}.
+ */
+ public void registerCallback(@NonNull Callback callback, @NonNull Executor executor) {
+ mCallbacks.add(callback, executor);
+ }
+
+ /**
+ * Unregister a callback.
+ *
+ * @param callback The {@link Callback} to unregister.
+ */
+ public void unregisterCallback(@NonNull Callback callback) {
+ mCallbacks.remove(callback);
+ }
+
+ /**
+ * Send a message to a connected device.
+ *
+ * @param deviceId Id of connected device.
+ * @param message {@link DeviceMessage} to send.
+ */
+ public void sendMessage(@NonNull String deviceId, @NonNull DeviceMessage message) {
+ BleDevice device = getConnectedDevice(deviceId);
+ if (device == null) {
+ logw(TAG, "Attempted to send message to unknown device $deviceId. Ignored.");
+ return;
+ }
+
+ sendMessage(device, message);
+ }
+
+ /**
+ * Send a message to a connected device.
+ *
+ * @param device The connected {@link BleDevice}.
+ * @param message {@link DeviceMessage} to send.
+ */
+ public void sendMessage(@NonNull BleDevice device, @NonNull DeviceMessage message) {
+ String deviceId = device.mDeviceId;
+ if (deviceId == null) {
+ deviceId = "Unidentified device";
+ }
+
+ logd(TAG, "Writing " + message.getMessage().length + " bytes to " + deviceId + ".");
+
+
+ if (message.isMessageEncrypted()) {
+ device.mSecureChannel.sendEncryptedMessage(message);
+ } else {
+ device.mSecureChannel.getStream().writeMessage(message);
+ }
+ }
+
+ /**
+ * Get the {@link BleDevice} with matching {@link BluetoothGatt} if available. Returns
+ * {@code null} if no matches are found.
+ */
+ @Nullable
+ BleDevice getConnectedDevice(@NonNull BluetoothGatt gatt) {
+ for (BleDevice device : mConnectedDevices) {
+ if (device.mGatt == gatt) {
+ return device;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Get the {@link BleDevice} with matching {@link BluetoothDevice} if available. Returns
+ * {@code null} if no matches are found.
+ */
+ @Nullable
+ BleDevice getConnectedDevice(@NonNull BluetoothDevice device) {
+ for (BleDevice connectedDevice : mConnectedDevices) {
+ if (device.equals(connectedDevice.mDevice)) {
+ return connectedDevice;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Get the {@link BleDevice} with matching device id if available. Returns {@code null} if
+ * no matches are found.
+ */
+ @Nullable
+ BleDevice getConnectedDevice(@NonNull String deviceId) {
+ for (BleDevice device : mConnectedDevices) {
+ if (deviceId.equals(device.mDeviceId)) {
+ return device;
+ }
+ }
+
+ return null;
+ }
+
+ /** Add the {@link BleDevice} that has connected. */
+ void addConnectedDevice(@NonNull BleDevice device) {
+ mConnectedDevices.add(device);
+ }
+
+ /** Return the number of devices currently connected. */
+ int getConnectedDevicesCount() {
+ return mConnectedDevices.size();
+ }
+
+ /** Remove [@link BleDevice} that has been disconnected. */
+ void removeConnectedDevice(@NonNull BleDevice device) {
+ mConnectedDevices.remove(device);
+ }
+
+ /** State for a connected device. */
+ enum BleDeviceState {
+ CONNECTING,
+ PENDING_VERIFICATION,
+ CONNECTED,
+ UNKNOWN
+ }
+
+ /**
+ * Container class to hold information about a connected device.
+ */
+ static class BleDevice {
+
+ BluetoothDevice mDevice;
+ BluetoothGatt mGatt;
+ BleDeviceState mState;
+ String mDeviceId;
+ SecureBleChannel mSecureChannel;
+
+ BleDevice(@NonNull BluetoothDevice device, @Nullable BluetoothGatt gatt) {
+ mDevice = device;
+ mGatt = gatt;
+ mState = BleDeviceState.UNKNOWN;
+ }
+ }
+
+ /**
+ * Callback for triggered events from {@link CarBleManager}.
+ */
+ public interface Callback {
+ /**
+ * Triggered when device is connected and device id retrieved. Device is now ready to
+ * receive messages.
+ *
+ * @param deviceId Id of device that has connected.
+ */
+ void onDeviceConnected(@NonNull String deviceId);
+
+ /**
+ * Triggered when device is disconnected.
+ *
+ * @param deviceId Id of device that has disconnected.
+ */
+ void onDeviceDisconnected(@NonNull String deviceId);
+
+ /**
+ * Triggered when device has established encryption for secure communication.
+ *
+ * @param deviceId Id of device that has established encryption.
+ */
+ void onSecureChannelEstablished(@NonNull String deviceId);
+
+ /**
+ * Triggered when a new message is received.
+ *
+ * @param deviceId Id of the device that sent the message.
+ * @param message {@link DeviceMessage} received.
+ */
+ void onMessageReceived(@NonNull String deviceId, @NonNull DeviceMessage message);
+
+ /**
+ * Triggered when an error when establishing the secure channel.
+ *
+ * @param deviceId Id of the device that experienced the error.
+ */
+ void onSecureChannelError(@NonNull String deviceId);
+ }
+}
diff --git a/connected-device-lib/src/com/android/car/connecteddevice/ble/CarBlePeripheralManager.java b/connected-device-lib/src/com/android/car/connecteddevice/ble/CarBlePeripheralManager.java
new file mode 100644
index 0000000..4745fdb
--- /dev/null
+++ b/connected-device-lib/src/com/android/car/connecteddevice/ble/CarBlePeripheralManager.java
@@ -0,0 +1,491 @@
+/*
+ * 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.car.connecteddevice.ble;
+
+import static com.android.car.connecteddevice.util.SafeLog.logd;
+import static com.android.car.connecteddevice.util.SafeLog.loge;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothGattCharacteristic;
+import android.bluetooth.BluetoothGattDescriptor;
+import android.bluetooth.BluetoothGattService;
+import android.bluetooth.le.AdvertiseCallback;
+import android.bluetooth.le.AdvertiseData;
+import android.bluetooth.le.AdvertiseSettings;
+import android.car.encryptionrunner.EncryptionRunnerFactory;
+import android.os.ParcelUuid;
+
+import com.android.car.connecteddevice.AssociationCallback;
+import com.android.car.connecteddevice.model.AssociatedDevice;
+import com.android.car.connecteddevice.storage.ConnectedDeviceStorage;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.UUID;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Communication manager that allows for targeted connections to a specific device in the car.
+ */
+public class CarBlePeripheralManager extends CarBleManager {
+
+ private static final String TAG = "CarBlePeripheralManager";
+
+ // Attribute protocol bytes attached to message. Available write size is MTU size minus att
+ // bytes.
+ private static final int ATT_PROTOCOL_BYTES = 3;
+
+ // Arbitrary delay time for a retry of association advertising if bluetooth adapter name change
+ // fails.
+ private static final long ASSOCIATE_ADVERTISING_DELAY_MS = 10L;
+
+ private static final UUID CLIENT_CHARACTERISTIC_CONFIG =
+ UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
+
+ private final BluetoothGattDescriptor mDescriptor =
+ new BluetoothGattDescriptor(CLIENT_CHARACTERISTIC_CONFIG,
+ BluetoothGattDescriptor.PERMISSION_READ
+ | BluetoothGattDescriptor.PERMISSION_WRITE);
+
+ private final ScheduledExecutorService mScheduler =
+ Executors.newSingleThreadScheduledExecutor();
+
+ private final BlePeripheralManager mBlePeripheralManager;
+
+ private final UUID mAssociationServiceUuid;
+
+ private final BluetoothGattCharacteristic mWriteCharacteristic;
+
+ private final BluetoothGattCharacteristic mReadCharacteristic;
+
+ // BLE default is 23, minus 3 bytes for ATT_PROTOCOL.
+ private int mWriteSize = 20;
+
+ private String mOriginalBluetoothName;
+
+ private String mClientDeviceName;
+
+ private String mClientDeviceAddress;
+
+ private AssociationCallback mAssociationCallback;
+
+ private AdvertiseCallback mAdvertiseCallback;
+
+ /**
+ * Initialize a new instance of manager.
+ *
+ * @param blePeripheralManager {@link BlePeripheralManager} for establishing connection.
+ * @param connectedDeviceStorage Shared {@link ConnectedDeviceStorage} for companion features.
+ * @param associationServiceUuid {@link UUID} of association service.
+ * @param writeCharacteristicUuid {@link UUID} of characteristic the car will write to.
+ * @param readCharacteristicUuid {@link UUID} of characteristic the device will write to.
+ */
+ public CarBlePeripheralManager(@NonNull BlePeripheralManager blePeripheralManager,
+ @NonNull ConnectedDeviceStorage connectedDeviceStorage,
+ @NonNull UUID associationServiceUuid, @NonNull UUID writeCharacteristicUuid,
+ @NonNull UUID readCharacteristicUuid) {
+ super(connectedDeviceStorage);
+ mBlePeripheralManager = blePeripheralManager;
+ mAssociationServiceUuid = associationServiceUuid;
+ mDescriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
+ mWriteCharacteristic = new BluetoothGattCharacteristic(writeCharacteristicUuid,
+ BluetoothGattCharacteristic.PROPERTY_NOTIFY,
+ BluetoothGattCharacteristic.PROPERTY_READ);
+ mReadCharacteristic = new BluetoothGattCharacteristic(readCharacteristicUuid,
+ BluetoothGattCharacteristic.PROPERTY_WRITE
+ | BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE,
+ BluetoothGattCharacteristic.PERMISSION_WRITE);
+ mReadCharacteristic.addDescriptor(mDescriptor);
+ }
+
+ @Override
+ public void stop() {
+ super.stop();
+ reset();
+ }
+
+ private void reset() {
+ resetBluetoothAdapterName();
+ mClientDeviceAddress = null;
+ mClientDeviceName = null;
+ mAssociationCallback = null;
+ mBlePeripheralManager.cleanup();
+ mConnectedDevices.clear();
+ }
+
+ /** Connect to device with provided id. */
+ public void connectToDevice(@NonNull UUID deviceId) {
+ for (BleDevice device : mConnectedDevices) {
+ if (UUID.fromString(device.mDeviceId).equals(deviceId)) {
+ // Already connected to this device. Ignore requests to connect again.
+ return;
+ }
+ }
+
+ // Clear any previous session before starting a new one.
+ reset();
+
+ mAdvertiseCallback = new AdvertiseCallback() {
+ @Override
+ public void onStartSuccess(AdvertiseSettings settingsInEffect) {
+ super.onStartSuccess(settingsInEffect);
+ logd(TAG, "Successfully started advertising for device " + deviceId + ".");
+ }
+ };
+ mBlePeripheralManager.registerCallback(mReconnectPeripheralCallback);
+ startAdvertising(deviceId, mAdvertiseCallback, /* includeDeviceName = */ false);
+ }
+
+ @Nullable
+ private BleDevice getConnectedDevice() {
+ if (mConnectedDevices.isEmpty()) {
+ return null;
+ }
+ return mConnectedDevices.iterator().next();
+ }
+
+ /** Start the association with a new device */
+ public void startAssociation(@NonNull String nameForAssociation,
+ @NonNull AssociationCallback callback) {
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ if (adapter == null) {
+ loge(TAG, "Bluetooth is unavailable on this device. Unable to start associating.");
+ return;
+ }
+
+ reset();
+ mAssociationCallback = callback;
+ if (mOriginalBluetoothName == null) {
+ mOriginalBluetoothName = adapter.getName();
+ }
+ adapter.setName(nameForAssociation);
+ logd(TAG, "Changing bluetooth adapter name from " + mOriginalBluetoothName + " to "
+ + nameForAssociation + ".");
+ mBlePeripheralManager.registerCallback(mAssociationPeripheralCallback);
+ mAdvertiseCallback = new AdvertiseCallback() {
+ @Override
+ public void onStartSuccess(AdvertiseSettings settingsInEffect) {
+ super.onStartSuccess(settingsInEffect);
+ callback.onAssociationStartSuccess(nameForAssociation);
+ logd(TAG, "Successfully started advertising for association.");
+ }
+
+ @Override
+ public void onStartFailure(int errorCode) {
+ super.onStartFailure(errorCode);
+ callback.onAssociationStartFailure();
+ logd(TAG, "Failed to start advertising for association. Error code: " + errorCode);
+ }
+ };
+ attemptAssociationAdvertising(nameForAssociation, callback);
+ }
+
+ /** Stop the association with any device. */
+ public void stopAssociation(@NonNull AssociationCallback callback) {
+ if (!isAssociating() || callback != mAssociationCallback) {
+ return;
+ }
+ reset();
+ }
+
+ private void attemptAssociationAdvertising(@NonNull String adapterName,
+ @NonNull AssociationCallback callback) {
+ if (mOriginalBluetoothName != null
+ && adapterName.equals(BluetoothAdapter.getDefaultAdapter().getName())) {
+ startAdvertising(mAssociationServiceUuid, mAdvertiseCallback,
+ /* includeDeviceName = */ true);
+ return;
+ }
+
+ ScheduledFuture future = mScheduler.schedule(
+ () -> attemptAssociationAdvertising(adapterName, callback),
+ ASSOCIATE_ADVERTISING_DELAY_MS, TimeUnit.MILLISECONDS);
+ if (future.isCancelled()) {
+ // Association failed to start.
+ callback.onAssociationStartFailure();
+ return;
+ }
+ logd(TAG, "Adapter name change has not taken affect prior to advertising attempt. Trying "
+ + "again in " + ASSOCIATE_ADVERTISING_DELAY_MS + " milliseconds.");
+ }
+
+ private void startAdvertising(@NonNull UUID serviceUuid, @NonNull AdvertiseCallback callback,
+ boolean includeDeviceName) {
+ BluetoothGattService gattService = new BluetoothGattService(serviceUuid,
+ BluetoothGattService.SERVICE_TYPE_PRIMARY);
+ gattService.addCharacteristic(mWriteCharacteristic);
+ gattService.addCharacteristic(mReadCharacteristic);
+
+ AdvertiseData advertiseData = new AdvertiseData.Builder()
+ .setIncludeDeviceName(includeDeviceName)
+ .addServiceUuid(new ParcelUuid(serviceUuid))
+ .build();
+ mBlePeripheralManager.startAdvertising(gattService, advertiseData, callback);
+ }
+
+ /** Notify that the user has accepted a pairing code or other out-of-band confirmation. */
+ public void notifyOutOfBandAccepted() {
+ if (getConnectedDevice() == null) {
+ disconnectWithError("Null connected device found when out-of-band confirmation "
+ + "received.");
+ return;
+ }
+
+ SecureBleChannel secureChannel = getConnectedDevice().mSecureChannel;
+ if (secureChannel == null) {
+ disconnectWithError("Null SecureBleChannel found for the current connected device "
+ + "when out-of-band confirmation received.");
+ return;
+ }
+
+ secureChannel.notifyOutOfBandAccepted();
+ }
+
+ @VisibleForTesting
+ @Nullable
+ SecureBleChannel getConnectedDeviceChannel() {
+ BleDevice connectedDevice = getConnectedDevice();
+ if (connectedDevice == null) {
+ return null;
+ }
+
+ return connectedDevice.mSecureChannel;
+ }
+
+ private void setDeviceId(@NonNull String deviceId) {
+ logd(TAG, "Setting device id: " + deviceId);
+ BleDevice connectedDevice = getConnectedDevice();
+ if (connectedDevice == null) {
+ disconnectWithError("Null connected device found when device id received.");
+ return;
+ }
+
+ connectedDevice.mDeviceId = deviceId;
+ mCallbacks.invoke(callback -> callback.onDeviceConnected(deviceId));
+ }
+
+ private void disconnectWithError(@NonNull String errorMessage) {
+ loge(TAG, errorMessage);
+ reset();
+ }
+
+ private void resetBluetoothAdapterName() {
+ if (mOriginalBluetoothName == null) {
+ return;
+ }
+ logd(TAG, "Changing bluetooth adapter name back to " + mOriginalBluetoothName + ".");
+ BluetoothAdapter.getDefaultAdapter().setName(mOriginalBluetoothName);
+ mOriginalBluetoothName = null;
+ }
+
+ private void addConnectedDevice(BluetoothDevice device, boolean isReconnect) {
+ mBlePeripheralManager.stopAdvertising(mAdvertiseCallback);
+ mClientDeviceAddress = device.getAddress();
+ mClientDeviceName = device.getName();
+ if (mClientDeviceName == null) {
+ logd(TAG, "Device connected, but name is null; issuing request to retrieve device "
+ + "name.");
+ mBlePeripheralManager.retrieveDeviceName(device);
+ }
+
+ BleDeviceMessageStream secureStream = new BleDeviceMessageStream(mBlePeripheralManager,
+ device, mWriteCharacteristic, mReadCharacteristic);
+ secureStream.setMaxWriteSize(mWriteSize);
+ SecureBleChannel secureChannel = new SecureBleChannel(secureStream, mStorage, isReconnect,
+ EncryptionRunnerFactory.newRunner());
+ secureChannel.registerCallback(mSecureChannelCallback);
+ BleDevice bleDevice = new BleDevice(device, /* gatt = */ null);
+ bleDevice.mSecureChannel = secureChannel;
+ addConnectedDevice(bleDevice);
+ }
+
+ private void setMtuSize(int mtuSize) {
+ mWriteSize = mtuSize - ATT_PROTOCOL_BYTES;
+ BleDevice connectedDevice = getConnectedDevice();
+ if (connectedDevice != null
+ && connectedDevice.mSecureChannel != null
+ && connectedDevice.mSecureChannel.getStream() != null) {
+ connectedDevice.mSecureChannel.getStream().setMaxWriteSize(mWriteSize);
+ }
+ }
+
+ private boolean isAssociating() {
+ return mAssociationCallback != null;
+ }
+
+ private final BlePeripheralManager.Callback mReconnectPeripheralCallback =
+ new BlePeripheralManager.Callback() {
+
+ @Override
+ public void onDeviceNameRetrieved(String deviceName) {
+ // Ignored.
+ }
+
+ @Override
+ public void onMtuSizeChanged(int size) {
+ setMtuSize(size);
+ }
+
+ @Override
+ public void onRemoteDeviceConnected(BluetoothDevice device) {
+ addConnectedDevice(device, /* isReconnect= */ true);
+ }
+
+ @Override
+ public void onRemoteDeviceDisconnected(BluetoothDevice device) {
+ String deviceId = null;
+ BleDevice connectedDevice = getConnectedDevice(device);
+ if (connectedDevice != null) {
+ deviceId = connectedDevice.mDeviceId;
+ }
+ final String finalDeviceId = deviceId;
+ if (finalDeviceId != null) {
+ mCallbacks.invoke(callback -> callback.onDeviceDisconnected(finalDeviceId));
+ }
+ reset();
+ }
+ };
+
+ private final BlePeripheralManager.Callback mAssociationPeripheralCallback =
+ new BlePeripheralManager.Callback() {
+ @Override
+ public void onDeviceNameRetrieved(String deviceName) {
+ if (deviceName == null) {
+ return;
+ }
+ mClientDeviceName = deviceName;
+ BleDevice connectedDevice = getConnectedDevice();
+ if (connectedDevice == null || connectedDevice.mDeviceId == null) {
+ return;
+ }
+ mStorage.updateAssociatedDeviceName(connectedDevice.mDeviceId, deviceName);
+ }
+
+ @Override
+ public void onMtuSizeChanged(int size) {
+ setMtuSize(size);
+ }
+
+ @Override
+ public void onRemoteDeviceConnected(BluetoothDevice device) {
+ resetBluetoothAdapterName();
+ addConnectedDevice(device, /* isReconnect = */ false);
+ BleDevice connectedDevice = getConnectedDevice();
+ if (connectedDevice == null || connectedDevice.mSecureChannel == null) {
+ return;
+ }
+ connectedDevice.mSecureChannel.setShowVerificationCodeListener(
+ code -> {
+ if (!isAssociating()) {
+ loge(TAG, "No valid callback for association.");
+ return;
+ }
+ mAssociationCallback.onVerificationCodeAvailable(code);
+ });
+ }
+
+ @Override
+ public void onRemoteDeviceDisconnected(BluetoothDevice device) {
+ BleDevice connectedDevice = getConnectedDevice(device);
+ if (connectedDevice != null && connectedDevice.mDeviceId != null) {
+ mCallbacks.invoke(callback -> callback.onDeviceDisconnected(
+ connectedDevice.mDeviceId));
+ }
+ reset();
+ }
+ };
+
+ private final SecureBleChannel.Callback mSecureChannelCallback =
+ new SecureBleChannel.Callback() {
+ @Override
+ public void onSecureChannelEstablished() {
+ BleDevice connectedDevice = getConnectedDevice();
+ if (connectedDevice == null || connectedDevice.mDeviceId == null) {
+ disconnectWithError("Null device id found when secure channel "
+ + "established.");
+ return;
+ }
+ String deviceId = connectedDevice.mDeviceId;
+ if (mClientDeviceAddress == null) {
+ disconnectWithError("Null device address found when secure channel "
+ + "established.");
+ return;
+ }
+ if (isAssociating()) {
+ logd(TAG, "Secure channel established for un-associated device. Saving "
+ + "association of that device for current user.");
+ mStorage.addAssociatedDeviceForActiveUser(
+ new AssociatedDevice(deviceId, mClientDeviceAddress,
+ mClientDeviceName));
+ if (mAssociationCallback != null) {
+ mAssociationCallback.onAssociationCompleted(deviceId);
+ mAssociationCallback = null;
+ }
+ }
+ mCallbacks.invoke(callback -> callback.onSecureChannelEstablished(deviceId));
+ }
+
+ @Override
+ public void onEstablishSecureChannelFailure(int error) {
+ BleDevice connectedDevice = getConnectedDevice();
+ if (connectedDevice == null || connectedDevice.mDeviceId == null) {
+ disconnectWithError("Null device id found when secure channel failed to "
+ + "establish.");
+ return;
+ }
+ String deviceId = connectedDevice.mDeviceId;
+ mCallbacks.invoke(callback -> callback.onSecureChannelError(deviceId));
+
+ if (isAssociating()) {
+ mAssociationCallback.onAssociationError(error);
+ disconnectWithError("Error while establishing secure connection.");
+ }
+ }
+
+ @Override
+ public void onMessageReceived(DeviceMessage deviceMessage) {
+ BleDevice connectedDevice = getConnectedDevice();
+ if (connectedDevice == null || connectedDevice.mDeviceId == null) {
+ disconnectWithError("Null device id found when message received.");
+ return;
+ }
+
+ logd(TAG, "Received new message from " + connectedDevice.mDeviceId
+ + " with " + deviceMessage.getMessage().length + " in its payload. "
+ + "Notifying " + mCallbacks.size() + " callbacks.");
+ mCallbacks.invoke(
+ callback ->callback.onMessageReceived(connectedDevice.mDeviceId,
+ deviceMessage));
+ }
+
+ @Override
+ public void onMessageReceivedError(Exception exception) {
+ // TODO(b/143879960) Extend the message error from here to continue up the
+ // chain.
+ }
+
+ @Override
+ public void onDeviceIdReceived(String deviceId) {
+ setDeviceId(deviceId);
+ }
+ };
+}
diff --git a/connected-device-lib/src/com/android/car/connecteddevice/ble/DeviceMessage.java b/connected-device-lib/src/com/android/car/connecteddevice/ble/DeviceMessage.java
new file mode 100644
index 0000000..9d3ac48
--- /dev/null
+++ b/connected-device-lib/src/com/android/car/connecteddevice/ble/DeviceMessage.java
@@ -0,0 +1,87 @@
+/*
+ * 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.connecteddevice.ble;
+
+import static com.android.car.connecteddevice.BleStreamProtos.BleDeviceMessageProto.BleDeviceMessage;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import java.util.Arrays;
+import java.util.Objects;
+import java.util.UUID;
+
+/** Holds the needed data from a {@link BleDeviceMessage}. */
+public class DeviceMessage {
+
+ private static final String TAG = "DeviceMessage";
+
+ private final UUID mRecipient;
+
+ private final boolean mIsMessageEncrypted;
+
+ private byte[] mMessage;
+
+ public DeviceMessage(@Nullable UUID recipient, boolean isMessageEncrypted,
+ @NonNull byte[] message) {
+ mRecipient = recipient;
+ mIsMessageEncrypted = isMessageEncrypted;
+ mMessage = message;
+ }
+
+ /** Returns the recipient for this message. {@code null} if no recipient set. */
+ @Nullable
+ public UUID getRecipient() {
+ return mRecipient;
+ }
+
+ /** Returns whether this message is encrypted. */
+ public boolean isMessageEncrypted() {
+ return mIsMessageEncrypted;
+ }
+
+ /** Returns the message payload. */
+ @Nullable
+ public byte[] getMessage() {
+ return mMessage;
+ }
+
+ /** Set the message payload. */
+ public void setMessage(@NonNull byte[] message) {
+ mMessage = message;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (!(obj instanceof DeviceMessage)) {
+ return false;
+ }
+ DeviceMessage deviceMessage = (DeviceMessage) obj;
+ return Objects.equals(mRecipient, deviceMessage.mRecipient)
+ && mIsMessageEncrypted == deviceMessage.mIsMessageEncrypted
+ && Arrays.equals(mMessage, deviceMessage.mMessage);
+ }
+
+ @Override
+ public int hashCode() {
+ return 31 * Objects.hash(mRecipient, mIsMessageEncrypted)
+ + Arrays.hashCode(mMessage);
+ }
+}
diff --git a/connected-device-lib/src/com/android/car/connecteddevice/ble/SecureBleChannel.java b/connected-device-lib/src/com/android/car/connecteddevice/ble/SecureBleChannel.java
new file mode 100644
index 0000000..a821186
--- /dev/null
+++ b/connected-device-lib/src/com/android/car/connecteddevice/ble/SecureBleChannel.java
@@ -0,0 +1,477 @@
+/*
+ * 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.connecteddevice.ble;
+
+import static com.android.car.connecteddevice.util.SafeLog.logd;
+import static com.android.car.connecteddevice.util.SafeLog.loge;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.car.encryptionrunner.EncryptionRunner;
+import android.car.encryptionrunner.EncryptionRunnerFactory;
+import android.car.encryptionrunner.HandshakeException;
+import android.car.encryptionrunner.HandshakeMessage;
+import android.car.encryptionrunner.HandshakeMessage.HandshakeState;
+import android.car.encryptionrunner.Key;
+
+import com.android.car.connecteddevice.BleStreamProtos.BleOperationProto.OperationType;
+import com.android.car.connecteddevice.storage.ConnectedDeviceStorage;
+import com.android.car.connecteddevice.util.ByteUtils;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.security.SignatureException;
+import java.util.UUID;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Consumer;
+
+/**
+ * Establishes a secure channel with {@link EncryptionRunner} over {@link BleDeviceMessageStream} as
+ * server side, sends and receives messages securely after the secure channel has been established.
+ */
+class SecureBleChannel {
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = { "CHANNEL_ERROR" },
+ value = {
+ CHANNEL_ERROR_INVALID_HANDSHAKE,
+ CHANNEL_ERROR_INVALID_MSG,
+ CHANNEL_ERROR_INVALID_DEVICE_ID,
+ CHANNEL_ERROR_INVALID_VERIFICATION,
+ CHANNEL_ERROR_INVALID_STATE,
+ CHANNEL_ERROR_INVALID_ENCRYPTION_KEY,
+ CHANNEL_ERROR_STORAGE_ERROR
+ }
+ )
+ @interface ChannelError { }
+
+ /** Indicates an error during a Handshake of EncryptionRunner. */
+ static final int CHANNEL_ERROR_INVALID_HANDSHAKE = 0;
+ /** Received an invalid handshake message or has an invalid handshake message to send. */
+ static final int CHANNEL_ERROR_INVALID_MSG = 1;
+ /** Unable to retrieve a valid id. */
+ static final int CHANNEL_ERROR_INVALID_DEVICE_ID = 2;
+ /** Unable to get verification code or there's a error during pin verification. */
+ static final int CHANNEL_ERROR_INVALID_VERIFICATION = 3;
+ /** Encountered an unexpected handshake state. */
+ static final int CHANNEL_ERROR_INVALID_STATE = 4;
+ /** Failed to get a valid previous/new encryption key.*/
+ static final int CHANNEL_ERROR_INVALID_ENCRYPTION_KEY = 5;
+ /** Failed to save the encryption key*/
+ static final int CHANNEL_ERROR_STORAGE_ERROR = 6;
+
+ @VisibleForTesting
+ static final byte[] CONFIRMATION_SIGNAL = "True".getBytes();
+
+ private static final String TAG = "SecureBleChannel";
+
+ private final BleDeviceMessageStream mStream;
+
+ private final ConnectedDeviceStorage mStorage;
+
+ private final boolean mIsReconnect;
+
+ private final EncryptionRunner mEncryptionRunner;
+
+ private final AtomicReference<Key> mEncryptionKey = new AtomicReference<>();
+
+ private @HandshakeState int mState = HandshakeState.UNKNOWN;
+
+ private String mDeviceId;
+
+ private Callback mCallback;
+
+ private ShowVerificationCodeListener mShowVerificationCodeListener;
+
+ SecureBleChannel(@NonNull BleDeviceMessageStream stream,
+ @NonNull ConnectedDeviceStorage storage) {
+ this(stream, storage, /* isReconnect = */ true, EncryptionRunnerFactory.newRunner());
+ }
+
+ SecureBleChannel(@NonNull BleDeviceMessageStream stream,
+ @NonNull ConnectedDeviceStorage storage, boolean isReconnect,
+ @NonNull EncryptionRunner encryptionRunner) {
+ mStream = stream;
+ mStorage = storage;
+ mIsReconnect = isReconnect;
+ mEncryptionRunner = encryptionRunner;
+ mEncryptionRunner.setIsReconnect(isReconnect);
+ mStream.setMessageReceivedListener(mStreamListener);
+ }
+
+ private void processHandshake(@NonNull byte[] message) throws HandshakeException {
+ switch (mState) {
+ case HandshakeState.UNKNOWN:
+ processHandshakeUnknown(message);
+ break;
+ case HandshakeState.IN_PROGRESS:
+ processHandshakeInProgress(message);
+ break;
+ case HandshakeState.RESUMING_SESSION:
+ processHandshakeResumingSession(message);
+ break;
+ default:
+ loge(TAG, "Encountered unexpected handshake state: " + mState + ". Received "
+ + "message: " + ByteUtils.byteArrayToHexString(message) + ".");
+ notifySecureChannelFailure(CHANNEL_ERROR_INVALID_STATE);
+ }
+ }
+
+ private void processHandshakeUnknown(@NonNull byte[] message) throws HandshakeException {
+ if (mDeviceId != null) {
+ logd(TAG, "Responding to handshake init request.");
+ HandshakeMessage handshakeMessage = mEncryptionRunner.respondToInitRequest(message);
+ mState = handshakeMessage.getHandshakeState();
+ sendHandshakeMessage(handshakeMessage.getNextMessage());
+ return;
+ }
+ UUID deviceId = ByteUtils.bytesToUUID(message);
+ if (deviceId == null) {
+ loge(TAG, "Received invalid device id. Ignoring.");
+ return;
+ }
+ mDeviceId = deviceId.toString();
+ if (mIsReconnect && !hasEncryptionKey(mDeviceId)) {
+ loge(TAG, "Attempted to reconnect device but no key found. Aborting secure channel.");
+ notifySecureChannelFailure(CHANNEL_ERROR_INVALID_DEVICE_ID);
+ return;
+ }
+ notifyCallback(callback -> callback.onDeviceIdReceived(mDeviceId));
+ sendUniqueIdToClient();
+ }
+
+ private void processHandshakeInProgress(@NonNull byte[] message) throws HandshakeException {
+ logd(TAG, "Continuing handshake.");
+ HandshakeMessage handshakeMessage = mEncryptionRunner.continueHandshake(message);
+ mState = handshakeMessage.getHandshakeState();
+
+ boolean isValidStateForAssociation = !mIsReconnect
+ && mState == HandshakeState.VERIFICATION_NEEDED;
+ boolean isValidStateForReconnect = mIsReconnect
+ && mState == HandshakeState.RESUMING_SESSION;
+ if (!isValidStateForAssociation && !isValidStateForReconnect) {
+ loge(TAG, "processHandshakeInProgress: Encountered unexpected handshake state: "
+ + mState + ".");
+ notifySecureChannelFailure(CHANNEL_ERROR_INVALID_STATE);
+ return;
+ }
+
+ if (!isValidStateForAssociation) {
+ return;
+ }
+
+ String code = handshakeMessage.getVerificationCode();
+ if (code == null) {
+ loge(TAG, "Unable to get verification code.");
+ notifySecureChannelFailure(CHANNEL_ERROR_INVALID_VERIFICATION);
+ return;
+ }
+
+ if (mShowVerificationCodeListener != null) {
+ logd(TAG, "Showing pairing code: " + code);
+ mShowVerificationCodeListener.showVerificationCode(code);
+ }
+ }
+
+ private void processHandshakeResumingSession(@NonNull byte[] message)
+ throws HandshakeException {
+ logd(TAG, "Start reconnection authentication.");
+ if (mDeviceId == null) {
+ loge(TAG, "processHandshakeResumingSession: Unable to resume session, device id is "
+ + "null.");
+ notifySecureChannelFailure(CHANNEL_ERROR_INVALID_DEVICE_ID);
+ return;
+ }
+
+ byte[] previousKey = mStorage.getEncryptionKey(mDeviceId);
+ if (previousKey == null) {
+ loge(TAG, "Unable to resume session, previous key is null.");
+ notifySecureChannelFailure(CHANNEL_ERROR_INVALID_ENCRYPTION_KEY);
+ return;
+ }
+
+ HandshakeMessage handshakeMessage = mEncryptionRunner.authenticateReconnection(message,
+ previousKey);
+ mState = handshakeMessage.getHandshakeState();
+ if (mState != HandshakeState.FINISHED) {
+ loge(TAG, "Unable to resume session, unexpected next handshake state: " + mState + ".");
+ notifySecureChannelFailure(CHANNEL_ERROR_INVALID_STATE);
+ return;
+ }
+
+ Key newKey = handshakeMessage.getKey();
+ if (newKey == null) {
+ loge(TAG, "Unable to resume session, new key is null.");
+ notifySecureChannelFailure(CHANNEL_ERROR_INVALID_ENCRYPTION_KEY);
+ return;
+ }
+
+ logd(TAG, "Saved new key for reconnection.");
+ mStorage.saveEncryptionKey(mDeviceId, newKey.asBytes());
+ mEncryptionKey.set(newKey);
+ sendServerAuthToClient(handshakeMessage.getNextMessage());
+ notifyCallback(callback -> callback.onSecureChannelEstablished());
+ }
+
+ private void sendUniqueIdToClient() {
+ UUID uniqueId = mStorage.getUniqueId();
+ DeviceMessage deviceMessage = new DeviceMessage(/* recipient = */ null,
+ /* isMessageEncrypted = */ false, ByteUtils.uuidToBytes(uniqueId));
+ logd(TAG, "Sending car's device id of " + uniqueId + " to device.");
+ mStream.writeMessage(deviceMessage, OperationType.ENCRYPTION_HANDSHAKE);
+ }
+
+ private boolean hasEncryptionKey(@NonNull String id) {
+ return mStorage.getEncryptionKey(id) != null;
+ }
+
+ private void sendHandshakeMessage(@Nullable byte[] message) {
+ if (message == null) {
+ loge(TAG, "Unable to send next handshake message, message is null.");
+ notifySecureChannelFailure(CHANNEL_ERROR_INVALID_MSG);
+ return;
+ }
+
+ logd(TAG, "Send handshake message: " + ByteUtils.byteArrayToHexString(message) + ".");
+ DeviceMessage deviceMessage = new DeviceMessage(/* recipient = */ null,
+ /* isMessageEncrypted = */ false, message);
+ mStream.writeMessage(deviceMessage, OperationType.ENCRYPTION_HANDSHAKE);
+ }
+
+ private void sendServerAuthToClient(@Nullable byte[] message) {
+ if (message == null) {
+ loge(TAG, "Unable to send server authentication message to client, message is null.");
+ notifySecureChannelFailure(CHANNEL_ERROR_INVALID_MSG);
+ return;
+ }
+ DeviceMessage deviceMessage = new DeviceMessage(/* recipient = */ null,
+ /* isMessageEncrypted = */ false, message);
+ mStream.writeMessage(deviceMessage, OperationType.ENCRYPTION_HANDSHAKE);
+ }
+
+ /**
+ * Send an encrypted message.
+ * <p>Note: This should be called only after the secure channel has been established.</p>
+ *
+ * @param deviceMessage The {@link DeviceMessage} to encrypt and send.
+ */
+ void sendEncryptedMessage(@NonNull DeviceMessage deviceMessage) throws IllegalStateException {
+ if (!deviceMessage.isMessageEncrypted()) {
+ loge(TAG, "Encryption not required for this message " + deviceMessage + ".");
+ return;
+ }
+ Key key = mEncryptionKey.get();
+ if (key == null) {
+ throw new IllegalStateException("Secure channel has not been established.");
+ }
+
+ byte[] encryptedMessage = key.encryptData(deviceMessage.getMessage());
+ deviceMessage.setMessage(encryptedMessage);
+ mStream.writeMessage(deviceMessage, OperationType.CLIENT_MESSAGE);
+ }
+
+ /**
+ * Called by the client to notify that the user has accepted a pairing code or any out-of-band
+ * confirmation, and send confirmation signals to remote bluetooth device.
+ */
+ void notifyOutOfBandAccepted() {
+ HandshakeMessage message;
+ try {
+ message = mEncryptionRunner.verifyPin();
+ } catch (HandshakeException e) {
+ loge(TAG, "Error during PIN verification", e);
+ notifySecureChannelFailure(CHANNEL_ERROR_INVALID_VERIFICATION);
+ return;
+ }
+ if (message.getHandshakeState() != HandshakeState.FINISHED) {
+ loge(TAG, "Handshake not finished after calling verify PIN. Instead got "
+ + "state: " + message.getHandshakeState() + ".");
+ notifySecureChannelFailure(CHANNEL_ERROR_INVALID_STATE);
+ return;
+ }
+
+ Key localKey = message.getKey();
+ if (localKey == null) {
+ loge(TAG, "Unable to finish association, generated key is null.");
+ notifySecureChannelFailure(CHANNEL_ERROR_INVALID_ENCRYPTION_KEY);
+ return;
+ }
+
+ mState = message.getHandshakeState();
+ mStorage.saveEncryptionKey(mDeviceId, localKey.asBytes());
+ mEncryptionKey.set(localKey);
+ if (mDeviceId == null) {
+ loge(TAG, "Unable to finish association, device id is null.");
+ notifySecureChannelFailure(CHANNEL_ERROR_INVALID_DEVICE_ID);
+ return;
+ }
+ logd(TAG, "Pairing code successfully verified and encryption key saved. Sending "
+ + "confirmation to device.");
+ notifyCallback(Callback::onSecureChannelEstablished);
+ DeviceMessage deviceMessage = new DeviceMessage(/* recipient = */ null,
+ /* isMessageEncrypted = */ false, CONFIRMATION_SIGNAL);
+ mStream.writeMessage(deviceMessage, OperationType.ENCRYPTION_HANDSHAKE);
+ }
+
+ /** Get the BLE stream backing this channel. */
+ @NonNull
+ BleDeviceMessageStream getStream() {
+ return mStream;
+ }
+
+ /**Set the listener that notifies to show verification code. {@code null} to clear.*/
+ void setShowVerificationCodeListener(@Nullable ShowVerificationCodeListener listener) {
+ mShowVerificationCodeListener = listener;
+ }
+
+ @VisibleForTesting
+ @Nullable
+ ShowVerificationCodeListener getShowVerificationCodeListener() {
+ return mShowVerificationCodeListener;
+ }
+
+ /** Register a callback that notifies secure channel events. */
+ void registerCallback(Callback callback) {
+ mCallback = callback;
+ }
+
+ /** Unregister a callback. */
+ void unregisterCallback(Callback callback) {
+ if (callback == mCallback) {
+ mCallback = null;
+ }
+ }
+
+ @VisibleForTesting
+ @Nullable
+ Callback getCallback() {
+ return mCallback;
+ }
+
+ private void notifyCallback(Consumer<Callback> notification) {
+ if (mCallback != null) {
+ notification.accept(mCallback);
+ }
+ }
+
+ private void notifySecureChannelFailure(@ChannelError int error) {
+ loge(TAG, "Secure channel error: " + error);
+ notifyCallback(callback -> callback.onEstablishSecureChannelFailure(error));
+ }
+
+ private final BleDeviceMessageStream.MessageReceivedListener mStreamListener =
+ new BleDeviceMessageStream.MessageReceivedListener() {
+ @Override
+ public void onMessageReceived(DeviceMessage deviceMessage,
+ OperationType operationType) {
+ byte[] message = deviceMessage.getMessage();
+ switch(operationType) {
+ case ENCRYPTION_HANDSHAKE:
+ logd(TAG, "Message received and handed off to handshake.");
+ try {
+ processHandshake(message);
+ } catch (HandshakeException e) {
+ loge(TAG, "Handshake failed.", e);
+ notifyCallback(callback -> callback.onEstablishSecureChannelFailure(
+ CHANNEL_ERROR_INVALID_HANDSHAKE));
+ }
+ break;
+ case CLIENT_MESSAGE:
+ logd(TAG, "Received client message.");
+ if (!deviceMessage.isMessageEncrypted()) {
+ notifyCallback(callback -> callback.onMessageReceived(
+ deviceMessage));
+ return;
+ }
+ Key key = mEncryptionKey.get();
+ if (key == null) {
+ loge(TAG, "Received encrypted message before secure channel has "
+ + "been established.");
+ notifyCallback(callback -> callback.onMessageReceivedError(null));
+ return;
+ }
+ try {
+ byte[] decryptedPayload =
+ key.decryptData(deviceMessage.getMessage());
+ deviceMessage.setMessage(decryptedPayload);
+ notifyCallback(
+ callback -> callback.onMessageReceived(deviceMessage));
+ } catch (SignatureException e) {
+ loge(TAG, "Could not decrypt client credentials.", e);
+ notifyCallback(callback -> callback.onMessageReceivedError(e));
+ }
+ break;
+ default:
+ loge(TAG, "Received unexpected operation type: " + operationType + ".");
+ }
+ }
+ };
+
+ /**
+ * Callbacks that will be invoked during establishing secure channel, sending and receiving
+ * messages securely.
+ */
+ interface Callback {
+ /**
+ * Invoked when secure channel has been established successfully.
+ */
+ void onSecureChannelEstablished();
+
+ /**
+ * Invoked when a {@link ChannelError} has been encountered in attempting to establish
+ * a secure channel.
+ *
+ * @param error The failure indication.
+ */
+ void onEstablishSecureChannelFailure(@SecureBleChannel.ChannelError int error);
+
+ /**
+ * Invoked when a complete message is received securely from the client and decrypted.
+ *
+ * @param deviceMessage The {@link DeviceMessage} with decrypted message.
+ */
+ void onMessageReceived(@NonNull DeviceMessage deviceMessage);
+
+ /**
+ * Invoked when there was an error during a processing or decrypting of a client message.
+ *
+ * @param exception The error.
+ */
+ void onMessageReceivedError(@Nullable Exception exception);
+
+ /**
+ * Invoked when the device id was received from the client.
+ *
+ * @param deviceId The unique device id of client.
+ */
+ void onDeviceIdReceived(@NonNull String deviceId);
+ }
+
+ /**
+ * Listener that will be invoked to display verification code.
+ */
+ interface ShowVerificationCodeListener {
+ /**
+ * Invoke when a verification need to be displayed during device association.
+ *
+ * @param code The verification code to show.
+ */
+ void showVerificationCode(@NonNull String code);
+ }
+}
diff --git a/connected-device-lib/src/com/android/car/connecteddevice/model/AssociatedDevice.java b/connected-device-lib/src/com/android/car/connecteddevice/model/AssociatedDevice.java
new file mode 100644
index 0000000..f23c2ca
--- /dev/null
+++ b/connected-device-lib/src/com/android/car/connecteddevice/model/AssociatedDevice.java
@@ -0,0 +1,86 @@
+/*
+ * 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.connecteddevice.model;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import java.util.Objects;
+
+/**
+ * Contains basic info of an associated device.
+ */
+public class AssociatedDevice {
+
+ private final String mDeviceId;
+
+ private final String mDeviceAddress;
+
+ private final String mDeviceName;
+
+
+ /**
+ * Create a new AssociatedDevice.
+ *
+ * @param deviceId Id of the associated device.
+ * @param deviceAddress Address of the associated device.
+ * @param deviceName Name of the associated device. {@code null} if not known.
+ */
+ public AssociatedDevice(@NonNull String deviceId, @NonNull String deviceAddress,
+ @Nullable String deviceName) {
+ mDeviceId = deviceId;
+ mDeviceAddress = deviceAddress;
+ mDeviceName = deviceName;
+ }
+
+ /** Returns the id for this device. */
+ @NonNull
+ public String getDeviceId() {
+ return mDeviceId;
+ }
+
+ /** Returns the address for this device. */
+ @NonNull
+ public String getDeviceAddress() {
+ return mDeviceAddress;
+ }
+
+ /** Returns the name for this device or {@code null} if not known. */
+ @Nullable
+ public String getDeviceName() {
+ return mDeviceName;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (!(obj instanceof AssociatedDevice)) {
+ return false;
+ }
+ AssociatedDevice associatedDevice = (AssociatedDevice) obj;
+ return Objects.equals(mDeviceId, associatedDevice.mDeviceId)
+ && Objects.equals(mDeviceAddress, associatedDevice.mDeviceAddress)
+ && Objects.equals(mDeviceName, associatedDevice.mDeviceName);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mDeviceId, mDeviceAddress, mDeviceName);
+ }
+}
diff --git a/connected-device-lib/src/com/android/car/connecteddevice/model/ConnectedDevice.java b/connected-device-lib/src/com/android/car/connecteddevice/model/ConnectedDevice.java
new file mode 100644
index 0000000..d65f97d
--- /dev/null
+++ b/connected-device-lib/src/com/android/car/connecteddevice/model/ConnectedDevice.java
@@ -0,0 +1,96 @@
+/*
+ * 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.connecteddevice.model;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import java.util.Objects;
+
+/**
+ * View model representing a connected device.
+ */
+public class ConnectedDevice {
+
+ private final String mDeviceId;
+
+ private final String mDeviceName;
+
+ private final boolean mBelongsToActiveUser;
+
+ private final boolean mHasSecureChannel;
+
+ /**
+ * Create a new connected device.
+ *
+ * @param deviceId Id of the connected device.
+ * @param deviceName Name of the connected device. {@code null} if not known.
+ * @param belongsToActiveUser User associated with this device is currently in the foreground.
+ * @param hasSecureChannel {@code true} if a secure channel is available for this device.
+ */
+ public ConnectedDevice(@NonNull String deviceId, @Nullable String deviceName,
+ boolean belongsToActiveUser, boolean hasSecureChannel) {
+ mDeviceId = deviceId;
+ mDeviceName = deviceName;
+ mBelongsToActiveUser = belongsToActiveUser;
+ mHasSecureChannel = hasSecureChannel;
+ }
+
+ /** Returns the id for this device. */
+ @NonNull
+ public String getDeviceId() {
+ return mDeviceId;
+ }
+
+ /** Returns the name for this device or {@code null} if not known. */
+ @Nullable
+ public String getDeviceName() {
+ return mDeviceName;
+ }
+
+ /**
+ * Returns {@code true} if this device is associated with the user currently in the foreground.
+ */
+ public boolean isAssociatedWithActiveUser() {
+ return mBelongsToActiveUser;
+ }
+
+ /** Returns {@code true} if this device has a secure channel available. */
+ public boolean hasSecureChannel() {
+ return mHasSecureChannel;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (!(obj instanceof ConnectedDevice)) {
+ return false;
+ }
+ ConnectedDevice connectedDevice = (ConnectedDevice) obj;
+ return Objects.equals(mDeviceId, connectedDevice.mDeviceId)
+ && Objects.equals(mDeviceName, connectedDevice.mDeviceName)
+ && mBelongsToActiveUser == connectedDevice.mBelongsToActiveUser
+ && mHasSecureChannel == connectedDevice.mHasSecureChannel;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mDeviceId, mDeviceName, mBelongsToActiveUser, mHasSecureChannel);
+ }
+}
diff --git a/connected-device-lib/src/com/android/car/connecteddevice/storage/AssociatedDeviceDao.java b/connected-device-lib/src/com/android/car/connecteddevice/storage/AssociatedDeviceDao.java
new file mode 100644
index 0000000..c041d58
--- /dev/null
+++ b/connected-device-lib/src/com/android/car/connecteddevice/storage/AssociatedDeviceDao.java
@@ -0,0 +1,66 @@
+/*
+ * 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.car.connecteddevice.storage;
+
+import androidx.room.Dao;
+import androidx.room.Delete;
+import androidx.room.Insert;
+import androidx.room.OnConflictStrategy;
+import androidx.room.Query;
+
+import java.util.List;
+
+/**
+ * Queries for associated device table.
+ */
+@Dao
+public interface AssociatedDeviceDao {
+
+ /** Get an associated device based on device id. */
+ @Query("SELECT * FROM associated_devices WHERE id LIKE :deviceId LIMIT 1")
+ AssociatedDeviceEntity getAssociatedDevice(String deviceId);
+
+ /** Get all {@link AssociatedDeviceEntity}s associated with a user. */
+ @Query("SELECT * FROM associated_devices WHERE userId LIKE :userId")
+ List<AssociatedDeviceEntity> getAssociatedDevicesForUser(int userId);
+
+ /**
+ * Add a {@link AssociatedDeviceEntity}. Replace if a device already exists with the same
+ * device id.
+ */
+ @Insert(onConflict = OnConflictStrategy.REPLACE)
+ void addOrReplaceAssociatedDevice(AssociatedDeviceEntity associatedDevice);
+
+ /** Remove a {@link AssociatedDeviceEntity}. */
+ @Delete
+ void removeAssociatedDevice(AssociatedDeviceEntity connectedDevice);
+
+ /** Get the key associated with a device id. */
+ @Query("SELECT * FROM associated_device_keys WHERE id LIKE :deviceId LIMIT 1")
+ AssociatedDeviceKeyEntity getAssociatedDeviceKey(String deviceId);
+
+ /**
+ * Add a {@link AssociatedDeviceKeyEntity}. Replace if a device key already exists with the
+ * same device id.
+ */
+ @Insert(onConflict = OnConflictStrategy.REPLACE)
+ void addOrReplaceAssociatedDeviceKey(AssociatedDeviceKeyEntity keyEntity);
+
+ /** Remove a {@link AssociatedDeviceKeyEntity}. */
+ @Delete
+ void removeAssociatedDeviceKey(AssociatedDeviceKeyEntity keyEntity);
+}
diff --git a/connected-device-lib/src/com/android/car/connecteddevice/storage/AssociatedDeviceEntity.java b/connected-device-lib/src/com/android/car/connecteddevice/storage/AssociatedDeviceEntity.java
new file mode 100644
index 0000000..cc97717
--- /dev/null
+++ b/connected-device-lib/src/com/android/car/connecteddevice/storage/AssociatedDeviceEntity.java
@@ -0,0 +1,59 @@
+/*
+ * 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.car.connecteddevice.storage;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.room.Entity;
+import androidx.room.PrimaryKey;
+
+import com.android.car.connecteddevice.model.AssociatedDevice;
+
+/** Table entity representing an associated device. */
+@Entity(tableName = "associated_devices")
+public class AssociatedDeviceEntity {
+
+ /** Id of the device. */
+ @PrimaryKey
+ @NonNull
+ public String id;
+
+ /** Id of user associated with this device. */
+ public int userId;
+
+ /** Bluetooth address of the device. */
+ @Nullable
+ public String address;
+
+ /** Bluetooth device name. */
+ @Nullable
+ public String name;
+
+ public AssociatedDeviceEntity() { }
+
+ public AssociatedDeviceEntity(int userId, AssociatedDevice associatedDevice) {
+ this.userId = userId;
+ id = associatedDevice.getDeviceId();
+ address = associatedDevice.getDeviceAddress();
+ name = associatedDevice.getDeviceName();
+ }
+
+ /** Return a new {@link AssociatedDevice} of this entity. */
+ public AssociatedDevice toAssociatedDevice() {
+ return new AssociatedDevice(id, address, name);
+ }
+}
diff --git a/connected-device-lib/src/com/android/car/connecteddevice/storage/AssociatedDeviceKeyEntity.java b/connected-device-lib/src/com/android/car/connecteddevice/storage/AssociatedDeviceKeyEntity.java
new file mode 100644
index 0000000..6cd791f
--- /dev/null
+++ b/connected-device-lib/src/com/android/car/connecteddevice/storage/AssociatedDeviceKeyEntity.java
@@ -0,0 +1,41 @@
+/*
+ * 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.connecteddevice.storage;
+
+import androidx.annotation.NonNull;
+import androidx.room.Entity;
+import androidx.room.PrimaryKey;
+
+/** Table entity representing a key for an associated device. */
+@Entity(tableName = "associated_device_keys")
+public class AssociatedDeviceKeyEntity {
+
+ /** Id of the device. */
+ @PrimaryKey
+ @NonNull
+ public String id;
+
+ @NonNull
+ public String encryptedKey;
+
+ public AssociatedDeviceKeyEntity() { }
+
+ public AssociatedDeviceKeyEntity(String deviceId, String encryptedKey) {
+ id = deviceId;
+ this.encryptedKey = encryptedKey;
+ }
+}
diff --git a/connected-device-lib/src/com/android/car/connecteddevice/storage/ConnectedDeviceDatabase.java b/connected-device-lib/src/com/android/car/connecteddevice/storage/ConnectedDeviceDatabase.java
new file mode 100644
index 0000000..3671440
--- /dev/null
+++ b/connected-device-lib/src/com/android/car/connecteddevice/storage/ConnectedDeviceDatabase.java
@@ -0,0 +1,28 @@
+/*
+ * 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.car.connecteddevice.storage;
+
+import androidx.room.Database;
+import androidx.room.RoomDatabase;
+
+/** Database for connected devices. */
+@Database(entities = { AssociatedDeviceEntity.class, AssociatedDeviceKeyEntity.class }, version = 1,
+ exportSchema = false)
+public abstract class ConnectedDeviceDatabase extends RoomDatabase {
+ /** Return the DAO for the associated device table. */
+ public abstract AssociatedDeviceDao associatedDeviceDao();
+}
diff --git a/connected-device-lib/src/com/android/car/connecteddevice/storage/ConnectedDeviceStorage.java b/connected-device-lib/src/com/android/car/connecteddevice/storage/ConnectedDeviceStorage.java
new file mode 100644
index 0000000..7b05981
--- /dev/null
+++ b/connected-device-lib/src/com/android/car/connecteddevice/storage/ConnectedDeviceStorage.java
@@ -0,0 +1,440 @@
+/*
+ * 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.car.connecteddevice.storage;
+
+import static com.android.car.connecteddevice.util.SafeLog.logd;
+import static com.android.car.connecteddevice.util.SafeLog.loge;
+import static com.android.car.connecteddevice.util.SafeLog.logw;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.security.keystore.KeyGenParameterSpec;
+import android.security.keystore.KeyProperties;
+import android.util.Base64;
+
+import androidx.room.Room;
+
+import com.android.car.connecteddevice.R;
+import com.android.car.connecteddevice.model.AssociatedDevice;
+
+import java.io.IOException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.CertificateException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.KeyGenerator;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.spec.GCMParameterSpec;
+
+/** Storage for Trusted Devices in a car. */
+public class ConnectedDeviceStorage {
+ private static final String TAG = "CompanionStorage";
+
+ private static final String UNIQUE_ID_KEY = "CTABM_unique_id";
+ private static final String KEY_ALIAS = "Ukey2Key";
+ private static final String CIPHER_TRANSFORMATION = "AES/GCM/NoPadding";
+ private static final String KEYSTORE_PROVIDER = "AndroidKeyStore";
+ private static final String DATABASE_NAME = "connected-device-database";
+ private static final String IV_SPEC_SEPARATOR = ";";
+ // This delimiter separates deviceId and deviceInfo, so it has to differ from the
+ // TrustedDeviceInfo delimiter. Once new API can be added, deviceId will be added to
+ // TrustedDeviceInfo and this delimiter will be removed.
+
+ // The length of the authentication tag for a cipher in GCM mode. The GCM specification states
+ // that this length can only have the values {128, 120, 112, 104, 96}. Using the highest
+ // possible value.
+ private static final int GCM_AUTHENTICATION_TAG_LENGTH = 128;
+
+ private final Context mContext;
+
+ private SharedPreferences mSharedPreferences;
+
+ private UUID mUniqueId;
+
+ private AssociatedDeviceDao mAssociatedDeviceDatabase;
+
+ private AssociatedDeviceCallback mAssociatedDeviceCallback;
+
+ public ConnectedDeviceStorage(@NonNull Context context) {
+ mContext = context;
+ mAssociatedDeviceDatabase = Room.databaseBuilder(context, ConnectedDeviceDatabase.class,
+ DATABASE_NAME)
+ .fallbackToDestructiveMigration()
+ .build()
+ .associatedDeviceDao();
+ }
+
+ /**
+ * Set a callback for associated device updates.
+ *
+ * @param callback {@link AssociatedDeviceCallback} to set.
+ */
+ public void setAssociatedDeviceCallback(
+ @NonNull AssociatedDeviceCallback callback) {
+ mAssociatedDeviceCallback = callback;
+ }
+
+ /** Clear the callback for association device callback updates. */
+ public void clearAssociationDeviceCallback() {
+ mAssociatedDeviceCallback = null;
+ }
+
+ /**
+ * Get communication encryption key for the given device
+ *
+ * @param deviceId id of trusted device
+ * @return encryption key, null if device id is not recognized
+ */
+ @Nullable
+ public byte[] getEncryptionKey(@NonNull String deviceId) {
+ AssociatedDeviceKeyEntity entity =
+ mAssociatedDeviceDatabase.getAssociatedDeviceKey(deviceId);
+ if (entity == null) {
+ logd(TAG, "Encryption key not found!");
+ return null;
+ }
+ String[] values = entity.encryptedKey.split(IV_SPEC_SEPARATOR, -1);
+
+ if (values.length != 2) {
+ logd(TAG, "Stored encryption key had the wrong length.");
+ return null;
+ }
+
+ byte[] encryptedKey = Base64.decode(values[0], Base64.DEFAULT);
+ byte[] ivSpec = Base64.decode(values[1], Base64.DEFAULT);
+ return decryptWithKeyStore(KEY_ALIAS, encryptedKey, ivSpec);
+ }
+
+ /**
+ * Save encryption key for the given device
+ *
+ * @param deviceId did of trusted device
+ * @param encryptionKey encryption key
+ */
+ public void saveEncryptionKey(@NonNull String deviceId, @NonNull byte[] encryptionKey) {
+ String encryptedKey = encryptWithKeyStore(KEY_ALIAS, encryptionKey);
+ AssociatedDeviceKeyEntity entity = new AssociatedDeviceKeyEntity(deviceId, encryptedKey);
+ mAssociatedDeviceDatabase.addOrReplaceAssociatedDeviceKey(entity);
+ logd(TAG, "Successfully wrote encryption key.");
+ }
+
+ /**
+ * Encrypt value with designated key
+ *
+ * <p>The encrypted value is of the form:
+ *
+ * <p>key + IV_SPEC_SEPARATOR + ivSpec
+ *
+ * <p>The {@code ivSpec} is needed to decrypt this key later on.
+ *
+ * @param keyAlias KeyStore alias for key to use
+ * @param value a value to encrypt
+ * @return encrypted value, null if unable to encrypt
+ */
+ @Nullable
+ private String encryptWithKeyStore(@NonNull String keyAlias, @Nullable byte[] value) {
+ if (value == null) {
+ logw(TAG, "Received a null key value.");
+ return null;
+ }
+
+ Key key = getKeyStoreKey(keyAlias);
+ try {
+ Cipher cipher = Cipher.getInstance(CIPHER_TRANSFORMATION);
+ cipher.init(Cipher.ENCRYPT_MODE, key);
+ return Base64.encodeToString(cipher.doFinal(value), Base64.DEFAULT)
+ + IV_SPEC_SEPARATOR
+ + Base64.encodeToString(cipher.getIV(), Base64.DEFAULT);
+ } catch (IllegalBlockSizeException
+ | BadPaddingException
+ | NoSuchAlgorithmException
+ | NoSuchPaddingException
+ | IllegalStateException
+ | InvalidKeyException e) {
+ loge(TAG, "Unable to encrypt value with key " + keyAlias, e);
+ return null;
+ }
+ }
+
+ /**
+ * Decrypt value with designated key
+ *
+ * @param keyAlias KeyStore alias for key to use
+ * @param value encrypted value
+ * @return decrypted value, null if unable to decrypt
+ */
+ @Nullable
+ private byte[] decryptWithKeyStore(
+ @NonNull String keyAlias, @Nullable byte[] value, @NonNull byte[] ivSpec) {
+ if (value == null) {
+ return null;
+ }
+
+ try {
+ Key key = getKeyStoreKey(keyAlias);
+ Cipher cipher = Cipher.getInstance(CIPHER_TRANSFORMATION);
+ cipher.init(
+ Cipher.DECRYPT_MODE, key,
+ new GCMParameterSpec(GCM_AUTHENTICATION_TAG_LENGTH, ivSpec));
+ return cipher.doFinal(value);
+ } catch (IllegalBlockSizeException
+ | BadPaddingException
+ | NoSuchAlgorithmException
+ | NoSuchPaddingException
+ | IllegalStateException
+ | InvalidKeyException
+ | InvalidAlgorithmParameterException e) {
+ loge(TAG, "Unable to decrypt value with key " + keyAlias, e);
+ return null;
+ }
+ }
+
+ @Nullable
+ private static Key getKeyStoreKey(@NonNull String keyAlias) {
+ KeyStore keyStore;
+ try {
+ keyStore = KeyStore.getInstance(KEYSTORE_PROVIDER);
+ keyStore.load(null);
+ if (!keyStore.containsAlias(keyAlias)) {
+ KeyGenerator keyGenerator =
+ KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES,
+ KEYSTORE_PROVIDER);
+ keyGenerator.init(
+ new KeyGenParameterSpec.Builder(
+ keyAlias,
+ KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
+ .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
+ .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
+ .build());
+ keyGenerator.generateKey();
+ }
+ return keyStore.getKey(keyAlias, null);
+
+ } catch (KeyStoreException
+ | NoSuchAlgorithmException
+ | UnrecoverableKeyException
+ | NoSuchProviderException
+ | CertificateException
+ | IOException
+ | InvalidAlgorithmParameterException e) {
+ loge(TAG, "Unable to retrieve key " + keyAlias + " from KeyStore.", e);
+ throw new IllegalStateException(e);
+ }
+ }
+
+ @NonNull
+ private SharedPreferences getSharedPrefs() {
+ // This should be called only after user 0 is unlocked.
+ if (mSharedPreferences != null) {
+ return mSharedPreferences;
+ }
+ mSharedPreferences = mContext.getSharedPreferences(
+ mContext.getString(R.string.connected_device_shared_preferences),
+ Context.MODE_PRIVATE);
+ return mSharedPreferences;
+
+ }
+
+ /**
+ * Get the unique id for head unit. Persists on device until factory reset. This should be
+ * called only after user 0 is unlocked.
+ *
+ * @return unique id
+ */
+ @NonNull
+ public UUID getUniqueId() {
+ if (mUniqueId != null) {
+ return mUniqueId;
+ }
+
+ SharedPreferences prefs = getSharedPrefs();
+ if (prefs.contains(UNIQUE_ID_KEY)) {
+ mUniqueId = UUID.fromString(prefs.getString(UNIQUE_ID_KEY, null));
+ logd(TAG,
+ "Found existing trusted unique id: " + prefs.getString(UNIQUE_ID_KEY, ""));
+ }
+
+ if (mUniqueId == null) {
+ mUniqueId = UUID.randomUUID();
+ prefs.edit().putString(UNIQUE_ID_KEY, mUniqueId.toString()).apply();
+ logd(TAG,
+ "Generated new trusted unique id: " + prefs.getString(UNIQUE_ID_KEY, ""));
+ }
+
+ return mUniqueId;
+ }
+
+ /**
+ * Get a list of associated devices for the given user.
+ *
+ * @param userId The identifier of the user.
+ * @return Associated device list.
+ */
+ @NonNull
+ public List<AssociatedDevice> getAssociatedDevicesForUser(@NonNull int userId) {
+ List<AssociatedDeviceEntity> entities =
+ mAssociatedDeviceDatabase.getAssociatedDevicesForUser(userId);
+
+ if (entities == null) {
+ return new ArrayList<>();
+ }
+
+ ArrayList<AssociatedDevice> userDevices = new ArrayList<>();
+ for (AssociatedDeviceEntity entity : entities) {
+ userDevices.add(entity.toAssociatedDevice());
+ }
+
+ return userDevices;
+ }
+
+ /**
+ * Get a list of associated devices for the current user.
+ *
+ * @return Associated device list.
+ */
+ @NonNull
+ public List<AssociatedDevice> getActiveUserAssociatedDevices() {
+ return getAssociatedDevicesForUser(ActivityManager.getCurrentUser());
+ }
+
+ /**
+ * Returns a list of device ids of associated devices for the given user.
+ *
+ * @param userId The user id for whom we want to know the device ids.
+ * @return List of device ids.
+ */
+ @NonNull
+ public List<String> getAssociatedDeviceIdsForUser(@NonNull int userId) {
+ List<AssociatedDevice> userDevices = getAssociatedDevicesForUser(userId);
+ ArrayList<String> userDeviceIds = new ArrayList<>();
+
+ for (AssociatedDevice device : userDevices) {
+ userDeviceIds.add(device.getDeviceId());
+ }
+
+ return userDeviceIds;
+ }
+
+ /**
+ * Returns a list of device ids of associated devices for the current user.
+ *
+ * @return List of device ids.
+ */
+ @NonNull
+ public List<String> getActiveUserAssociatedDeviceIds() {
+ return getAssociatedDeviceIdsForUser(ActivityManager.getCurrentUser());
+ }
+
+ /**
+ * Add the associated device of the given deviceId for the currently active user.
+ *
+ * @param device New associated device to be added.
+ */
+ public void addAssociatedDeviceForActiveUser(@NonNull AssociatedDevice device) {
+ addAssociatedDeviceForUser(ActivityManager.getCurrentUser(), device);
+ if (mAssociatedDeviceCallback != null) {
+ mAssociatedDeviceCallback.onAssociatedDeviceAdded(device.getDeviceId());
+ }
+ }
+
+
+ /**
+ * Add the associated device of the given deviceId for the given user.
+ *
+ * @param userId The identifier of the user.
+ * @param device New associated device to be added.
+ */
+ public void addAssociatedDeviceForUser(int userId, @NonNull AssociatedDevice device) {
+ AssociatedDeviceEntity entity = new AssociatedDeviceEntity(userId, device);
+ mAssociatedDeviceDatabase.addOrReplaceAssociatedDevice(entity);
+ }
+
+ /**
+ * Update the name for an associated device.
+ *
+ * @param deviceId The id of the associated device.
+ * @param name The name to replace with.
+ */
+ public void updateAssociatedDeviceName(@NonNull String deviceId, @NonNull String name) {
+ AssociatedDeviceEntity entity = mAssociatedDeviceDatabase.getAssociatedDevice(deviceId);
+ if (entity == null) {
+ logw(TAG, "Attempt to update name on an unrecognized device " + deviceId
+ + ". Ignoring.");
+ return;
+ }
+ entity.name = name;
+ mAssociatedDeviceDatabase.addOrReplaceAssociatedDevice(entity);
+ if (mAssociatedDeviceCallback != null) {
+ mAssociatedDeviceCallback.onAssociatedDeviceUpdated(
+ new AssociatedDevice(deviceId, entity.address, name));
+ }
+
+ }
+
+ /**
+ * Remove the associated device of the given deviceId for the given user.
+ *
+ * @param userId The identifier of the user.
+ * @param deviceId The identifier of the device to be cleared.
+ */
+ public void removeAssociatedDevice(int userId, @NonNull String deviceId) {
+ AssociatedDeviceEntity entity = mAssociatedDeviceDatabase.getAssociatedDevice(deviceId);
+ if (entity == null || entity.userId != userId) {
+ return;
+ }
+ mAssociatedDeviceDatabase.removeAssociatedDevice(entity);
+ }
+
+ /**
+ * Clear the associated device of the given deviceId for the current user.
+ *
+ * @param deviceId The identifier of the device to be cleared.
+ */
+ public void removeAssociatedDeviceForActiveUser(@NonNull String deviceId) {
+ removeAssociatedDevice(ActivityManager.getCurrentUser(), deviceId);
+ if (mAssociatedDeviceCallback != null) {
+ mAssociatedDeviceCallback.onAssociatedDeviceRemoved(deviceId);
+ }
+ }
+
+ /** Callback for association device related events. */
+ public interface AssociatedDeviceCallback {
+ /** Triggered when an associated device has been added */
+ void onAssociatedDeviceAdded(@NonNull String deviceId);
+
+ /** Triggered when an associated device has been removed. */
+ void onAssociatedDeviceRemoved(@NonNull String deviceId);
+
+ /** Triggered when an associated device has been updated. */
+ void onAssociatedDeviceUpdated(@NonNull AssociatedDevice device);
+ }
+}
diff --git a/connected-device-lib/src/com/android/car/connecteddevice/util/ByteUtils.java b/connected-device-lib/src/com/android/car/connecteddevice/util/ByteUtils.java
new file mode 100644
index 0000000..3d07227
--- /dev/null
+++ b/connected-device-lib/src/com/android/car/connecteddevice/util/ByteUtils.java
@@ -0,0 +1,159 @@
+/*
+ * 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.car.connecteddevice.util;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.UUID;
+import java.util.concurrent.ThreadLocalRandom;
+
+/**
+ * Utility classes for manipulating bytes.
+ */
+public final class ByteUtils {
+ // https://developer.android.com/reference/java/util/UUID
+ private static final int UUID_LENGTH = 16;
+
+ private ByteUtils() {
+ }
+
+ /**
+ * Returns a byte buffer corresponding to the passed long argument.
+ *
+ * @param primitive data to convert format.
+ */
+ public static byte[] longToBytes(long primitive) {
+ ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES);
+ buffer.putLong(primitive);
+ return buffer.array();
+ }
+
+ /**
+ * Returns a byte buffer corresponding to the passed long argument.
+ *
+ * @param array data to convert format.
+ */
+ public static long bytesToLong(byte[] array) {
+ ByteBuffer buffer = ByteBuffer.allocate(Long.SIZE / Byte.SIZE);
+ buffer.put(array);
+ buffer.flip();
+ long value = buffer.getLong();
+ return value;
+ }
+
+ /**
+ * Returns a String in Hex format that is formed from the bytes in the byte array Useful for
+ * debugging
+ *
+ * @param array the byte array
+ * @return the Hex string version of the input byte array
+ */
+ public static String byteArrayToHexString(byte[] array) {
+ StringBuilder sb = new StringBuilder(array.length * 2);
+ for (byte b : array) {
+ sb.append(String.format("%02x", b));
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Convert UUID to Big Endian byte array
+ *
+ * @param uuid UUID to convert
+ * @return the byte array representing the UUID
+ */
+ @NonNull
+ public static byte[] uuidToBytes(@NonNull UUID uuid) {
+
+ return ByteBuffer.allocate(UUID_LENGTH)
+ .order(ByteOrder.BIG_ENDIAN)
+ .putLong(uuid.getMostSignificantBits())
+ .putLong(uuid.getLeastSignificantBits())
+ .array();
+ }
+
+ /**
+ * Convert Big Endian byte array to UUID
+ *
+ * @param bytes byte array to convert
+ * @return the UUID representing the byte array, or null if not a valid UUID
+ */
+ @Nullable
+ public static UUID bytesToUUID(@NonNull byte[] bytes) {
+ if (bytes.length != UUID_LENGTH) {
+ return null;
+ }
+
+ ByteBuffer buffer = ByteBuffer.wrap(bytes);
+ return new UUID(buffer.getLong(), buffer.getLong());
+ }
+
+ /**
+ * Generate a random zero-filled string of given length
+ *
+ * @param length of string
+ * @return generated string
+ */
+ @SuppressLint("DefaultLocale") // Should always have the same format regardless of locale
+ public static String generateRandomNumberString(int length) {
+ return String.format(
+ "%0" + length + "d",
+ ThreadLocalRandom.current().nextInt((int) Math.pow(10, length)));
+ }
+
+ /**
+ * Generate a {@link byte[]} with random bytes.
+ *
+ * @param size of array to generate.
+ * @return generated {@link byte[]}.
+ */
+ @NonNull
+ public static byte[] randomBytes(int size) {
+ byte[] array = new byte[size];
+ ThreadLocalRandom.current().nextBytes(array);
+ return array;
+ }
+
+ /**
+ * Concatentate the given 2 byte arrays
+ *
+ * @param a input array 1
+ * @param b input array 2
+ * @return concatenated array of arrays 1 and 2
+ */
+ @Nullable
+ public static byte[] concatByteArrays(@Nullable byte[] a, @Nullable byte[] b) {
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ try {
+ if (a != null) {
+ outputStream.write(a);
+ }
+ if (b != null) {
+ outputStream.write(b);
+ }
+ } catch (IOException e) {
+ return null;
+ }
+ return outputStream.toByteArray();
+ }
+}
diff --git a/connected-device-lib/src/com/android/car/connecteddevice/util/RemoteCallbackBinder.java b/connected-device-lib/src/com/android/car/connecteddevice/util/RemoteCallbackBinder.java
new file mode 100644
index 0000000..e18366b
--- /dev/null
+++ b/connected-device-lib/src/com/android/car/connecteddevice/util/RemoteCallbackBinder.java
@@ -0,0 +1,74 @@
+/*
+ * 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.connecteddevice.util;
+
+import static com.android.car.connecteddevice.util.SafeLog.logd;
+
+import android.os.IBinder;
+import android.os.RemoteException;
+
+import java.util.function.Consumer;
+
+/**
+ * Class that holds the binder of a remote callback and an action to be executed when this
+ * binder dies.
+ * It registers for death notification of the {@link #mCallbackBinder} and executes
+ * {@link #mOnDiedConsumer} when {@link #mCallbackBinder} dies.
+ */
+public class RemoteCallbackBinder implements IBinder.DeathRecipient {
+ private static final String TAG = "BinderClient";
+ private final IBinder mCallbackBinder;
+ private final Consumer<IBinder> mOnDiedConsumer;
+
+ public RemoteCallbackBinder(IBinder binder, Consumer<IBinder> onBinderDied) {
+ mCallbackBinder = binder;
+ mOnDiedConsumer = onBinderDied;
+ try {
+ binder.linkToDeath(this, 0);
+ } catch (RemoteException e) {
+ logd(TAG, "Cannot link death recipient to binder " + mCallbackBinder + ", "
+ + e);
+ }
+ }
+
+ @Override
+ public void binderDied() {
+ logd(TAG, "Binder died " + mCallbackBinder);
+ mOnDiedConsumer.accept(mCallbackBinder);
+ cleanUp();
+ }
+
+ /** Clean up the client. */
+ public void cleanUp() {
+ mCallbackBinder.unlinkToDeath(this, 0);
+ }
+
+ /** Get the callback binder of the client. */
+ public IBinder getCallbackBinder() {
+ return mCallbackBinder;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return mCallbackBinder.equals(obj);
+ }
+
+ @Override
+ public int hashCode() {
+ return mCallbackBinder.hashCode();
+ }
+}
diff --git a/connected-device-lib/src/com/android/car/connecteddevice/util/SafeLog.java b/connected-device-lib/src/com/android/car/connecteddevice/util/SafeLog.java
new file mode 100644
index 0000000..6ab18ce
--- /dev/null
+++ b/connected-device-lib/src/com/android/car/connecteddevice/util/SafeLog.java
@@ -0,0 +1,70 @@
+/*
+ * 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.connecteddevice.util;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.util.Log;
+
+/**
+ * Convenience logging methods that respect whitelisted tags.
+ */
+public class SafeLog {
+
+ private SafeLog() { }
+
+ /** Log message if tag is whitelisted for {@code Log.VERBOSE}. */
+ public static void logv(@NonNull String tag, @NonNull String message) {
+ if (Log.isLoggable(tag, Log.VERBOSE)) {
+ Log.v(tag, message);
+ }
+ }
+
+ /** Log message if tag is whitelisted for {@code Log.INFO}. */
+ public static void logi(@NonNull String tag, @NonNull String message) {
+ if (Log.isLoggable(tag, Log.INFO)) {
+ Log.i(tag, message);
+ }
+ }
+
+ /** Log message if tag is whitelisted for {@code Log.DEBUG}. */
+ public static void logd(@NonNull String tag, @NonNull String message) {
+ if (Log.isLoggable(tag, Log.DEBUG)) {
+ Log.d(tag, message);
+ }
+ }
+
+ /** Log message if tag is whitelisted for {@code Log.WARN}. */
+ public static void logw(@NonNull String tag, @NonNull String message) {
+ if (Log.isLoggable(tag, Log.WARN)) {
+ Log.w(tag, message);
+ }
+ }
+
+ /** Log message if tag is whitelisted for {@code Log.ERROR}. */
+ public static void loge(@NonNull String tag, @NonNull String message) {
+ loge(tag, message, /* exception = */ null);
+ }
+
+ /** Log message and optional exception if tag is whitelisted for {@code Log.ERROR}. */
+ public static void loge(@NonNull String tag, @NonNull String message,
+ @Nullable Exception exception) {
+ if (Log.isLoggable(tag, Log.ERROR)) {
+ Log.e(tag, message, exception);
+ }
+ }
+}
diff --git a/connected-device-lib/src/com/android/car/connecteddevice/util/ScanDataAnalyzer.java b/connected-device-lib/src/com/android/car/connecteddevice/util/ScanDataAnalyzer.java
new file mode 100644
index 0000000..6748bba
--- /dev/null
+++ b/connected-device-lib/src/com/android/car/connecteddevice/util/ScanDataAnalyzer.java
@@ -0,0 +1,124 @@
+/*
+ * 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.connecteddevice.util;
+
+import static com.android.car.connecteddevice.util.SafeLog.logw;
+
+import android.annotation.NonNull;
+import android.bluetooth.le.ScanResult;
+
+import java.math.BigInteger;
+
+/**
+ * Analyzer of {@link ScanResult} data to identify an Apple device that is advertising from the
+ * background.
+ */
+public class ScanDataAnalyzer {
+
+ private static final String TAG = "ScanDataAnalyzer";
+
+ private static final byte IOS_OVERFLOW_LENGTH = (byte) 0x14;
+ private static final byte IOS_ADVERTISING_TYPE = (byte) 0xff;
+ private static final int IOS_ADVERTISING_TYPE_LENGTH = 1;
+ private static final long IOS_OVERFLOW_CUSTOM_ID = 0x4c0001;
+ private static final int IOS_OVERFLOW_CUSTOM_ID_LENGTH = 3;
+ private static final int IOS_OVERFLOW_CONTENT_LENGTH =
+ IOS_OVERFLOW_LENGTH - IOS_OVERFLOW_CUSTOM_ID_LENGTH - IOS_ADVERTISING_TYPE_LENGTH;
+
+ private ScanDataAnalyzer() { }
+
+ /**
+ * Returns {@code true} if the given bytes from a [ScanResult] contains service UUIDs once the
+ * given serviceUuidMask is applied.
+ *
+ * When an iOS peripheral device goes into a background state, the service UUIDs and other
+ * identifying information are removed from the advertising data and replaced with a hashed
+ * bit in a special "overflow" area. There is no documentation on the layout of this area,
+ * and the below was compiled from experimentation and examples from others who have worked
+ * on reverse engineering iOS background peripherals.
+ *
+ * My best guess is Apple is taking the service UUID and hashing it into a bloom filter. This
+ * would allow any device with the same hashing function to filter for all devices that
+ * might contain the desired service. Since we do not have access to this hashing function,
+ * we must first advertise our service from an iOS device and manually inspect the bit that
+ * is flipped. Once known, it can be passed to serviceUuidMask and used as a filter.
+ *
+ * EXAMPLE
+ *
+ * Foreground contents:
+ * 02011A1107FB349B5F8000008000100000C53A00000709546573746572000000000000000000000000000000000000000000000000000000000000000000
+ *
+ * Background contents:
+ * 02011A14FF4C0001000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000
+ *
+ * The overflow bytes are comprised of four parts:
+ * Length -> 14
+ * Advertising type -> FF
+ * Id custom to Apple -> 4C0001
+ * Contents where hashed values are stored -> 00000000000000000000000000200000
+ *
+ * Apple's documentation on advertising from the background:
+ * https://developer.apple.com/library/archive/documentation/NetworkingInternetWeb/Conceptual/CoreBluetooth_concepts/CoreBluetoothBackgroundProcessingForIOSApps/PerformingTasksWhileYourAppIsInTheBackground.html#//apple_ref/doc/uid/TP40013257-CH7-SW9
+ *
+ * Other similar reverse engineering:
+ * http://www.pagepinner.com/2014/04/how-to-get-ble-overflow-hash-bit-from.html
+ */
+ public static boolean containsUuidsInOverflow(@NonNull byte[] scanData,
+ @NonNull BigInteger serviceUuidMask) {
+ byte[] overflowBytes = new byte[IOS_OVERFLOW_CONTENT_LENGTH];
+ int overflowPtr = 0;
+ int outPtr = 0;
+ try {
+ while (overflowPtr < scanData.length - IOS_OVERFLOW_LENGTH) {
+ byte length = scanData[overflowPtr++];
+ if (length == 0) {
+ break;
+ } else if (length != IOS_OVERFLOW_LENGTH) {
+ continue;
+ }
+
+ if (scanData[overflowPtr++] != IOS_ADVERTISING_TYPE) {
+ return false;
+ }
+
+ byte[] idBytes = new byte[IOS_OVERFLOW_CUSTOM_ID_LENGTH];
+ for (int i = 0; i < IOS_OVERFLOW_CUSTOM_ID_LENGTH; i++) {
+ idBytes[i] = scanData[overflowPtr++];
+ }
+
+ if (!new BigInteger(idBytes).equals(BigInteger.valueOf(IOS_OVERFLOW_CUSTOM_ID))) {
+ return false;
+ }
+
+ for (outPtr = 0; outPtr < IOS_OVERFLOW_CONTENT_LENGTH; outPtr++) {
+ overflowBytes[outPtr] = scanData[overflowPtr++];
+ }
+ break;
+ }
+
+ if (outPtr == IOS_OVERFLOW_CONTENT_LENGTH) {
+ BigInteger overflowBytesValue = new BigInteger(overflowBytes);
+ return overflowBytesValue.and(serviceUuidMask).signum() == 1;
+ }
+
+ } catch (ArrayIndexOutOfBoundsException e) {
+ logw(TAG, "Inspecting advertisement overflow bytes went out of bounds.");
+ }
+
+ return false;
+ }
+}
diff --git a/connected-device-lib/src/com/android/car/connecteddevice/util/ThreadSafeCallbacks.java b/connected-device-lib/src/com/android/car/connecteddevice/util/ThreadSafeCallbacks.java
new file mode 100644
index 0000000..b3d3ef1
--- /dev/null
+++ b/connected-device-lib/src/com/android/car/connecteddevice/util/ThreadSafeCallbacks.java
@@ -0,0 +1,60 @@
+/*
+ * 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.car.connecteddevice.util;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.NonNull;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
+
+/**
+ * Class for invoking thread-safe callbacks.
+ *
+ * @param <T> Callback type.
+ */
+public class ThreadSafeCallbacks<T> {
+
+ private final ConcurrentHashMap<T, Executor> mCallbacks = new ConcurrentHashMap<>();
+
+ /** Add a callback to be notified on its executor. */
+ public void add(@NonNull T callback, @NonNull @CallbackExecutor Executor executor) {
+ mCallbacks.put(callback, executor);
+ }
+
+ /** Remove a callback from the collection. */
+ public void remove(@NonNull T callback) {
+ mCallbacks.remove(callback);
+ }
+
+ /** Clear all callbacks from the collection. */
+ public void clear() {
+ mCallbacks.clear();
+ }
+
+ /** Return the number of callbacks in collection. */
+ public int size() {
+ return mCallbacks.size();
+ }
+
+ /** Invoke notification on all callbacks with their supplied {@link Executor}. */
+ public void invoke(Consumer<T> notification) {
+ mCallbacks.forEach((callback, executor) ->
+ executor.execute(() -> notification.accept(callback)));
+ }
+}
diff --git a/connected-device-lib/tests/unit/Android.bp b/connected-device-lib/tests/unit/Android.bp
new file mode 100644
index 0000000..9cf29ba
--- /dev/null
+++ b/connected-device-lib/tests/unit/Android.bp
@@ -0,0 +1,50 @@
+//
+// 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.
+//
+
+android_test {
+ name: "connected-device-lib-unit-tests",
+
+ srcs: ["src/**/*.java"],
+
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ "android.test.mock",
+ ],
+
+ static_libs: [
+ "android.car",
+ "androidx.test.core",
+ "androidx.test.ext.junit",
+ "androidx.test.rules",
+ "connected-device-lib",
+ "mockito-target-extended-minus-junit4",
+ "testables",
+ "truth-prebuilt",
+ ],
+
+ jni_libs: [
+ // For mockito extended
+ "libdexmakerjvmtiagent",
+ "libstaticjvmtiagent",
+ ],
+
+ platform_apis: true,
+
+ certificate: "platform",
+
+ privileged: true,
+}
\ No newline at end of file
diff --git a/connected-device-lib/tests/unit/AndroidManifest.xml b/connected-device-lib/tests/unit/AndroidManifest.xml
new file mode 100644
index 0000000..9863ccf
--- /dev/null
+++ b/connected-device-lib/tests/unit/AndroidManifest.xml
@@ -0,0 +1,37 @@
+<!--
+ ~ 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.car.connecteddevice.tests.unit">
+
+ <!-- Needed for BLE scanning/advertising -->
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+ <uses-permission android:name="android.permission.BLUETOOTH"/>
+ <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
+
+ <!-- Needed for detecting foreground user -->
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS"/>
+ <uses-permission android:name="android.permission.MANAGE_USERS" />
+
+ <application android:testOnly="true"
+ android:debuggable="true">
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.car.connecteddevice.tests.unit"
+ android:label="Connected Device Lib Test Cases" />
+</manifest>
diff --git a/connected-device-lib/tests/unit/README.md b/connected-device-lib/tests/unit/README.md
new file mode 100644
index 0000000..4543058
--- /dev/null
+++ b/connected-device-lib/tests/unit/README.md
@@ -0,0 +1,24 @@
+# Instructions for running unit tests
+
+### Build unit test module
+
+`m connected-device-lib-unit-tests`
+
+### Install resulting apk on device
+
+`adb install -r -t $OUT/testcases/connected-device-lib-unit-tests/arm64/connected-device-lib-unit-tests.apk`
+
+### Run all tests
+
+`adb shell am instrument -w com.android.car.connecteddevice.tests.unit`
+
+### Run tests in a class
+
+`adb shell am instrument -w -e class com.android.car.connecteddevice.<classPath> com.android.car.connecteddevice.tests.unit`
+
+### Run a specific test
+
+`adb shell am instrument -w -e class com.android.car.connecteddevice.<classPath>#<testMethod> com.android.car.connecteddevice.tests.unit`
+
+More general information can be found at
+http://developer.android.com/reference/android/support/test/runner/AndroidJUnitRunner.html
\ No newline at end of file
diff --git a/connected-device-lib/tests/unit/src/com/android/car/connecteddevice/ConnectedDeviceManagerTest.java b/connected-device-lib/tests/unit/src/com/android/car/connecteddevice/ConnectedDeviceManagerTest.java
new file mode 100644
index 0000000..58e7892
--- /dev/null
+++ b/connected-device-lib/tests/unit/src/com/android/car/connecteddevice/ConnectedDeviceManagerTest.java
@@ -0,0 +1,627 @@
+/*
+ * 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.car.connecteddevice;
+
+import static com.android.car.connecteddevice.ConnectedDeviceManager.DEVICE_ERROR_INSECURE_RECIPIENT_ID_DETECTED;
+import static com.android.car.connecteddevice.ConnectedDeviceManager.DEVICE_ERROR_INVALID_SECURITY_KEY;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mockitoSession;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.annotation.NonNull;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.car.connecteddevice.ConnectedDeviceManager.ConnectionCallback;
+import com.android.car.connecteddevice.ConnectedDeviceManager.DeviceAssociationCallback;
+import com.android.car.connecteddevice.ConnectedDeviceManager.DeviceCallback;
+import com.android.car.connecteddevice.ble.CarBleCentralManager;
+import com.android.car.connecteddevice.ble.CarBleManager;
+import com.android.car.connecteddevice.ble.CarBlePeripheralManager;
+import com.android.car.connecteddevice.ble.DeviceMessage;
+import com.android.car.connecteddevice.model.AssociatedDevice;
+import com.android.car.connecteddevice.model.ConnectedDevice;
+import com.android.car.connecteddevice.storage.ConnectedDeviceStorage;
+import com.android.car.connecteddevice.storage.ConnectedDeviceStorage.AssociatedDeviceCallback;
+import com.android.car.connecteddevice.util.ByteUtils;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.UUID;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+public class ConnectedDeviceManagerTest {
+
+ private final Executor mCallbackExecutor = Executors.newSingleThreadExecutor();
+
+ private final UUID mRecipientId = UUID.randomUUID();
+
+ @Mock
+ private ConnectedDeviceStorage mMockStorage;
+
+ @Mock
+ private CarBlePeripheralManager mMockPeripheralManager;
+
+ @Mock
+ private CarBleCentralManager mMockCentralManager;
+
+ private ConnectedDeviceManager mConnectedDeviceManager;
+
+ private MockitoSession mMockingSession;
+
+ private AssociatedDeviceCallback mAssociatedDeviceCallback;
+
+ @Before
+ public void setUp() {
+ mMockingSession = mockitoSession()
+ .initMocks(this)
+ .strictness(Strictness.LENIENT)
+ .startMocking();
+ ArgumentCaptor<AssociatedDeviceCallback> callbackCaptor = ArgumentCaptor
+ .forClass(AssociatedDeviceCallback.class);
+ mConnectedDeviceManager = new ConnectedDeviceManager(mMockStorage, mMockCentralManager,
+ mMockPeripheralManager);
+ verify(mMockStorage).setAssociatedDeviceCallback(callbackCaptor.capture());
+ mAssociatedDeviceCallback = callbackCaptor.getValue();
+ mConnectedDeviceManager.start();
+ }
+
+ @After
+ public void tearDown() {
+ if (mMockingSession != null) {
+ mMockingSession.finishMocking();
+ }
+ }
+
+ @Test
+ public void getActiveUserConnectedDevices_initiallyShouldReturnEmptyList() {
+ assertThat(mConnectedDeviceManager.getActiveUserConnectedDevices()).isEmpty();
+ }
+
+ @Test
+ public void getActiveUserConnectedDevices_includesNewlyConnectedDevice() {
+ String deviceId = connectNewDevice(mMockCentralManager);
+ List<ConnectedDevice> activeUserDevices =
+ mConnectedDeviceManager.getActiveUserConnectedDevices();
+ ConnectedDevice expectedDevice = new ConnectedDevice(deviceId, /* deviceName = */ null,
+ /* belongsToActiveUser = */ true, /* hasSecureChannel = */ false);
+ assertThat(activeUserDevices).containsExactly(expectedDevice);
+ }
+
+ @Test
+ public void getActiveUserConnectedDevices_excludesDevicesNotBelongingToActiveUser() {
+ String deviceId = UUID.randomUUID().toString();
+ String otherUserDeviceId = UUID.randomUUID().toString();
+ when(mMockStorage.getActiveUserAssociatedDeviceIds()).thenReturn(
+ Collections.singletonList(otherUserDeviceId));
+ mConnectedDeviceManager.addConnectedDevice(deviceId, mMockCentralManager);
+ assertThat(mConnectedDeviceManager.getActiveUserConnectedDevices()).isEmpty();
+ }
+
+ @Test
+ public void getActiveUserConnectedDevices_reflectsSecureChannelEstablished() {
+ String deviceId = connectNewDevice(mMockCentralManager);
+ mConnectedDeviceManager.onSecureChannelEstablished(deviceId, mMockCentralManager);
+ ConnectedDevice connectedDevice =
+ mConnectedDeviceManager.getActiveUserConnectedDevices().get(0);
+ assertThat(connectedDevice.hasSecureChannel()).isTrue();
+ }
+
+ @Test
+ public void getActiveUserConnectedDevices_excludesDisconnectedDevice() {
+ String deviceId = connectNewDevice(mMockCentralManager);
+ mConnectedDeviceManager.removeConnectedDevice(deviceId, mMockCentralManager);
+ assertThat(mConnectedDeviceManager.getActiveUserConnectedDevices()).isEmpty();
+ }
+
+ @Test
+ public void getActiveUserConnectedDevices_unaffectedByOtherManagerDisconnect() {
+ String deviceId = connectNewDevice(mMockCentralManager);
+ mConnectedDeviceManager.removeConnectedDevice(deviceId, mMockPeripheralManager);
+ assertThat(mConnectedDeviceManager.getActiveUserConnectedDevices()).hasSize(1);
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void sendMessageSecurely_throwsIllegalStateExceptionIfNoSecureChannel() {
+ connectNewDevice(mMockCentralManager);
+ ConnectedDevice device = mConnectedDeviceManager.getActiveUserConnectedDevices().get(0);
+ UUID recipientId = UUID.randomUUID();
+ byte[] message = ByteUtils.randomBytes(10);
+ mConnectedDeviceManager.sendMessageSecurely(device, recipientId, message);
+ }
+
+ @Test
+ public void sendMessageSecurely_sendsEncryptedMessage() {
+ String deviceId = connectNewDevice(mMockCentralManager);
+ mConnectedDeviceManager.onSecureChannelEstablished(deviceId, mMockCentralManager);
+ ConnectedDevice device = mConnectedDeviceManager.getActiveUserConnectedDevices().get(0);
+ UUID recipientId = UUID.randomUUID();
+ byte[] message = ByteUtils.randomBytes(10);
+ mConnectedDeviceManager.sendMessageSecurely(device, recipientId, message);
+ ArgumentCaptor<DeviceMessage> messageCaptor = ArgumentCaptor.forClass(DeviceMessage.class);
+ verify(mMockCentralManager).sendMessage(eq(deviceId), messageCaptor.capture());
+ assertThat(messageCaptor.getValue().isMessageEncrypted()).isTrue();
+ }
+
+ @Test
+ public void sendMessageSecurely_doesNotSendIfDeviceDisconnected() {
+ String deviceId = connectNewDevice(mMockCentralManager);
+ ConnectedDevice device = mConnectedDeviceManager.getActiveUserConnectedDevices().get(0);
+ mConnectedDeviceManager.removeConnectedDevice(deviceId, mMockCentralManager);
+ UUID recipientId = UUID.randomUUID();
+ byte[] message = ByteUtils.randomBytes(10);
+ mConnectedDeviceManager.sendMessageSecurely(device, recipientId, message);
+ verify(mMockCentralManager, times(0)).sendMessage(eq(deviceId), any(DeviceMessage.class));
+ }
+
+ @Test
+ public void sendMessageUnsecurely_sendsMessageWithoutEncryption() {
+ String deviceId = connectNewDevice(mMockCentralManager);
+ ConnectedDevice device = mConnectedDeviceManager.getActiveUserConnectedDevices().get(0);
+ UUID recipientId = UUID.randomUUID();
+ byte[] message = ByteUtils.randomBytes(10);
+ mConnectedDeviceManager.sendMessageUnsecurely(device, recipientId, message);
+ ArgumentCaptor<DeviceMessage> messageCaptor = ArgumentCaptor.forClass(DeviceMessage.class);
+ verify(mMockCentralManager).sendMessage(eq(deviceId), messageCaptor.capture());
+ assertThat(messageCaptor.getValue().isMessageEncrypted()).isFalse();
+ }
+
+ @Test
+ public void connectionCallback_onDeviceConnectedInvokedForNewlyConnectedDevice()
+ throws InterruptedException {
+ Semaphore semaphore = new Semaphore(0);
+ ConnectionCallback connectionCallback = createConnectionCallback(semaphore);
+ mConnectedDeviceManager.registerActiveUserConnectionCallback(connectionCallback,
+ mCallbackExecutor);
+ String deviceId = connectNewDevice(mMockCentralManager);
+ assertThat(tryAcquire(semaphore)).isTrue();
+ ArgumentCaptor<ConnectedDevice> deviceCaptor =
+ ArgumentCaptor.forClass(ConnectedDevice.class);
+ verify(connectionCallback).onDeviceConnected(deviceCaptor.capture());
+ ConnectedDevice connectedDevice = deviceCaptor.getValue();
+ assertThat(connectedDevice.getDeviceId()).isEqualTo(deviceId);
+ assertThat(connectedDevice.hasSecureChannel()).isFalse();
+ }
+
+ @Test
+ public void connectionCallback_onDeviceConnectedNotInvokedDeviceConnectedForDifferentUser()
+ throws InterruptedException {
+ Semaphore semaphore = new Semaphore(0);
+ ConnectionCallback connectionCallback = createConnectionCallback(semaphore);
+ mConnectedDeviceManager.registerActiveUserConnectionCallback(connectionCallback,
+ mCallbackExecutor);
+ String deviceId = UUID.randomUUID().toString();
+ String otherUserDeviceId = UUID.randomUUID().toString();
+ when(mMockStorage.getActiveUserAssociatedDeviceIds()).thenReturn(
+ Collections.singletonList(otherUserDeviceId));
+ mConnectedDeviceManager.addConnectedDevice(deviceId, mMockCentralManager);
+ assertThat(tryAcquire(semaphore)).isFalse();
+ }
+
+ @Test
+ public void connectionCallback_onDeviceConnectedNotInvokedForDifferentBleManager()
+ throws InterruptedException {
+ Semaphore semaphore = new Semaphore(0);
+ String deviceId = connectNewDevice(mMockPeripheralManager);
+ ConnectionCallback connectionCallback = createConnectionCallback(semaphore);
+ mConnectedDeviceManager.registerActiveUserConnectionCallback(connectionCallback,
+ mCallbackExecutor);
+ mConnectedDeviceManager.addConnectedDevice(deviceId, mMockCentralManager);
+ assertThat(tryAcquire(semaphore)).isFalse();
+ }
+
+ @Test
+ public void connectionCallback_onDeviceDisconnectedInvokedForActiveUserDevice()
+ throws InterruptedException {
+ Semaphore semaphore = new Semaphore(0);
+ String deviceId = connectNewDevice(mMockCentralManager);
+ ConnectionCallback connectionCallback = createConnectionCallback(semaphore);
+ mConnectedDeviceManager.registerActiveUserConnectionCallback(connectionCallback,
+ mCallbackExecutor);
+ mConnectedDeviceManager.removeConnectedDevice(deviceId, mMockCentralManager);
+ assertThat(tryAcquire(semaphore)).isTrue();
+ ArgumentCaptor<ConnectedDevice> deviceCaptor =
+ ArgumentCaptor.forClass(ConnectedDevice.class);
+ verify(connectionCallback).onDeviceDisconnected(deviceCaptor.capture());
+ assertThat(deviceCaptor.getValue().getDeviceId()).isEqualTo(deviceId);
+ }
+
+ @Test
+ public void connectionCallback_onDeviceDisconnectedNotInvokedDeviceForDifferentUser()
+ throws InterruptedException {
+ Semaphore semaphore = new Semaphore(0);
+ String deviceId = UUID.randomUUID().toString();
+ mConnectedDeviceManager.addConnectedDevice(deviceId, mMockCentralManager);
+ ConnectionCallback connectionCallback = createConnectionCallback(semaphore);
+ mConnectedDeviceManager.registerActiveUserConnectionCallback(connectionCallback,
+ mCallbackExecutor);
+ mConnectedDeviceManager.removeConnectedDevice(deviceId, mMockCentralManager);
+ assertThat(tryAcquire(semaphore)).isFalse();
+ }
+
+ @Test
+ public void unregisterConnectionCallback_removesCallbackAndNotInvoked()
+ throws InterruptedException {
+ Semaphore semaphore = new Semaphore(0);
+ ConnectionCallback connectionCallback = createConnectionCallback(semaphore);
+ mConnectedDeviceManager.registerActiveUserConnectionCallback(connectionCallback,
+ mCallbackExecutor);
+ mConnectedDeviceManager.unregisterConnectionCallback(connectionCallback);
+ connectNewDevice(mMockCentralManager);
+ assertThat(tryAcquire(semaphore)).isFalse();
+ }
+
+ @Test
+ public void registerDeviceCallback_blacklistsDuplicateRecipientId()
+ throws InterruptedException {
+ connectNewDevice(mMockCentralManager);
+ ConnectedDevice connectedDevice =
+ mConnectedDeviceManager.getActiveUserConnectedDevices().get(0);
+ Semaphore firstSemaphore = new Semaphore(0);
+ Semaphore secondSemaphore = new Semaphore(0);
+ Semaphore thirdSemaphore = new Semaphore(0);
+ DeviceCallback firstDeviceCallback = createDeviceCallback(firstSemaphore);
+ DeviceCallback secondDeviceCallback = createDeviceCallback(secondSemaphore);
+ DeviceCallback thirdDeviceCallback = createDeviceCallback(thirdSemaphore);
+
+ // Register three times for following chain of events:
+ // 1. First callback registered without issue.
+ // 2. Second callback with same recipientId triggers blacklisting both callbacks and issues
+ // error callbacks on both. Both callbacks should be unregistered at this point.
+ // 3. Third callback gets rejected at registration and issues error callback.
+
+ mConnectedDeviceManager.registerDeviceCallback(connectedDevice, mRecipientId,
+ firstDeviceCallback, mCallbackExecutor);
+ mConnectedDeviceManager.registerDeviceCallback(connectedDevice, mRecipientId,
+ secondDeviceCallback, mCallbackExecutor);
+ DeviceMessage message = new DeviceMessage(mRecipientId, false, new byte[10]);
+ mConnectedDeviceManager.onMessageReceived(connectedDevice.getDeviceId(), message);
+ assertThat(tryAcquire(firstSemaphore)).isTrue();
+ assertThat(tryAcquire(secondSemaphore)).isTrue();
+ verify(firstDeviceCallback)
+ .onDeviceError(connectedDevice, DEVICE_ERROR_INSECURE_RECIPIENT_ID_DETECTED);
+ verify(secondDeviceCallback)
+ .onDeviceError(connectedDevice, DEVICE_ERROR_INSECURE_RECIPIENT_ID_DETECTED);
+ verify(firstDeviceCallback, times(0)).onMessageReceived(any(), any());
+ verify(secondDeviceCallback, times(0)).onMessageReceived(any(), any());
+
+ mConnectedDeviceManager.registerDeviceCallback(connectedDevice, mRecipientId,
+ thirdDeviceCallback, mCallbackExecutor);
+ assertThat(tryAcquire(thirdSemaphore)).isTrue();
+ verify(thirdDeviceCallback)
+ .onDeviceError(connectedDevice, DEVICE_ERROR_INSECURE_RECIPIENT_ID_DETECTED);
+ }
+
+ @Test
+ public void deviceCallback_onSecureChannelEstablishedInvoked() throws InterruptedException {
+ Semaphore semaphore = new Semaphore(0);
+ connectNewDevice(mMockCentralManager);
+ ConnectedDevice connectedDevice =
+ mConnectedDeviceManager.getActiveUserConnectedDevices().get(0);
+ DeviceCallback deviceCallback = createDeviceCallback(semaphore);
+ mConnectedDeviceManager.registerDeviceCallback(connectedDevice, mRecipientId,
+ deviceCallback, mCallbackExecutor);
+ mConnectedDeviceManager.onSecureChannelEstablished(connectedDevice.getDeviceId(),
+ mMockCentralManager);
+ connectedDevice =
+ mConnectedDeviceManager.getActiveUserConnectedDevices().get(0);
+ assertThat(tryAcquire(semaphore)).isTrue();
+ verify(deviceCallback).onSecureChannelEstablished(connectedDevice);
+ }
+
+ @Test
+ public void deviceCallback_onSecureChannelEstablishedNotInvokedWithSecondBleManager()
+ throws InterruptedException {
+ Semaphore semaphore = new Semaphore(0);
+ connectNewDevice(mMockCentralManager);
+ ConnectedDevice connectedDevice =
+ mConnectedDeviceManager.getActiveUserConnectedDevices().get(0);
+ mConnectedDeviceManager.onSecureChannelEstablished(connectedDevice.getDeviceId(),
+ mMockCentralManager);
+ DeviceCallback deviceCallback = createDeviceCallback(semaphore);
+ mConnectedDeviceManager.registerDeviceCallback(connectedDevice, mRecipientId,
+ deviceCallback, mCallbackExecutor);
+ mConnectedDeviceManager.onSecureChannelEstablished(connectedDevice.getDeviceId(),
+ mMockPeripheralManager);
+ assertThat(tryAcquire(semaphore)).isFalse();
+ }
+
+ @Test
+ public void deviceCallback_onMessageReceivedInvokedForSameRecipientId()
+ throws InterruptedException {
+ Semaphore semaphore = new Semaphore(0);
+ connectNewDevice(mMockCentralManager);
+ ConnectedDevice connectedDevice =
+ mConnectedDeviceManager.getActiveUserConnectedDevices().get(0);
+ DeviceCallback deviceCallback = createDeviceCallback(semaphore);
+ mConnectedDeviceManager.registerDeviceCallback(connectedDevice, mRecipientId,
+ deviceCallback, mCallbackExecutor);
+ byte[] payload = ByteUtils.randomBytes(10);
+ DeviceMessage message = new DeviceMessage(mRecipientId, false, payload);
+ mConnectedDeviceManager.onMessageReceived(connectedDevice.getDeviceId(), message);
+ assertThat(tryAcquire(semaphore)).isTrue();
+ verify(deviceCallback).onMessageReceived(connectedDevice, payload);
+ }
+
+ @Test
+ public void deviceCallback_onMessageReceivedNotInvokedForDifferentRecipientId()
+ throws InterruptedException {
+ Semaphore semaphore = new Semaphore(0);
+ connectNewDevice(mMockCentralManager);
+ ConnectedDevice connectedDevice =
+ mConnectedDeviceManager.getActiveUserConnectedDevices().get(0);
+ DeviceCallback deviceCallback = createDeviceCallback(semaphore);
+ mConnectedDeviceManager.registerDeviceCallback(connectedDevice, mRecipientId,
+ deviceCallback, mCallbackExecutor);
+ byte[] payload = ByteUtils.randomBytes(10);
+ DeviceMessage message = new DeviceMessage(UUID.randomUUID(), false, payload);
+ mConnectedDeviceManager.onMessageReceived(connectedDevice.getDeviceId(), message);
+ assertThat(tryAcquire(semaphore)).isFalse();
+ }
+
+ @Test
+ public void deviceCallback_onDeviceErrorInvokedOnChannelError() throws InterruptedException {
+ Semaphore semaphore = new Semaphore(0);
+ connectNewDevice(mMockCentralManager);
+ ConnectedDevice connectedDevice =
+ mConnectedDeviceManager.getActiveUserConnectedDevices().get(0);
+ DeviceCallback deviceCallback = createDeviceCallback(semaphore);
+ mConnectedDeviceManager.registerDeviceCallback(connectedDevice, mRecipientId,
+ deviceCallback, mCallbackExecutor);
+ mConnectedDeviceManager.deviceErrorOccurred(connectedDevice.getDeviceId());
+ assertThat(tryAcquire(semaphore)).isTrue();
+ verify(deviceCallback).onDeviceError(connectedDevice, DEVICE_ERROR_INVALID_SECURITY_KEY);
+ }
+
+ @Test
+ public void unregisterDeviceCallback_removesCallbackAndNotInvoked()
+ throws InterruptedException {
+ Semaphore semaphore = new Semaphore(0);
+ connectNewDevice(mMockCentralManager);
+ ConnectedDevice connectedDevice =
+ mConnectedDeviceManager.getActiveUserConnectedDevices().get(0);
+ DeviceCallback deviceCallback = createDeviceCallback(semaphore);
+ mConnectedDeviceManager.registerDeviceCallback(connectedDevice, mRecipientId,
+ deviceCallback, mCallbackExecutor);
+ mConnectedDeviceManager.unregisterDeviceCallback(connectedDevice, mRecipientId,
+ deviceCallback);
+ mConnectedDeviceManager.onSecureChannelEstablished(connectedDevice.getDeviceId(),
+ mMockPeripheralManager);
+ assertThat(tryAcquire(semaphore)).isFalse();
+ }
+
+ @Test
+ public void registerDeviceCallback_sendsMissedMessageAfterRegistration()
+ throws InterruptedException {
+ Semaphore semaphore = new Semaphore(0);
+ connectNewDevice(mMockCentralManager);
+ ConnectedDevice connectedDevice =
+ mConnectedDeviceManager.getActiveUserConnectedDevices().get(0);
+ byte[] payload = ByteUtils.randomBytes(10);
+ DeviceMessage message = new DeviceMessage(mRecipientId, false, payload);
+ mConnectedDeviceManager.onMessageReceived(connectedDevice.getDeviceId(), message);
+ DeviceCallback deviceCallback = createDeviceCallback(semaphore);
+ mConnectedDeviceManager.registerDeviceCallback(connectedDevice, mRecipientId,
+ deviceCallback, mCallbackExecutor);
+ assertThat(tryAcquire(semaphore)).isTrue();
+ verify(deviceCallback).onMessageReceived(connectedDevice, payload);
+ }
+
+ @Test
+ public void registerDeviceCallback_doesNotSendMissedMessageForDifferentRecipient()
+ throws InterruptedException {
+ Semaphore semaphore = new Semaphore(0);
+ connectNewDevice(mMockCentralManager);
+ ConnectedDevice connectedDevice =
+ mConnectedDeviceManager.getActiveUserConnectedDevices().get(0);
+ byte[] payload = ByteUtils.randomBytes(10);
+ DeviceMessage message = new DeviceMessage(UUID.randomUUID(), false, payload);
+ mConnectedDeviceManager.onMessageReceived(connectedDevice.getDeviceId(), message);
+ DeviceCallback deviceCallback = createDeviceCallback(semaphore);
+ mConnectedDeviceManager.registerDeviceCallback(connectedDevice, mRecipientId,
+ deviceCallback, mCallbackExecutor);
+ assertThat(tryAcquire(semaphore)).isFalse();
+ }
+
+ @Test
+ public void registerDeviceCallback_doesNotSendMissedMessageForDifferentDevice()
+ throws InterruptedException {
+ Semaphore semaphore = new Semaphore(0);
+ connectNewDevice(mMockCentralManager);
+ connectNewDevice(mMockCentralManager);
+ List<ConnectedDevice> connectedDevices =
+ mConnectedDeviceManager.getActiveUserConnectedDevices();
+ ConnectedDevice connectedDevice = connectedDevices.get(0);
+ ConnectedDevice otherDevice = connectedDevices.get(1);
+ byte[] payload = ByteUtils.randomBytes(10);
+ DeviceMessage message = new DeviceMessage(mRecipientId, false, payload);
+ mConnectedDeviceManager.onMessageReceived(otherDevice.getDeviceId(), message);
+ DeviceCallback deviceCallback = createDeviceCallback(semaphore);
+ mConnectedDeviceManager.registerDeviceCallback(connectedDevice, mRecipientId,
+ deviceCallback, mCallbackExecutor);
+ assertThat(tryAcquire(semaphore)).isFalse();
+ }
+
+ @Test
+ public void onAssociationCompleted_disconnectsOriginalDeviceAndReconnectsAsActiveUser()
+ throws InterruptedException {
+ String deviceId = UUID.randomUUID().toString();
+ mConnectedDeviceManager.addConnectedDevice(deviceId, mMockPeripheralManager);
+ Semaphore semaphore = new Semaphore(0);
+ ConnectionCallback connectionCallback = createConnectionCallback(semaphore);
+ mConnectedDeviceManager.registerActiveUserConnectionCallback(connectionCallback,
+ mCallbackExecutor);
+ when(mMockStorage.getActiveUserAssociatedDeviceIds()).thenReturn(
+ Collections.singletonList(deviceId));
+ mConnectedDeviceManager.onAssociationCompleted(deviceId);
+ assertThat(tryAcquire(semaphore)).isTrue();
+ }
+
+ private boolean tryAcquire(Semaphore semaphore) throws InterruptedException {
+ return semaphore.tryAcquire(100, TimeUnit.MILLISECONDS);
+ }
+
+ @Test
+ public void deviceAssociationCallback_onAssociatedDeviceAdded() throws InterruptedException {
+ Semaphore semaphore = new Semaphore(0);
+ DeviceAssociationCallback callback = createDeviceAssociationCallback(semaphore);
+ mConnectedDeviceManager.registerDeviceAssociationCallback(callback, mCallbackExecutor);
+ String deviceId = UUID.randomUUID().toString();
+ mAssociatedDeviceCallback.onAssociatedDeviceAdded(deviceId);
+ assertThat(tryAcquire(semaphore)).isTrue();
+ verify(callback).onAssociatedDeviceAdded(eq(deviceId));
+ }
+
+ @Test
+ public void deviceAssociationCallback_onAssociationDeviceRemoved() throws InterruptedException {
+ Semaphore semaphore = new Semaphore(0);
+ DeviceAssociationCallback callback = createDeviceAssociationCallback(semaphore);
+ mConnectedDeviceManager.registerDeviceAssociationCallback(callback, mCallbackExecutor);
+ String deviceId = UUID.randomUUID().toString();
+ mAssociatedDeviceCallback.onAssociatedDeviceRemoved(deviceId);
+ assertThat(tryAcquire(semaphore)).isTrue();
+ verify(callback).onAssociatedDeviceRemoved(eq(deviceId));
+ }
+
+ @Test
+ public void deviceAssociationCallback_onAssociatedDeviceUpdated() throws InterruptedException {
+ Semaphore semaphore = new Semaphore(0);
+ DeviceAssociationCallback callback = createDeviceAssociationCallback(semaphore);
+ mConnectedDeviceManager.registerDeviceAssociationCallback(callback, mCallbackExecutor);
+ String deviceId = UUID.randomUUID().toString();
+ String deviceAddress = "00:11:22:33:44:55";
+ String deviceName = "TEST_NAME";
+ AssociatedDevice testDevice = new AssociatedDevice(deviceId, deviceAddress, deviceName);
+ mAssociatedDeviceCallback.onAssociatedDeviceUpdated(testDevice);
+ assertThat(tryAcquire(semaphore)).isTrue();
+ verify(callback).onAssociatedDeviceUpdated(eq(testDevice));
+ }
+
+ @Test
+ public void removeConnectedDevice_startsAdvertisingForActiveUserDevice()
+ throws InterruptedException {
+ String deviceId = UUID.randomUUID().toString();
+ when(mMockStorage.getActiveUserAssociatedDeviceIds()).thenReturn(
+ Collections.singletonList(deviceId));
+ mConnectedDeviceManager.addConnectedDevice(deviceId, mMockPeripheralManager);
+ mConnectedDeviceManager.removeConnectedDevice(deviceId, mMockPeripheralManager);
+ Thread.sleep(100); // Async process so need to allow it time to complete.
+ // ConnectedDeviceManager.start() also invokes connectToDevice(), so expect # of calls = 2.
+ verify(mMockPeripheralManager, timeout(1000).times(2))
+ .connectToDevice(eq(UUID.fromString(deviceId)));
+ }
+
+ @Test
+ public void removeConnectedDevice__doesNotAdvertiseForNonActiveUserDevice()
+ throws InterruptedException {
+ String deviceId = UUID.randomUUID().toString();
+ String userDeviceId = UUID.randomUUID().toString();
+ when(mMockStorage.getActiveUserAssociatedDeviceIds()).thenReturn(
+ Collections.singletonList(userDeviceId));
+ mConnectedDeviceManager.addConnectedDevice(deviceId, mMockPeripheralManager);
+ mConnectedDeviceManager.removeConnectedDevice(deviceId, mMockPeripheralManager);
+ // ConnectedDeviceManager.start() invokes connectToDevice(), so expect # of calls = 1.
+ verify(mMockPeripheralManager, timeout(1000))
+ .connectToDevice(eq(UUID.fromString(userDeviceId)));
+ }
+
+ @NonNull
+ private String connectNewDevice(@NonNull CarBleManager carBleManager) {
+ String deviceId = UUID.randomUUID().toString();
+ when(mMockStorage.getActiveUserAssociatedDeviceIds()).thenReturn(
+ Collections.singletonList(deviceId));
+ mConnectedDeviceManager.addConnectedDevice(deviceId, carBleManager);
+ return deviceId;
+ }
+
+ @NonNull
+ private ConnectionCallback createConnectionCallback(@NonNull final Semaphore semaphore) {
+ return spy(new ConnectionCallback() {
+ @Override
+ public void onDeviceConnected(ConnectedDevice device) {
+ semaphore.release();
+ }
+
+ @Override
+ public void onDeviceDisconnected(ConnectedDevice device) {
+ semaphore.release();
+ }
+ });
+ }
+
+ @NonNull
+ private DeviceCallback createDeviceCallback(@NonNull final Semaphore semaphore) {
+ return spy(new DeviceCallback() {
+ @Override
+ public void onSecureChannelEstablished(ConnectedDevice device) {
+ semaphore.release();
+ }
+
+ @Override
+ public void onMessageReceived(ConnectedDevice device, byte[] message) {
+ semaphore.release();
+ }
+
+ @Override
+ public void onDeviceError(ConnectedDevice device, int error) {
+ semaphore.release();
+ }
+ });
+ }
+
+ @NonNull
+ private DeviceAssociationCallback createDeviceAssociationCallback(
+ @NonNull final Semaphore semaphore) {
+ return spy(new DeviceAssociationCallback() {
+ @Override
+ public void onAssociatedDeviceAdded(String deviceId) {
+ semaphore.release();
+ }
+
+ @Override
+ public void onAssociatedDeviceRemoved(String deviceId) {
+ semaphore.release();
+ }
+
+ @Override
+ public void onAssociatedDeviceUpdated(AssociatedDevice device) {
+ semaphore.release();
+ }
+ });
+ }
+}
diff --git a/connected-device-lib/tests/unit/src/com/android/car/connecteddevice/ble/BleDeviceMessageStreamTest.java b/connected-device-lib/tests/unit/src/com/android/car/connecteddevice/ble/BleDeviceMessageStreamTest.java
new file mode 100644
index 0000000..b45b6f2
--- /dev/null
+++ b/connected-device-lib/tests/unit/src/com/android/car/connecteddevice/ble/BleDeviceMessageStreamTest.java
@@ -0,0 +1,199 @@
+/*
+ * 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.connecteddevice.ble;
+
+import static com.android.car.connecteddevice.BleStreamProtos.BleDeviceMessageProto.BleDeviceMessage;
+import static com.android.car.connecteddevice.BleStreamProtos.BleOperationProto.OperationType;
+import static com.android.car.connecteddevice.BleStreamProtos.BlePacketProto.BlePacket;
+import static com.android.car.connecteddevice.ble.BleDeviceMessageStream.MessageReceivedListener;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mockitoSession;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.annotation.NonNull;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothGattCharacteristic;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.car.connecteddevice.util.ByteUtils;
+import com.android.car.protobuf.ByteString;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+public class BleDeviceMessageStreamTest {
+
+ private static final String TAG = "BleDeviceMessageStreamTest";
+
+ private BleDeviceMessageStream mStream;
+
+ @Mock
+ private BlePeripheralManager mMockBlePeripheralManager;
+
+ @Mock
+ private BluetoothDevice mMockBluetoothDevice;
+
+ @Mock
+ private BluetoothGattCharacteristic mMockWriteCharacteristic;
+
+ @Mock
+ private BluetoothGattCharacteristic mMockReadCharacteristic;
+
+ private MockitoSession mMockingSession;
+
+ @Before
+ public void setup() {
+ mMockingSession = mockitoSession()
+ .initMocks(this)
+ .strictness(Strictness.LENIENT)
+ .startMocking();
+
+ mStream = new BleDeviceMessageStream(mMockBlePeripheralManager, mMockBluetoothDevice,
+ mMockWriteCharacteristic, mMockReadCharacteristic);
+ }
+
+ @After
+ public void cleanup() {
+ if (mMockingSession != null) {
+ mMockingSession.finishMocking();
+ }
+ }
+
+ @Test
+ public void processPacket_notifiesWithEntireMessageForSinglePacketMessage()
+ throws InterruptedException {
+ Semaphore semaphore = new Semaphore(0);
+ MessageReceivedListener listener = createMessageReceivedListener(semaphore);
+ mStream.setMessageReceivedListener(listener);
+ byte[] data = ByteUtils.randomBytes(5);
+ processMessage(data);
+ assertThat(tryAcquire(semaphore)).isTrue();
+ ArgumentCaptor<DeviceMessage> messageCaptor = ArgumentCaptor.forClass(DeviceMessage.class);
+ verify(listener).onMessageReceived(messageCaptor.capture(), any());
+ }
+
+ @Test
+ public void processPacket_notifiesWithEntireMessageForMultiPacketMessage()
+ throws InterruptedException {
+ Semaphore semaphore = new Semaphore(0);
+ MessageReceivedListener listener = createMessageReceivedListener(semaphore);
+ mStream.setMessageReceivedListener(listener);
+ byte[] data = ByteUtils.randomBytes(750);
+ processMessage(data);
+ assertThat(tryAcquire(semaphore)).isTrue();
+ ArgumentCaptor<DeviceMessage> messageCaptor = ArgumentCaptor.forClass(DeviceMessage.class);
+ verify(listener).onMessageReceived(messageCaptor.capture(), any());
+ assertThat(Arrays.equals(data, messageCaptor.getValue().getMessage())).isTrue();
+ }
+
+ @Test
+ public void processPacket_receivingMultipleMessagesInParallelParsesSuccessfully()
+ throws InterruptedException {
+ Semaphore semaphore = new Semaphore(0);
+ MessageReceivedListener listener = createMessageReceivedListener(semaphore);
+ mStream.setMessageReceivedListener(listener);
+ byte[] data = ByteUtils.randomBytes(750);
+ List<BlePacket> packets1 = createPackets(data);
+ List<BlePacket> packets2 = createPackets(data);
+
+ for (int i = 0; i < packets1.size(); i++) {
+ mStream.processPacket(packets1.get(i));
+ if (i == packets1.size() - 1) {
+ break;
+ }
+ mStream.processPacket(packets2.get(i));
+ }
+ assertThat(tryAcquire(semaphore)).isTrue();
+ ArgumentCaptor<DeviceMessage> messageCaptor = ArgumentCaptor.forClass(DeviceMessage.class);
+ verify(listener).onMessageReceived(messageCaptor.capture(), any());
+ assertThat(Arrays.equals(data, messageCaptor.getValue().getMessage())).isTrue();
+
+ semaphore = new Semaphore(0);
+ listener = createMessageReceivedListener(semaphore);
+ mStream.setMessageReceivedListener(listener);
+ mStream.processPacket(packets2.get(packets2.size() - 1));
+ verify(listener).onMessageReceived(messageCaptor.capture(), any());
+ assertThat(Arrays.equals(data, messageCaptor.getValue().getMessage())).isTrue();
+ }
+
+ @Test
+ public void processPacket_doesNotNotifyOfNewMessageIfNotAllPacketsReceived()
+ throws InterruptedException {
+ Semaphore semaphore = new Semaphore(0);
+ MessageReceivedListener listener = createMessageReceivedListener(semaphore);
+ mStream.setMessageReceivedListener(listener);
+ byte[] data = ByteUtils.randomBytes(750);
+ List<BlePacket> packets = createPackets(data);
+ for (int i = 0; i < packets.size() - 1; i++) {
+ mStream.processPacket(packets.get(i));
+ }
+ assertThat(tryAcquire(semaphore)).isFalse();
+ }
+
+ @NonNull
+ private List<BlePacket> createPackets(byte[] data) {
+ try {
+ BleDeviceMessage message = BleDeviceMessage.newBuilder()
+ .setPayload(ByteString.copyFrom(data))
+ .setOperation(OperationType.CLIENT_MESSAGE)
+ .build();
+ return BlePacketFactory.makeBlePackets(message.toByteArray(),
+ ThreadLocalRandom.current().nextInt(), 500);
+ } catch (Exception e) {
+ assertWithMessage("Uncaught exception while making packets.").fail();
+ return new ArrayList<>();
+ }
+ }
+
+ private void processMessage(byte[] data) {
+ List<BlePacket> packets = createPackets(data);
+ for (BlePacket packet : packets) {
+ mStream.processPacket(packet);
+ }
+ }
+
+ private boolean tryAcquire(Semaphore semaphore) throws InterruptedException {
+ return semaphore.tryAcquire(100, TimeUnit.MILLISECONDS);
+ }
+
+ @NonNull
+ private MessageReceivedListener createMessageReceivedListener(
+ Semaphore semaphore) {
+ return spy((deviceMessage, operationType) -> semaphore.release());
+ }
+
+}
diff --git a/connected-device-lib/tests/unit/src/com/android/car/connecteddevice/ble/BlePacketFactoryTest.java b/connected-device-lib/tests/unit/src/com/android/car/connecteddevice/ble/BlePacketFactoryTest.java
new file mode 100644
index 0000000..8e8682f
--- /dev/null
+++ b/connected-device-lib/tests/unit/src/com/android/car/connecteddevice/ble/BlePacketFactoryTest.java
@@ -0,0 +1,170 @@
+/*
+ * 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.car.connecteddevice.ble;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.car.connecteddevice.BleStreamProtos.BlePacketProto.BlePacket;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.ByteArrayOutputStream;
+import java.util.List;
+import java.util.Random;
+
+@RunWith(AndroidJUnit4.class)
+public class BlePacketFactoryTest {
+ @Test
+ public void testGetHeaderSize() {
+ // 1 byte to encode the ID, 1 byte for the field number.
+ int messageId = 1;
+ int messageIdEncodingSize = 2;
+
+ // 1 byte for the payload size, 1 byte for the field number.
+ int payloadSize = 2;
+ int payloadSizeEncodingSize = 2;
+
+ // 1 byte for total packets, 1 byte for field number.
+ int totalPackets = 5;
+ int totalPacketsEncodingSize = 2;
+
+ // Packet number if a fixed32, so 4 bytes + 1 byte for field number.
+ int packetNumberEncodingSize = 5;
+
+ int expectedHeaderSize = messageIdEncodingSize + payloadSizeEncodingSize
+ + totalPacketsEncodingSize + packetNumberEncodingSize;
+
+ assertThat(BlePacketFactory.getPacketHeaderSize(totalPackets, messageId, payloadSize))
+ .isEqualTo(expectedHeaderSize);
+ }
+
+ @Test
+ public void testGetTotalPackets_withVarintSize1_returnsCorrectPackets()
+ throws BlePacketFactoryException {
+ int messageId = 1;
+ int maxSize = 49;
+ int payloadSize = 100;
+
+ // This leaves us 40 bytes to use for the payload and its encoding size. Assuming a varint
+ // of size 1 means it takes 2 bytes to encode its value. This leaves 38 bytes for the
+ // payload. ceil(payloadSize/38) gives the total packets.
+ int expectedTotalPackets = 3;
+
+ assertThat(BlePacketFactory.getTotalPacketNumber(messageId, payloadSize, maxSize))
+ .isEqualTo(expectedTotalPackets);
+ }
+
+ @Test
+ public void testGetTotalPackets_withVarintSize2_returnsCorrectPackets()
+ throws BlePacketFactoryException {
+ int messageId = 1;
+ int maxSize = 49;
+ int payloadSize = 6000;
+
+ // This leaves us 40 bytes to use for the payload and its encoding size. Assuming a varint
+ // of size 2 means it takes 3 bytes to encode its value. This leaves 37 bytes for the
+ // payload. ceil(payloadSize/37) gives the total packets.
+ int expectedTotalPackets = 163;
+
+ assertThat(BlePacketFactory.getTotalPacketNumber(messageId, payloadSize, maxSize))
+ .isEqualTo(expectedTotalPackets);
+ }
+
+ @Test
+ public void testGetTotalPackets_withVarintSize3_returnsCorrectPackets()
+ throws BlePacketFactoryException {
+ int messageId = 1;
+ int maxSize = 49;
+ int payloadSize = 1000000;
+
+ // This leaves us 40 bytes to use for the payload and its encoding size. Assuming a varint
+ // of size 3 means it takes 4 bytes to encode its value. This leaves 36 bytes for the
+ // payload. ceil(payloadSize/36) gives the total packets.
+ int expectedTotalPackets = 27778;
+
+ assertThat(BlePacketFactory.getTotalPacketNumber(messageId, payloadSize, maxSize))
+ .isEqualTo(expectedTotalPackets);
+ }
+
+ @Test
+ public void testGetTotalPackets_withVarintSize4_returnsCorrectPackets()
+ throws BlePacketFactoryException {
+ int messageId = 1;
+ int maxSize = 49;
+ int payloadSize = 178400320;
+
+ // This leaves us 40 bytes to use for the payload and its encoding size. Assuming a varint
+ // of size 4 means it takes 5 bytes to encode its value. This leaves 35 bytes for the
+ // payload. ceil(payloadSize/35) gives the total packets.
+ int expectedTotalPackets = 5097152;
+
+ assertThat(BlePacketFactory.getTotalPacketNumber(messageId, payloadSize, maxSize))
+ .isEqualTo(expectedTotalPackets);
+ }
+
+ @Test
+ public void testMakePackets_correctlyChunksPayload() throws Exception {
+ // Payload of size 100, but maxSize of 1000 to ensure it fits.
+ byte[] payload = makePayload(/* length= */ 100);
+ int maxSize = 1000;
+
+ List<BlePacket> packets =
+ BlePacketFactory.makeBlePackets(payload, /* mesageId= */ 1, maxSize);
+
+ assertThat(packets).hasSize(1);
+
+ ByteArrayOutputStream reconstructedPayload = new ByteArrayOutputStream();
+
+ // Combine together all the payloads within the BlePackets.
+ for (BlePacket packet : packets) {
+ reconstructedPayload.write(packet.getPayload().toByteArray());
+ }
+
+ assertThat(reconstructedPayload.toByteArray()).isEqualTo(payload);
+ }
+
+ @Test
+ public void testMakePackets_correctlyChunksSplitPayload() throws Exception {
+ // Payload size of 10000 but max size of 50 to ensure the payload is split.
+ byte[] payload = makePayload(/* length= */ 10000);
+ int maxSize = 50;
+
+ List<BlePacket> packets =
+ BlePacketFactory.makeBlePackets(payload, /* mesageId= */ 1, maxSize);
+
+ assertThat(packets.size()).isGreaterThan(1);
+
+ ByteArrayOutputStream reconstructedPayload = new ByteArrayOutputStream();
+
+ // Combine together all the payloads within the BlePackets.
+ for (BlePacket packet : packets) {
+ reconstructedPayload.write(packet.getPayload().toByteArray());
+ }
+
+ assertThat(reconstructedPayload.toByteArray()).isEqualTo(payload);
+ }
+
+ /** Creates a byte array of the given length, populated with random bytes. */
+ private byte[] makePayload(int length) {
+ byte[] payload = new byte[length];
+ new Random().nextBytes(payload);
+ return payload;
+ }
+}
diff --git a/connected-device-lib/tests/unit/src/com/android/car/connecteddevice/ble/CarBlePeripheralManagerTest.java b/connected-device-lib/tests/unit/src/com/android/car/connecteddevice/ble/CarBlePeripheralManagerTest.java
new file mode 100644
index 0000000..adba67b
--- /dev/null
+++ b/connected-device-lib/tests/unit/src/com/android/car/connecteddevice/ble/CarBlePeripheralManagerTest.java
@@ -0,0 +1,253 @@
+/*
+ * 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.car.connecteddevice.ble;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mockitoSession;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+
+import android.annotation.NonNull;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.le.AdvertiseCallback;
+import android.bluetooth.le.AdvertiseData;
+import android.bluetooth.le.AdvertiseSettings;
+import android.car.encryptionrunner.EncryptionRunnerFactory;
+import android.car.encryptionrunner.Key;
+import android.os.ParcelUuid;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.car.connecteddevice.AssociationCallback;
+import com.android.car.connecteddevice.model.AssociatedDevice;
+import com.android.car.connecteddevice.storage.ConnectedDeviceStorage;
+import com.android.car.connecteddevice.util.ByteUtils;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
+
+import java.util.UUID;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+public class CarBlePeripheralManagerTest {
+ private static final UUID ASSOCIATION_SERVICE_UUID = UUID.randomUUID();
+ private static final UUID WRITE_UUID = UUID.randomUUID();
+ private static final UUID READ_UUID = UUID.randomUUID();
+ private static final int DEVICE_NAME_LENGTH_LIMIT = 8;
+ private static final String TEST_REMOTE_DEVICE_ADDRESS = "00:11:22:33:AA:BB";
+ private static final UUID TEST_REMOTE_DEVICE_ID = UUID.randomUUID();
+ private static final String TEST_VERIFICATION_CODE = "000000";
+ private static final byte[] TEST_KEY = "Key".getBytes();
+ private static String sAdapterName;
+
+ @Mock private BlePeripheralManager mMockPeripheralManager;
+ @Mock private ConnectedDeviceStorage mMockStorage;
+
+ private CarBlePeripheralManager mCarBlePeripheralManager;
+
+ private MockitoSession mMockitoSession;
+
+ @BeforeClass
+ public static void beforeSetUp() {
+ sAdapterName = BluetoothAdapter.getDefaultAdapter().getName();
+ }
+ @Before
+ public void setUp() {
+ mMockitoSession = mockitoSession()
+ .initMocks(this)
+ .strictness(Strictness.LENIENT)
+ .startMocking();
+ mCarBlePeripheralManager = new CarBlePeripheralManager(mMockPeripheralManager, mMockStorage,
+ ASSOCIATION_SERVICE_UUID, WRITE_UUID, READ_UUID);
+ }
+
+ @After
+ public void tearDown() {
+ mCarBlePeripheralManager.stop();
+ if (mMockitoSession != null) {
+ mMockitoSession.finishMocking();
+ }
+ }
+
+ @AfterClass
+ public static void afterTearDown() {
+ BluetoothAdapter.getDefaultAdapter().setName(sAdapterName);
+ }
+
+ @Test
+ public void testStartAssociationAdvertisingSuccess() {
+ Semaphore semaphore = new Semaphore(0);
+ AssociationCallback callback = createAssociationCallback(semaphore);
+ String testDeviceName = getNameForAssociation();
+ startAssociation(callback, testDeviceName);
+ ArgumentCaptor<AdvertiseData> dataCaptor = ArgumentCaptor.forClass(AdvertiseData.class);
+ verify(mMockPeripheralManager, timeout(3000)).startAdvertising(any(),
+ dataCaptor.capture(), any());
+ AdvertiseData data = dataCaptor.getValue();
+ assertThat(data.getIncludeDeviceName()).isTrue();
+ ParcelUuid expected = new ParcelUuid(ASSOCIATION_SERVICE_UUID);
+ assertThat(data.getServiceUuids().get(0)).isEqualTo(expected);
+ assertThat(BluetoothAdapter.getDefaultAdapter().getName()).isEqualTo(testDeviceName);
+ }
+
+ @Test
+ public void testStartAssociationAdvertisingFailure() throws InterruptedException {
+ Semaphore semaphore = new Semaphore(0);
+ AssociationCallback callback = createAssociationCallback(semaphore);
+ startAssociation(callback, getNameForAssociation());
+ ArgumentCaptor<AdvertiseCallback> callbackCaptor =
+ ArgumentCaptor.forClass(AdvertiseCallback.class);
+ verify(mMockPeripheralManager, timeout(3000))
+ .startAdvertising(any(), any(), callbackCaptor.capture());
+ AdvertiseCallback advertiseCallback = callbackCaptor.getValue();
+ int testErrorCode = 2;
+ advertiseCallback.onStartFailure(testErrorCode);
+ assertThat(tryAcquire(semaphore)).isTrue();
+ verify(callback).onAssociationStartFailure();
+ }
+
+ @Test
+ public void testNotifyAssociationSuccess() throws InterruptedException {
+ Semaphore semaphore = new Semaphore(0);
+ AssociationCallback callback = createAssociationCallback(semaphore);
+ String testDeviceName = getNameForAssociation();
+ startAssociation(callback, testDeviceName);
+ ArgumentCaptor<AdvertiseCallback> callbackCaptor =
+ ArgumentCaptor.forClass(AdvertiseCallback.class);
+ verify(mMockPeripheralManager, timeout(3000))
+ .startAdvertising(any(), any(), callbackCaptor.capture());
+ AdvertiseCallback advertiseCallback = callbackCaptor.getValue();
+ AdvertiseSettings settings = new AdvertiseSettings.Builder().build();
+ advertiseCallback.onStartSuccess(settings);
+ assertThat(tryAcquire(semaphore)).isTrue();
+ verify(callback).onAssociationStartSuccess(eq(testDeviceName));
+ }
+
+ @Test
+ public void testShowVerificationCode() throws InterruptedException {
+ Semaphore semaphore = new Semaphore(0);
+ AssociationCallback callback = createAssociationCallback(semaphore);
+ SecureBleChannel channel = getChannelForAssociation(callback);
+ channel.getShowVerificationCodeListener().showVerificationCode(TEST_VERIFICATION_CODE);
+ assertThat(tryAcquire(semaphore)).isTrue();
+ verify(callback).onVerificationCodeAvailable(eq(TEST_VERIFICATION_CODE));
+ }
+
+ @Test
+ public void testAssociationSuccess() throws InterruptedException {
+ Semaphore semaphore = new Semaphore(0);
+ AssociationCallback callback = createAssociationCallback(semaphore);
+ SecureBleChannel channel = getChannelForAssociation(callback);
+ SecureBleChannel.Callback channelCallback = channel.getCallback();
+ assertThat(channelCallback).isNotNull();
+ channelCallback.onDeviceIdReceived(TEST_REMOTE_DEVICE_ID.toString());
+ Key key = EncryptionRunnerFactory.newDummyRunner().keyOf(TEST_KEY);
+ channelCallback.onSecureChannelEstablished();
+ ArgumentCaptor<AssociatedDevice> deviceCaptor =
+ ArgumentCaptor.forClass(AssociatedDevice.class);
+ verify(mMockStorage).addAssociatedDeviceForActiveUser(deviceCaptor.capture());
+ AssociatedDevice device = deviceCaptor.getValue();
+ assertThat(device.getDeviceId()).isEqualTo(TEST_REMOTE_DEVICE_ID.toString());
+ assertThat(tryAcquire(semaphore)).isTrue();
+ verify(callback).onAssociationCompleted(eq(TEST_REMOTE_DEVICE_ID.toString()));
+ }
+
+ @Test
+ public void testAssociationFailure_channelError() throws InterruptedException {
+ Semaphore semaphore = new Semaphore(0);
+ AssociationCallback callback = createAssociationCallback(semaphore);
+ SecureBleChannel channel = getChannelForAssociation(callback);
+ SecureBleChannel.Callback channelCallback = channel.getCallback();
+ int testErrorCode = 1;
+ assertThat(channelCallback).isNotNull();
+ channelCallback.onDeviceIdReceived(TEST_REMOTE_DEVICE_ID.toString());
+ channelCallback.onEstablishSecureChannelFailure(testErrorCode);
+ assertThat(tryAcquire(semaphore)).isTrue();
+ verify(callback).onAssociationError(eq(testErrorCode));
+ }
+
+ private BlePeripheralManager.Callback startAssociation(AssociationCallback callback,
+ String deviceName) {
+ ArgumentCaptor<BlePeripheralManager.Callback> callbackCaptor =
+ ArgumentCaptor.forClass(BlePeripheralManager.Callback.class);
+ mCarBlePeripheralManager.startAssociation(deviceName, callback);
+ verify(mMockPeripheralManager, timeout(3000)).registerCallback(callbackCaptor.capture());
+ return callbackCaptor.getValue();
+ }
+
+ private SecureBleChannel getChannelForAssociation(AssociationCallback callback) {
+ BlePeripheralManager.Callback bleManagerCallback = startAssociation(callback,
+ getNameForAssociation());
+ BluetoothDevice bluetoothDevice = BluetoothAdapter.getDefaultAdapter()
+ .getRemoteDevice(TEST_REMOTE_DEVICE_ADDRESS);
+ bleManagerCallback.onRemoteDeviceConnected(bluetoothDevice);
+ return mCarBlePeripheralManager.getConnectedDeviceChannel();
+ }
+
+ private boolean tryAcquire(Semaphore semaphore) throws InterruptedException {
+ return semaphore.tryAcquire(100, TimeUnit.MILLISECONDS);
+ }
+
+ private String getNameForAssociation() {
+ return ByteUtils.generateRandomNumberString(DEVICE_NAME_LENGTH_LIMIT);
+
+ }
+
+ @NonNull
+ private AssociationCallback createAssociationCallback(@NonNull final Semaphore semaphore) {
+ return spy(new AssociationCallback() {
+ @Override
+ public void onAssociationStartSuccess(String deviceName) {
+ semaphore.release();
+ }
+ @Override
+ public void onAssociationStartFailure() {
+ semaphore.release();
+ }
+
+ @Override
+ public void onAssociationError(int error) {
+ semaphore.release();
+ }
+
+ @Override
+ public void onVerificationCodeAvailable(String code) {
+ semaphore.release();
+ }
+
+ @Override
+ public void onAssociationCompleted(String deviceId) {
+ semaphore.release();
+ }
+ });
+ }
+}
diff --git a/connected-device-lib/tests/unit/src/com/android/car/connecteddevice/ble/SecureBleChannelTest.java b/connected-device-lib/tests/unit/src/com/android/car/connecteddevice/ble/SecureBleChannelTest.java
new file mode 100644
index 0000000..2960e49
--- /dev/null
+++ b/connected-device-lib/tests/unit/src/com/android/car/connecteddevice/ble/SecureBleChannelTest.java
@@ -0,0 +1,221 @@
+/*
+ * 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.car.connecteddevice.ble;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.car.encryptionrunner.DummyEncryptionRunner;
+import android.car.encryptionrunner.EncryptionRunnerFactory;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.car.connecteddevice.BleStreamProtos.BleOperationProto.OperationType;
+import com.android.car.connecteddevice.ble.BleDeviceMessageStream.MessageReceivedListener;
+import com.android.car.connecteddevice.storage.ConnectedDeviceStorage;
+import com.android.car.connecteddevice.util.ByteUtils;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.UUID;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+public final class SecureBleChannelTest {
+ private static final UUID CLIENT_DEVICE_ID =
+ UUID.fromString("a5645523-3280-410a-90c1-582a6c6f4969");
+ private static final UUID SERVER_DEVICE_ID =
+ UUID.fromString("a29f0c74-2014-4b14-ac02-be6ed15b545a");
+
+ private SecureBleChannel mChannel;
+ private MessageReceivedListener mMessageReceivedListener;
+
+ @Mock private BleDeviceMessageStream mStreamMock;
+ @Mock private ConnectedDeviceStorage mStorageMock;
+ @Mock private SecureBleChannel.ShowVerificationCodeListener mShowVerificationCodeListenerMock;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ when(mStorageMock.getUniqueId()).thenReturn(SERVER_DEVICE_ID);
+ }
+
+ @Test
+ public void testEncryptionHandshake_Association() throws InterruptedException {
+ Semaphore semaphore = new Semaphore(0);
+ ChannelCallback callbackSpy = spy(new ChannelCallback(semaphore));
+ setUpSecureBleChannel_Association(callbackSpy);
+ ArgumentCaptor<String> deviceIdCaptor = ArgumentCaptor.forClass(String.class);
+ ArgumentCaptor<DeviceMessage> messageCaptor =
+ ArgumentCaptor.forClass(DeviceMessage.class);
+
+ sendDeviceId();
+ assertThat(semaphore.tryAcquire(100, TimeUnit.MILLISECONDS)).isTrue();
+ verify(callbackSpy).onDeviceIdReceived(deviceIdCaptor.capture());
+ verify(mStreamMock).writeMessage(messageCaptor.capture(), any());
+ byte[] deviceIdMessage = messageCaptor.getValue().getMessage();
+ assertThat(deviceIdMessage).isEqualTo(ByteUtils.uuidToBytes(SERVER_DEVICE_ID));
+ assertThat(deviceIdCaptor.getValue()).isEqualTo(CLIENT_DEVICE_ID.toString());
+
+ initHandshakeMessage();
+ verify(mStreamMock, times(2)).writeMessage(messageCaptor.capture(), any());
+ byte[] response = messageCaptor.getValue().getMessage();
+ assertThat(response).isEqualTo(DummyEncryptionRunner.INIT_RESPONSE.getBytes());
+
+ respondToContinueMessage();
+ verify(mShowVerificationCodeListenerMock).showVerificationCode(anyString());
+
+ mChannel.notifyOutOfBandAccepted();
+ verify(mStreamMock, times(3)).writeMessage(messageCaptor.capture(), any());
+ byte[] confirmMessage = messageCaptor.getValue().getMessage();
+ assertThat(confirmMessage).isEqualTo(SecureBleChannel.CONFIRMATION_SIGNAL);
+ assertThat(semaphore.tryAcquire(100, TimeUnit.MILLISECONDS)).isTrue();
+ verify(callbackSpy).onSecureChannelEstablished();
+ }
+
+ @Test
+ public void testEncryptionHandshake_Association_wrongInitHandshakeMessage()
+ throws InterruptedException {
+ Semaphore semaphore = new Semaphore(0);
+ ChannelCallback callbackSpy = spy(new ChannelCallback(semaphore));
+ setUpSecureBleChannel_Association(callbackSpy);
+
+ sendDeviceId();
+ assertThat(semaphore.tryAcquire(100, TimeUnit.MILLISECONDS)).isTrue();
+
+ // Wrong init handshake message
+ respondToContinueMessage();
+ assertThat(semaphore.tryAcquire(100, TimeUnit.MILLISECONDS)).isTrue();
+ verify(callbackSpy).onEstablishSecureChannelFailure(
+ eq(SecureBleChannel.CHANNEL_ERROR_INVALID_HANDSHAKE)
+ );
+ }
+
+ @Test
+ public void testEncryptionHandshake_Association_wrongRespondToContinueMessage()
+ throws InterruptedException {
+ Semaphore semaphore = new Semaphore(0);
+ ChannelCallback callbackSpy = spy(new ChannelCallback(semaphore));
+ setUpSecureBleChannel_Association(callbackSpy);
+
+ sendDeviceId();
+ assertThat(semaphore.tryAcquire(100, TimeUnit.MILLISECONDS)).isTrue();
+
+ initHandshakeMessage();
+
+ // Wrong respond to continue message
+ initHandshakeMessage();
+ assertThat(semaphore.tryAcquire(100, TimeUnit.MILLISECONDS)).isTrue();
+ verify(callbackSpy).onEstablishSecureChannelFailure(
+ eq(SecureBleChannel.CHANNEL_ERROR_INVALID_HANDSHAKE)
+ );
+ }
+
+ private void setUpSecureBleChannel_Association(ChannelCallback callback) {
+ mChannel = new SecureBleChannel(
+ mStreamMock,
+ mStorageMock,
+ /* isReconnect = */ false,
+ EncryptionRunnerFactory.newDummyRunner()
+ );
+ mChannel.registerCallback(callback);
+ mChannel.setShowVerificationCodeListener(mShowVerificationCodeListenerMock);
+ ArgumentCaptor<MessageReceivedListener> listenerCaptor =
+ ArgumentCaptor.forClass(MessageReceivedListener.class);
+ verify(mStreamMock).setMessageReceivedListener(listenerCaptor.capture());
+ mMessageReceivedListener = listenerCaptor.getValue();
+ }
+
+ private void sendDeviceId() {
+ DeviceMessage message = new DeviceMessage(
+ /* recipient = */ null,
+ /* isMessageEncrypted = */ false,
+ ByteUtils.uuidToBytes(CLIENT_DEVICE_ID)
+ );
+ mMessageReceivedListener.onMessageReceived(message, OperationType.ENCRYPTION_HANDSHAKE);
+ }
+
+ private void initHandshakeMessage() {
+ DeviceMessage message = new DeviceMessage(
+ /* recipient = */ null,
+ /* isMessageEncrypted = */ false,
+ DummyEncryptionRunner.INIT.getBytes()
+ );
+ mMessageReceivedListener.onMessageReceived(message, OperationType.ENCRYPTION_HANDSHAKE);
+ }
+
+ private void respondToContinueMessage() {
+ DeviceMessage message = new DeviceMessage(
+ /* recipient = */ null,
+ /* isMessageEncrypted = */ false,
+ DummyEncryptionRunner.CLIENT_RESPONSE.getBytes()
+ );
+ mMessageReceivedListener.onMessageReceived(message, OperationType.ENCRYPTION_HANDSHAKE);
+ }
+
+ /**
+ * Add the thread control logic into {@link SecureBleChannel.Callback} only for spy purpose.
+ *
+ * <p>The callback will release the semaphore which hold by one test when this callback
+ * is called, telling the test that it can verify certain behaviors which will only occurred
+ * after the callback is notified. This is needed mainly because of the callback is notified
+ * in a different thread.
+ */
+ class ChannelCallback implements SecureBleChannel.Callback {
+ private final Semaphore mSemaphore;
+ ChannelCallback(Semaphore semaphore) {
+ mSemaphore = semaphore;
+ }
+ @Override
+ public void onSecureChannelEstablished() {
+ mSemaphore.release();
+ }
+
+ @Override
+ public void onEstablishSecureChannelFailure(int error) {
+ mSemaphore.release();
+ }
+
+ @Override
+ public void onMessageReceived(DeviceMessage deviceMessage) {
+ mSemaphore.release();
+ }
+
+ @Override
+ public void onMessageReceivedError(Exception exception) {
+ mSemaphore.release();
+ }
+
+ @Override
+ public void onDeviceIdReceived(String deviceId) {
+ mSemaphore.release();
+ }
+ }
+}
diff --git a/connected-device-lib/tests/unit/src/com/android/car/connecteddevice/storage/ConnectedDeviceStorageTest.java b/connected-device-lib/tests/unit/src/com/android/car/connecteddevice/storage/ConnectedDeviceStorageTest.java
new file mode 100644
index 0000000..964f59b
--- /dev/null
+++ b/connected-device-lib/tests/unit/src/com/android/car/connecteddevice/storage/ConnectedDeviceStorageTest.java
@@ -0,0 +1,141 @@
+/*
+ * 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.car.connecteddevice.storage;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.util.Pair;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.car.connecteddevice.model.AssociatedDevice;
+import com.android.car.connecteddevice.util.ByteUtils;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+@RunWith(AndroidJUnit4.class)
+public final class ConnectedDeviceStorageTest {
+ private final Context mContext = ApplicationProvider.getApplicationContext();
+
+ private final int mActiveUserId = 10;
+
+ private ConnectedDeviceStorage mConnectedDeviceStorage;
+
+ private List<Pair<Integer, AssociatedDevice>> mAddedAssociatedDevices;
+
+ @Before
+ public void setUp() {
+ mConnectedDeviceStorage = new ConnectedDeviceStorage(mContext);
+ mAddedAssociatedDevices = new ArrayList<>();
+ }
+
+ @After
+ public void tearDown() {
+ // Clear any associated devices added during tests.
+ for (Pair<Integer, AssociatedDevice> device : mAddedAssociatedDevices) {
+ mConnectedDeviceStorage.removeAssociatedDevice(device.first,
+ device.second.getDeviceId());
+ }
+ }
+
+ @Test
+ public void getAssociatedDeviceIdsForUser_includesNewlyAddedDevice() {
+ AssociatedDevice addedDevice = addRandomAssociatedDevice(mActiveUserId);
+ List<String> associatedDevices =
+ mConnectedDeviceStorage.getAssociatedDeviceIdsForUser(mActiveUserId);
+ assertThat(associatedDevices).containsExactly(addedDevice.getDeviceId());
+ }
+
+ @Test
+ public void getAssociatedDeviceIdsForUser_excludesDeviceAddedForOtherUser() {
+ addRandomAssociatedDevice(mActiveUserId);
+ List<String> associatedDevices =
+ mConnectedDeviceStorage.getAssociatedDeviceIdsForUser(mActiveUserId + 1);
+ assertThat(associatedDevices).isEmpty();
+ }
+
+ @Test
+ public void getAssociatedDeviceIdsForUser_excludesRemovedDevice() {
+ AssociatedDevice addedDevice = addRandomAssociatedDevice(mActiveUserId);
+ mConnectedDeviceStorage.removeAssociatedDevice(mActiveUserId, addedDevice.getDeviceId());
+ List<String> associatedDevices =
+ mConnectedDeviceStorage.getAssociatedDeviceIdsForUser(mActiveUserId);
+ assertThat(associatedDevices).isEmpty();
+ }
+
+ @Test
+ public void getAssociatedDevicesForUser_includesNewlyAddedDevice() {
+ AssociatedDevice addedDevice = addRandomAssociatedDevice(mActiveUserId);
+ List<AssociatedDevice> associatedDevices =
+ mConnectedDeviceStorage.getAssociatedDevicesForUser(mActiveUserId);
+ assertThat(associatedDevices).containsExactly(addedDevice);
+ }
+
+ @Test
+ public void getAssociatedDevicesForUser_excludesDeviceAddedForOtherUser() {
+ addRandomAssociatedDevice(mActiveUserId);
+ List<String> associatedDevices =
+ mConnectedDeviceStorage.getAssociatedDeviceIdsForUser(mActiveUserId + 1);
+ assertThat(associatedDevices).isEmpty();
+ }
+
+ @Test
+ public void getAssociatedDevicesForUser_excludesRemovedDevice() {
+ AssociatedDevice addedDevice = addRandomAssociatedDevice(mActiveUserId);
+ mConnectedDeviceStorage.removeAssociatedDevice(mActiveUserId, addedDevice.getDeviceId());
+ List<AssociatedDevice> associatedDevices =
+ mConnectedDeviceStorage.getAssociatedDevicesForUser(mActiveUserId);
+ assertThat(associatedDevices).isEmpty();
+ }
+
+ @Test
+ public void getEncryptionKey_returnsSavedKey() {
+ String deviceId = addRandomAssociatedDevice(mActiveUserId).getDeviceId();
+ byte[] key = ByteUtils.randomBytes(16);
+ mConnectedDeviceStorage.saveEncryptionKey(deviceId, key);
+ assertThat(mConnectedDeviceStorage.getEncryptionKey(deviceId)).isEqualTo(key);
+ }
+
+ @Test
+ public void getEncryptionKey_returnsNullForUnrecognizedDeviceId() {
+ String deviceId = addRandomAssociatedDevice(mActiveUserId).getDeviceId();
+ mConnectedDeviceStorage.saveEncryptionKey(deviceId, ByteUtils.randomBytes(16));
+ assertThat(mConnectedDeviceStorage.getEncryptionKey(UUID.randomUUID().toString())).isNull();
+ }
+
+ private AssociatedDevice addRandomAssociatedDevice(int userId) {
+ AssociatedDevice device = new AssociatedDevice(UUID.randomUUID().toString(),
+ "00:00:00:00:00:00", "Test Device");
+ addAssociatedDevice(userId, device, ByteUtils.randomBytes(16));
+ return device;
+ }
+
+ private void addAssociatedDevice(int userId, AssociatedDevice device, byte[] encryptionKey) {
+ mConnectedDeviceStorage.addAssociatedDeviceForUser(userId, device);
+ mConnectedDeviceStorage.saveEncryptionKey(device.getDeviceId(), encryptionKey);
+ mAddedAssociatedDevices.add(new Pair<>(userId, device));
+ }
+}
diff --git a/connected-device-lib/tests/unit/src/com/android/car/connecteddevice/util/ScanDataAnalyzerTest.java b/connected-device-lib/tests/unit/src/com/android/car/connecteddevice/util/ScanDataAnalyzerTest.java
new file mode 100644
index 0000000..92e8d34
--- /dev/null
+++ b/connected-device-lib/tests/unit/src/com/android/car/connecteddevice/util/ScanDataAnalyzerTest.java
@@ -0,0 +1,108 @@
+/*
+ * 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.car.connecteddevice.util;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.math.BigInteger;
+
+@RunWith(AndroidJUnit4.class)
+public class ScanDataAnalyzerTest {
+ private static final BigInteger CORRECT_DATA =
+ new BigInteger(
+ "02011A14FF4C000100000000000000000000000000200000000000000000000000000000"
+ + "0000000000000000000000000000000000000000000000000000",
+ 16);
+
+ private static final BigInteger CORRECT_MASK =
+ new BigInteger("00000000000000000000000000200000", 16);
+
+ private static final BigInteger MULTIPLE_BIT_MASK =
+ new BigInteger("00000000000000000100000000200000", 16);
+
+ @Test
+ public void containsUuidsInOverflow_correctBitFlipped_shouldReturnTrue() {
+ assertThat(
+ ScanDataAnalyzer.containsUuidsInOverflow(CORRECT_DATA.toByteArray(), CORRECT_MASK))
+ .isTrue();
+ }
+
+ @Test
+ public void containsUuidsInOverflow_bitNotFlipped_shouldReturnFalse() {
+ assertThat(
+ ScanDataAnalyzer.containsUuidsInOverflow(
+ CORRECT_DATA.negate().toByteArray(), CORRECT_MASK))
+ .isFalse();
+ }
+
+ @Test
+ public void containsUuidsInOverflow_maskWithMultipleBitsIncompleteMatch_shouldReturnTrue() {
+ assertThat(
+ ScanDataAnalyzer.containsUuidsInOverflow(CORRECT_DATA.toByteArray(),
+ MULTIPLE_BIT_MASK))
+ .isTrue();
+ }
+
+ @Test
+ public void containsUuidsInOverflow_incorrectLengthByte_shouldReturnFalse() {
+ // Incorrect length of 0x20
+ byte[] data =
+ new BigInteger(
+ "02011A20FF4C00010000000000000000000000000020000000000000000000000000000000"
+ + "00000000000000000000000000000000000000000000000000",
+ 16)
+ .toByteArray();
+ BigInteger mask = new BigInteger("00000000000000000000000000200000", 16);
+ assertThat(ScanDataAnalyzer.containsUuidsInOverflow(data, mask)).isFalse();
+ }
+
+ @Test
+ public void containsUuidsInOverflow_incorrectAdTypeByte_shouldReturnFalse() {
+ // Incorrect advertising type of 0xEF
+ byte[] data =
+ new BigInteger(
+ "02011A14EF4C00010000000000000000000000000020000000000000000000000000000000"
+ + "00000000000000000000000000000000000000000000000000",
+ 16)
+ .toByteArray();
+ assertThat(ScanDataAnalyzer.containsUuidsInOverflow(data, CORRECT_MASK)).isFalse();
+ }
+
+ @Test
+ public void containsUuidsInOverflow_incorrectCustomId_shouldReturnFalse() {
+ // Incorrect custom id of 0x4C1001
+ byte[] data =
+ new BigInteger(
+ "02011A14FF4C10010000000000000000000000000020000000000000000000000000000000"
+ + "00000000000000000000000000000000000000000000000000",
+ 16)
+ .toByteArray();
+ assertThat(ScanDataAnalyzer.containsUuidsInOverflow(data, CORRECT_MASK)).isFalse();
+ }
+
+ @Test
+ public void containsUuidsInOverflow_incorrectContentLength_shouldReturnFalse() {
+ byte[] data = new BigInteger("02011A14FF4C1001000000000000000000000000002", 16)
+ .toByteArray();
+ assertThat(ScanDataAnalyzer.containsUuidsInOverflow(data, CORRECT_MASK)).isFalse();
+ }
+}