Merge "Update UserRestriction defaults to use framework mechanisms"
diff --git a/FrameworkPackageStubs/AndroidManifest.xml b/FrameworkPackageStubs/AndroidManifest.xml
index e1ad903..c88ffdb 100644
--- a/FrameworkPackageStubs/AndroidManifest.xml
+++ b/FrameworkPackageStubs/AndroidManifest.xml
@@ -55,6 +55,15 @@
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="vnd.android.cursor.dir/audio"/>
</intent-filter>
+ <intent-filter android:priority="-1">
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <data android:scheme="content" />
+ <data android:scheme="file" />
+ <data android:mimeType="video/*" />
+ <data android:mimeType="image/*" />
+ </intent-filter>
</activity>
<!-- Settings package stubs -->
diff --git a/car-lib/api/current.txt b/car-lib/api/current.txt
index c1c0e63..bab3b88 100644
--- a/car-lib/api/current.txt
+++ b/car-lib/api/current.txt
@@ -533,7 +533,9 @@
package android.car.hardware.property {
public class CarPropertyManager {
+ method public int getAreaId(int, int);
method public boolean getBooleanProperty(int, int);
+ method @Nullable public android.car.hardware.CarPropertyConfig<?> getCarPropertyConfig(int);
method public float getFloatProperty(int, int);
method @NonNull public int[] getIntArrayProperty(int, int);
method public int getIntProperty(int, int);
diff --git a/car-lib/src/android/car/Car.java b/car-lib/src/android/car/Car.java
index f3fb100..3bf0f5d 100644
--- a/car-lib/src/android/car/Car.java
+++ b/car-lib/src/android/car/Car.java
@@ -61,6 +61,7 @@
import android.os.Looper;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.TransactionTooLargeException;
import android.os.UserHandle;
import android.util.Log;
@@ -1462,7 +1463,12 @@
/** @hide */
void handleRemoteExceptionFromCarService(RemoteException e) {
- Log.w(TAG_CAR, "Car service has crashed", e);
+ if (e instanceof TransactionTooLargeException) {
+ Log.w(TAG_CAR, "Car service threw TransactionTooLargeException", e);
+ throw new CarTransactionException(e, "Car service threw TransactionTooLargException");
+ } else {
+ Log.w(TAG_CAR, "Car service has crashed", e);
+ }
}
@@ -1498,10 +1504,18 @@
/** @hide */
public static void handleRemoteExceptionFromCarService(Service service, RemoteException e) {
- Log.w(TAG_CAR,
- "Car service has crashed, client:" + service.getPackageName() + ","
- + service.getClass().getSimpleName(), e);
- service.stopSelf();
+ if (e instanceof TransactionTooLargeException) {
+ Log.w(TAG_CAR, "Car service threw TransactionTooLargeException, client:"
+ + service.getPackageName() + ","
+ + service.getClass().getSimpleName(), e);
+ throw new CarTransactionException(e, "Car service threw TransactionTooLargeException, "
+ + "client: %s, %s", service.getPackageName(), service.getClass().getSimpleName());
+ } else {
+ Log.w(TAG_CAR, "Car service has crashed, client:"
+ + service.getPackageName() + ","
+ + service.getClass().getSimpleName(), e);
+ service.stopSelf();
+ }
}
@Nullable
diff --git a/car-lib/src/android/car/CarTransactionException.java b/car-lib/src/android/car/CarTransactionException.java
new file mode 100644
index 0000000..c0e7e2f
--- /dev/null
+++ b/car-lib/src/android/car/CarTransactionException.java
@@ -0,0 +1,31 @@
+/*
+ * 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 android.car;
+
+/**
+ * Runtime exception thrown when a transaction-level binder exception has occurred.
+ *
+ * This allows clients to log or recover transaction errors as appropriate.
+ *
+ * @hide
+ */
+public class CarTransactionException extends UnsupportedOperationException {
+ CarTransactionException(Throwable cause, String msg, Object... args) {
+ super(String.format(msg, args), cause);
+ }
+}
+
diff --git a/car-lib/src/android/car/hardware/property/CarPropertyManager.java b/car-lib/src/android/car/hardware/property/CarPropertyManager.java
index e3651da..9419d6d 100644
--- a/car-lib/src/android/car/hardware/property/CarPropertyManager.java
+++ b/car-lib/src/android/car/hardware/property/CarPropertyManager.java
@@ -23,6 +23,7 @@
import android.annotation.Nullable;
import android.car.Car;
import android.car.CarManagerBase;
+import android.car.VehicleAreaType;
import android.car.hardware.CarPropertyConfig;
import android.car.hardware.CarPropertyValue;
import android.os.Handler;
@@ -317,6 +318,47 @@
}
/**
+ * Get CarPropertyConfig by property Id.
+ *
+ * @param propId Property ID
+ * @return {@link CarPropertyConfig} for the selected property.
+ * Null if the property is not available.
+ */
+ @Nullable
+ public CarPropertyConfig<?> getCarPropertyConfig(int propId) {
+ return mConfigMap.get(propId);
+ }
+
+ /**
+ * Returns areaId contains the seletcted area for the property.
+ *
+ * @param propId Property ID
+ * @param area Area enum such as Enums in {@link android.car.VehicleAreaSeat}.
+ * @throws IllegalArgumentException if the property is not available in the vehicle for
+ * the selected area.
+ * @return AreaId contains the selected area for the property.
+ */
+ public int getAreaId(int propId, int area) {
+ CarPropertyConfig<?> propConfig = getCarPropertyConfig(propId);
+ if (propConfig == null) {
+ throw new IllegalArgumentException("The property propId: 0x" + toHexString(propId)
+ + " is not available");
+ }
+ // For the global property, areaId is 0
+ if (propConfig.isGlobalProperty()) {
+ return VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL;
+ }
+ for (int areaId : propConfig.getAreaIds()) {
+ if ((area & areaId) == area) {
+ return areaId;
+ }
+ }
+
+ throw new IllegalArgumentException("The property propId: 0x" + toHexString(propId)
+ + " is not available at the area: 0x" + toHexString(area));
+ }
+
+ /**
* Return read permission string for given property ID.
*
* @param propId Property ID to query
diff --git a/car-lib/src/android/car/settings/CarSettings.java b/car-lib/src/android/car/settings/CarSettings.java
index 888ccad..cd31a50 100644
--- a/car-lib/src/android/car/settings/CarSettings.java
+++ b/car-lib/src/android/car/settings/CarSettings.java
@@ -54,22 +54,6 @@
"android.car.GARAGE_MODE_MAINTENANCE_WINDOW";
/**
- * Key for default user id to boot into.
- *
- * @hide
- */
- public static final String DEFAULT_USER_ID_TO_BOOT_INTO =
- "android.car.DEFAULT_BOOT_INTO_USER_ID";
-
- /**
- * Key for user id that is last logged in to.
- *
- * @hide
- */
- public static final String LAST_ACTIVE_USER_ID =
- "android.car.LAST_ACTIVE_USER_ID";
-
- /**
* Whether default restrictions for users have been set.
*
* @hide
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-af/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-af/strings.xml
index cf04334..abf8fd2 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-af/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"Bestuurder"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"kry benaderde ligging net op die voorgrond"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-am/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-am/strings.xml
index 4afdf25..0f190c4 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-am/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"ነጂ"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"ከፊት ለፊት ብቻ ግምታዊ አካባቢን ድረስ"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-ar/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-ar/strings.xml
index 874ff29..aa51d5d 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-ar/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"السائق"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"الوصول إلى الموقع الجغرافي التقريبي في الواجهة الأمامية فقط"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-az/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-az/strings.xml
index 67b565b..3e2ccc1 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-az/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"Sürücü"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"yalnız ön planda təqribi məkana daxil olun"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-b+sr+Latn/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-b+sr+Latn/strings.xml
index 5f857c2..a20c58e 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-b+sr+Latn/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"Vozač"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"pristup približnoj lokaciji samo u prvom planu"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-be/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-be/strings.xml
index 7cc0826..d6e8de4 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-be/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"Вадзіцель"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"доступ да прыблізнага месцазнаходжання толькі ў асноўным рэжыме"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-bg/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-bg/strings.xml
index ad2abf6..7a2fd23 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-bg/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"Шофьор"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"достъп до приблизителното местоположение само на преден план"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-bn/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-bn/strings.xml
index cb6d8a6..e9725c8 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-bn/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"ড্রাইভার"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"শুধুমাত্র অ্যাপটি খোলা থাকলে আপনার আনুমানিক লোকেশন অ্যাক্সেস করা"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-bs/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-bs/strings.xml
index 5f857c2..a20c58e 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-bs/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"Vozač"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"pristup približnoj lokaciji samo u prvom planu"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-ca/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-ca/strings.xml
index 130c869..8d24e22 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-ca/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"Conductor"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"accedeix a la ubicació aproximada només en primer pla"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-cs/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-cs/strings.xml
index 40d9e58..2432df2 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-cs/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"Řidič"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"přístup k přibližné poloze jen na popředí"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-da/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-da/strings.xml
index 25c544c..4f95061 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-da/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"Chauffør"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"få kun adgang til omtrentlig placering i forgrunden"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-de/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-de/strings.xml
index 6a1deea..9febde6 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-de/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"Fahrer"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"Nur bei Ausführung im Vordergrund auf den ungefähren Standort zugreifen"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-el/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-el/strings.xml
index 4c317af..fcfe739 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-el/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"Οδηγός"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"πρόσβαση στην κατά προσέγγιση τοποθεσία μόνο στο προσκήνιο"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-en-rAU/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-en-rAU/strings.xml
index a4a3e1a..85c4908 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-en-rAU/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"Driver"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"access approximate location only in the foreground"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-en-rCA/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-en-rCA/strings.xml
index a4a3e1a..85c4908 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-en-rCA/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"Driver"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"access approximate location only in the foreground"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-en-rGB/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-en-rGB/strings.xml
index a4a3e1a..85c4908 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-en-rGB/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"Driver"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"access approximate location only in the foreground"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-en-rIN/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-en-rIN/strings.xml
index a4a3e1a..85c4908 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-en-rIN/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"Driver"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"access approximate location only in the foreground"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-en-rXC/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-en-rXC/strings.xml
index 725d577..7778984 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-en-rXC/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"Driver"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"access approximate location only in the foreground"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-es-rUS/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-es-rUS/strings.xml
index 130c869..5666331 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-es-rUS/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"Conductor"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"acceder a la ubicación aproximada solo en primer plano"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-es/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-es/strings.xml
index 130c869..3e3ad48 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-es/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"Conductor"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"acceder a la ubicación aproximada solo al estar en primer plano"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-et/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-et/strings.xml
index 4cffa81..27ae02b 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-et/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"Sõitja"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"juurdepääs ligikaudsele asukohale ainult esiplaanil"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-eu/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-eu/strings.xml
index 14ccb8e..f7e62cf 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-eu/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"Gidaria"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"atzitu gutxi gorabeherako kokapena aurreko planoan bakarrik"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-fa/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-fa/strings.xml
index 19c4ff9..4d257d6 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-fa/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"راننده"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"دسترسی به مکان تقریبی فقط در پیشزمینه"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-fi/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-fi/strings.xml
index 07853e1..b2d5135 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-fi/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"Kuljettaja"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"käyttää likimääräistä sijaintia vain etualalla"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-fr-rCA/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-fr-rCA/strings.xml
index 3cfdaf3..2ac4be7 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-fr-rCA/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"Conducteur"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"accéder à votre position approximative seulement en avant-plan"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-fr/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-fr/strings.xml
index 3cfdaf3..81af986 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-fr/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"Conducteur"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"accéder à la position approximative au premier plan uniquement"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-gl/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-gl/strings.xml
index fa09574..3754442 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-gl/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"Condutor"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"acceder á localización aproximada só en primeiro plano"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-gu/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-gu/strings.xml
index 62dd43e..5c6ff84 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-gu/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"ડ્રાઇવર"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"ફૉરગ્રાઉન્ડમાં ફક્ત અંદાજિત સ્થાન ઍક્સેસ કરો"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-hi/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-hi/strings.xml
index fbe93e1..003478d 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-hi/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"ड्राइवर"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"अनुमानित जगह की जानकारी सिर्फ़ तब ऐक्सेस करें, जब ऐप्लिकेशन स्क्रीन पर खुला हो"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-hr/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-hr/strings.xml
index 5f857c2..4cffd31 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-hr/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"Vozač"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"pristupiti približnoj lokaciji samo u prednjem planu"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-hu/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-hu/strings.xml
index 83dc49a..52b7760 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-hu/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"Sofőr"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"megközelítőleges helyadatokhoz való hozzáférés csak előtérben"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-hy/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-hy/strings.xml
index cbaa105..68df140 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-hy/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"Վարորդ"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"տեղադրության մոտավոր տվյալների հասանելիություն միայն ֆոնային ռեժիմում"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-in/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-in/strings.xml
index 89fa52e..21c21a8 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-in/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"Pengemudi"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"akses perkiraan lokasi hanya saat di latar depan"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-is/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-is/strings.xml
index 38bba6e..1eb3776 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-is/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"Ökumaður"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"aðgangur að áætlaðri staðsetningu aðeins í forgrunni"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-it/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-it/strings.xml
index c9491dd..c704544 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-it/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"Autista"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"Accesso alla posizione approssimativa solo in primo piano"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-ja/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-ja/strings.xml
index 7872368..eb41c01 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-ja/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"ドライバー"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"フォアグラウンドでのみおおよその位置情報を取得"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-ka/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-ka/strings.xml
index 55879f3..4d26423 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-ka/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"მძღოლი"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"მიახლოებით მდებარეობაზე წვდომა მხოლოდ წინა პლანზე"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-kk/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-kk/strings.xml
index 68714f3..b12a6d5 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-kk/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"Көлік жүргізуші"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"болжалды орналасқан жер туралы ақпаратқа тек ашық экранда кіру"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-km/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-km/strings.xml
index f2d19e7..4975540 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-km/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"អ្នកបើកបរ"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"ចូលប្រើទីតាំងប្រហាក់ប្រហែលតែនៅផ្ទៃខាងមុខប៉ុណ្ណោះ"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-kn/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-kn/strings.xml
index 1812f01..27e9a9e 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-kn/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"ಡ್ರೈವರ್"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"ಮುನ್ನೆಲೆಯಲ್ಲಿ ಮಾತ್ರ ಅಂದಾಜು ಸ್ಥಳವನ್ನು ಪ್ರವೇಶಿಸಿ"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-ko/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-ko/strings.xml
index 6fb8bbd..20facb1 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-ko/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"운전자"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"포그라운드에서만 대략적인 위치에 액세스"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-ky/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-ky/strings.xml
index a961e34..1a43c49 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-ky/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"Айдоочу"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"болжолдуу аныкталган жайгашкан жерге активдүү режимде гана кирүүгө уруксат берүү"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-lo/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-lo/strings.xml
index a2e075b..877a259 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-lo/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"ຄົນຂັບລົດ"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"ເຂົ້າເຖິງສະຖານທີ່ໂດຍປະມານເມື່ອຢູ່ໃນພື້ນໜ້າເທົ່ານັ້ນ"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-lt/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-lt/strings.xml
index 20d10d8..134230f 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-lt/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"Vairuotojas"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"pasiekti apytikslę vietovę, tik kai programa veikia priekiniame plane"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-lv/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-lv/strings.xml
index f8a9b63..3cc5c88 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-lv/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"Vadītājs"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"piekļuve aptuvenai atrašanās vietai, tikai darbojoties priekšplānā"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-mk/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-mk/strings.xml
index ea97216..3b1eda7 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-mk/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"Возач"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"пристап до приближната локација само во преден план"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-ml/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-ml/strings.xml
index e09eaeb..95298dd 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-ml/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-ml/strings.xml
@@ -18,4 +18,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="owner_name" msgid="3416113395996003764">"ഡ്രൈവർ"</string>
+ <!-- no translation found for permlab_accessCoarseLocation (2494909511737161237) -->
+ <skip />
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-mn/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-mn/strings.xml
index 5a1682e..dd1d6a2 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-mn/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"Жолооч"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"ойролцоо байршилд зөвхөн дэлгэц дээр хандах"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-mr/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-mr/strings.xml
index de33088..a0619ec 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-mr/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"ड्रायव्हर"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"फक्त फोअरग्राउंडमध्ये अंदाजे स्थान अॅक्सेस करा"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-ms/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-ms/strings.xml
index 837f538..7f22021 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-ms/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"Pemandu"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"akses lokasi anggaran hanya di latar depan"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-my/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-my/strings.xml
index 5c96457..aea1568 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-my/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"ယာဉ်မောင်းသူ"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"မျက်နှာစာတွင်သာ ခန့်မှန်းခြေ တည်နေရာ အသုံးပြုခြင်း"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-nb/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-nb/strings.xml
index 139517b..6e0de84 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-nb/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"Sjåfør"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"bare tilgang til omtrentlig posisjon i forgrunnen"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-nl/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-nl/strings.xml
index c634d43..873fb01 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-nl/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"Chauffeur"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"alleen toegang tot geschatte locatie op de voorgrond"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-or/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-or/strings.xml
index 04f5336..964683f 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-or/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"ଡ୍ରାଇଭର୍"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"କେବଳ ଫୋର୍ଗ୍ରାଉଣ୍ଡରେ ହାରାହାରି ଲୋକେସନ୍ ଆକ୍ସେସ୍ କରନ୍ତୁ"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-pa/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-pa/strings.xml
index 354b580..16541d3 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-pa/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"ਡਰਾਈਵਰ"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"ਸਿਰਫ਼ ਫੋਰਗ੍ਰਾਊਂਡ ਵਿੱਚ ਅਨੁਮਾਨਿਤ ਟਿਕਾਣੇ ਤੱਕ ਪਹੁੰਚ ਕਰੋ"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-pl/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-pl/strings.xml
index 315bf44..d0ff092 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-pl/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"Kierowca"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"dostęp do przybliżonej lokalizacji tylko na pierwszym planie"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-pt-rPT/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-pt-rPT/strings.xml
index fa09574..984000a 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-pt-rPT/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"Condutor"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"apenas aceder à localização aproximada em primeiro plano"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-pt/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-pt/strings.xml
index af84856..7ac9eef 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-pt/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"Motorista"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"acessar local aproximado apenas em primeiro plano"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-ro/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-ro/strings.xml
index c6ca011..ec78db2 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-ro/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"Șofer"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"să acceseze locația aproximativă numai în prim-plan"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-ru/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-ru/strings.xml
index 87359fb..ed49d76 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-ru/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"Водитель"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"Доступ к приблизительному местоположению только в активном режиме"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-si/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-si/strings.xml
index a2aa811..fcba27e 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-si/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"රියදුරු"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"පෙරබිම තුළ පමණක් ආසන්න ස්ථානයට ප්රවේශය"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-sk/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-sk/strings.xml
index 94a4723..c9a990d 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-sk/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"Vodič"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"prístup k približnej polohe iba v popredí"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-sl/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-sl/strings.xml
index 9f75529..918dda4 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-sl/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"Voznik"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"dostop do približne lokacije samo, ko deluje v ospredju"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-sq/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-sq/strings.xml
index 4e6cd54..e4192e7 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-sq/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"Drejtuesi"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"qasu në vendndodhjen e përafërt vetëm në plan të parë"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-sr/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-sr/strings.xml
index ea97216..8cce889 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-sr/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"Возач"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"приступ приближној локацији само у првом плану"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-sv/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-sv/strings.xml
index 12d2369..b5b4f63 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-sv/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"Förare"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"endast åtkomst till ungefärlig plats i förgrunden"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-sw/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-sw/strings.xml
index 90924e1..765973c 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-sw/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"Dereva"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"kufikia mahali palipokadiriwa ikiwa tu programu imefunguliwa kwenye skrini"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-ta/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-ta/strings.xml
index 47a7058..264f0c1 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-ta/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"கார் உரிமையாளர்"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"முன்புலத்தில் இயங்கும்போது மட்டும் தோராயமான இருப்பிடத்தைக் கண்டறிதல்"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-th/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-th/strings.xml
index c3d4c8c..8fae2ca 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-th/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"ผู้ขับรถ"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"เข้าถึงตำแหน่งโดยประมาณเมื่ออยู่เบื้องหน้าเท่านั้น"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-tl/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-tl/strings.xml
index a4a3e1a..d425a87 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-tl/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"Driver"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"i-access lang ang tinatantyang lokasyon sa foreground"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-tr/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-tr/strings.xml
index 67b565b..244564e 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-tr/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"Sürücü"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"yalnızca ön planda yaklaşık konuma erişme"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-uk/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-uk/strings.xml
index 1bc0b22..b46d679 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-uk/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"Водій"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"отримувати доступ до даних про приблизне місцезнаходження лише в активному режимі"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-ur/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-ur/strings.xml
index f69a738..89fd655 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-ur/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"ڈرائیور"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"صرف پیش منظر میں تخمینی مقام تک رسائی"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-uz/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-uz/strings.xml
index 07264f4..9914c10 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-uz/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"Haydovchi"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"taxminiy joylashuv axborotini olishga faqat old fonda ruxsat"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-vi/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-vi/strings.xml
index ef6b702..41ce1e9 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-vi/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"Tài xế"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"chỉ truy cập thông tin vị trí gần đúng trong nền trước"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-zh-rCN/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-zh-rCN/strings.xml
index 0347e14..06fe50d 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-zh-rCN/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"司机"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"只有在前台运行时才能获取大致位置信息"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-zh-rHK/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-zh-rHK/strings.xml
index 37aab13..86618d3 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-zh-rHK/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"司機"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"只在前景存取大概位置"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-zh-rTW/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-zh-rTW/strings.xml
index 8ecce72..59f09e1 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-zh-rTW/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"駕駛"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"僅可在前景中取得概略位置"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-zu/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-zu/strings.xml
index b5ec2c1..adb9402 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-zu/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/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="owner_name" msgid="3416113395996003764">"Umshayeli"</string>
+ <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"finyelela indawo enembile kuphela engaphambili"</string>
</resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values/config.xml b/car_product/overlay/frameworks/base/core/res/res/values/config.xml
index cbd1660..2d28676 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values/config.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values/config.xml
@@ -97,8 +97,9 @@
<bool name="config_automotiveHideNavBarForKeyboard">true</bool>
- <!-- Turn off Wallpaper service -->
- <bool name="config_enableWallpaperService">false</bool>
+ <!-- Turn on Wallpaper service -->
+ <!-- Enabled temporarily to watch the dashboard-->
+ <bool name="config_enableWallpaperService">true</bool>
<!-- Default user restrictions for system user 0. -->
<string-array translatable="false" name="config_defaultFirstUserRestrictions">
diff --git a/computepipe/aidl/Android.bp b/computepipe/aidl/Android.bp
index b70b9b4..a60b2f2 100644
--- a/computepipe/aidl/Android.bp
+++ b/computepipe/aidl/Android.bp
@@ -3,13 +3,19 @@
vendor_available: true,
srcs: [
"android/automotive/computepipe/runner/*.aidl",
- "android/automotive/computepipe/*.aidl",
+ "android/automotive/computepipe/*.aidl",
+ ],
+ imports: [
+ "vintf-graphics-common",
],
stability: "vintf",
backend: {
java: {
enabled: false,
},
+ cpp: {
+ enabled: false,
+ },
},
}
@@ -19,12 +25,15 @@
imports: ["android.automotive.computepipe.runner"],
srcs: [
"android/automotive/computepipe/registry/*.aidl",
- "android/automotive/computepipe/*.aidl",
+ "android/automotive/computepipe/*.aidl",
],
stability: "vintf",
backend: {
java: {
enabled: false,
},
+ cpp: {
+ enabled: false,
+ },
},
}
diff --git a/computepipe/aidl/android/automotive/computepipe/runner/PacketDescriptor.aidl b/computepipe/aidl/android/automotive/computepipe/runner/PacketDescriptor.aidl
index b76210c..44f7e6b 100644
--- a/computepipe/aidl/android/automotive/computepipe/runner/PacketDescriptor.aidl
+++ b/computepipe/aidl/android/automotive/computepipe/runner/PacketDescriptor.aidl
@@ -16,7 +16,7 @@
package android.automotive.computepipe.runner;
import android.automotive.computepipe.runner.PacketDescriptorPacketType;
-import android.automotive.computepipe.NativeHandle;
+import android.hardware.graphics.common.HardwareBuffer;
/**
* Structure that describes the output packet for a specific outputstream
@@ -40,8 +40,10 @@
/**
* handle to memory region containing zero copy data
* This handle can be mapped and data retrieved.
+ * In case of Pixel data the description field will contain the
+ * graphics buffer description.
*/
- NativeHandle handle;
+ HardwareBuffer handle;
/**
* Timestamp of event at source. Timestamp value is milliseconds since epoch.
*/
@@ -51,4 +53,3 @@
*/
@utf8InCpp String data;
}
-
diff --git a/computepipe/proto/InputConfig.proto b/computepipe/proto/InputConfig.proto
index f696d57..b061e46 100644
--- a/computepipe/proto/InputConfig.proto
+++ b/computepipe/proto/InputConfig.proto
@@ -32,7 +32,7 @@
* of InputType. If only one of a certain type is present
* this should be 0. For VIDEO_FILE this should be 0.
*/
- optional int32 camId = 6;
+ optional int32 cam_id = 6;
optional int32 config_id = 7;
}
diff --git a/computepipe/proto/Options.proto b/computepipe/proto/Options.proto
index 94a7927..14d130d 100644
--- a/computepipe/proto/Options.proto
+++ b/computepipe/proto/Options.proto
@@ -11,7 +11,7 @@
/**
* input configurations supported by the graph
*/
- optional InputConfig input_configs = 1;
+ repeated InputConfig input_configs = 1;
/**
* Offload options supported by the graph
@@ -25,4 +25,9 @@
* Output streams supported by the graph.
*/
repeated OutputConfig output_configs = 4;
+
+ /**
+ * Name of the computer vision graph.
+ */
+ optional string graph_name = 5;
}
diff --git a/computepipe/router/1.0/Android.bp b/computepipe/router/1.0/Android.bp
index d1bad50..dd4b6c0 100644
--- a/computepipe/router/1.0/Android.bp
+++ b/computepipe/router/1.0/Android.bp
@@ -12,33 +12,33 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-
cc_library {
name: "android.automotive.computepipe.router@1.0-impl",
- vendor_available : true,
+ vendor_available: true,
srcs: [
"PipeClient.cpp",
- "PipeRunner.cpp",
- "PipeRegistration.cpp",
- "PipeQuery.cpp",
+ "PipeRunner.cpp",
+ "PipeRegistration.cpp",
+ "PipeQuery.cpp",
+ "RemoteState.cpp",
],
- cflags: ["-DLOG_TAG=\"ComputepipeRouter\""]
- + [
- "-Wall",
- "-Werror",
- "-Wextra",
- "-Wno-unused-parameter",
- ],
+ cflags: ["-DLOG_TAG=\"ComputepipeRouter\""] +
+ [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ "-Wno-unused-parameter",
+ ],
header_libs: [
- "computepipe_router_headers",
+ "computepipe_router_headers",
],
export_include_dirs: ["include"],
shared_libs: [
- "liblog",
+ "liblog",
"libutils",
- "libbinder",
- "android.automotive.computepipe.registry-cpp",
- "android.automotive.computepipe.runner-cpp",
+ "libbinder_ndk",
+ "android.automotive.computepipe.registry-ndk_platform",
+ "android.automotive.computepipe.runner-ndk_platform",
],
}
@@ -48,22 +48,18 @@
"service.cpp",
"RouterSvc.cpp",
],
-
shared_libs: [
"libcutils",
"liblog",
"libutils",
- "libbinder",
+ "libbinder_ndk",
"android.automotive.computepipe.router@1.0-impl",
- "android.automotive.computepipe.registry-cpp",
+ "android.automotive.computepipe.registry-ndk_platform",
],
-
header_libs: [
- "computepipe_router_headers",
+ "computepipe_router_headers",
],
-
init_rc: ["android.automotive.computepipe.router@1.0.rc"],
-
cflags: ["-DLOG_TAG=\"ComputepipeRouter\""] + [
"-DGL_GLEXT_PROTOTYPES",
"-DEGL_EGLEXT_PROTOTYPES",
@@ -73,5 +69,4 @@
"-Wunused",
"-Wunreachable-code",
],
-
}
diff --git a/computepipe/router/1.0/PipeClient.cpp b/computepipe/router/1.0/PipeClient.cpp
index 3896d73..817782a 100644
--- a/computepipe/router/1.0/PipeClient.cpp
+++ b/computepipe/router/1.0/PipeClient.cpp
@@ -16,7 +16,7 @@
#include "PipeClient.h"
-#include <binder/ProcessState.h>
+#include <android/binder_ibinder.h>
namespace android {
namespace automotive {
@@ -25,7 +25,13 @@
namespace V1_0 {
namespace implementation {
-using namespace android::automotive::computepipe::registry;
+using namespace aidl::android::automotive::computepipe::registry;
+using namespace ndk;
+
+PipeClient::PipeClient(const std::shared_ptr<IClientInfo>& info)
+ : mDeathMonitor(AIBinder_DeathRecipient_new(RemoteMonitor::BinderDiedCallback)),
+ mClientInfo(info) {
+}
uint32_t PipeClient::getClientId() {
if (mClientInfo == nullptr) {
@@ -38,37 +44,19 @@
}
bool PipeClient::startClientMonitor() {
- mClientMonitor = new ClientMonitor();
- if (!mClientMonitor) {
- return false;
- }
- const sp<IBinder> client = IInterface::asBinder(mClientInfo);
- if (!client) {
- return false;
- }
- auto res = client->linkToDeath(mClientMonitor);
- return res == OK;
+ mState = std::make_shared<RemoteState>();
+ auto monitor = new RemoteMonitor(mState);
+ auto status = ScopedAStatus::fromStatus(
+ AIBinder_linkToDeath(mClientInfo->asBinder().get(), mDeathMonitor.get(), monitor));
+ return status.isOk();
}
bool PipeClient::isAlive() {
- return mClientMonitor->isAlive();
+ return mState->isAlive();
}
PipeClient::~PipeClient() {
- const sp<IBinder> client = IInterface::asBinder(mClientInfo);
- (void)client->unlinkToDeath(mClientMonitor);
}
-
-void ClientMonitor::binderDied(const wp<android::IBinder>& /* base */) {
- std::lock_guard<std::mutex> lock(mStateLock);
- mAlive = false;
-}
-
-bool ClientMonitor::isAlive() {
- std::lock_guard<std::mutex> lock(mStateLock);
- return mAlive;
-}
-
} // namespace implementation
} // namespace V1_0
} // namespace router
diff --git a/computepipe/router/1.0/PipeQuery.cpp b/computepipe/router/1.0/PipeQuery.cpp
index 9ea8db1..42e4f0b 100644
--- a/computepipe/router/1.0/PipeQuery.cpp
+++ b/computepipe/router/1.0/PipeQuery.cpp
@@ -25,37 +25,38 @@
namespace implementation {
using namespace android::automotive::computepipe::router;
-using namespace android::automotive::computepipe::registry;
-using namespace android::automotive::computepipe::runner;
-using namespace android::binder;
+using namespace aidl::android::automotive::computepipe::registry;
+using namespace aidl::android::automotive::computepipe::runner;
+using namespace ndk;
-Status PipeQuery::getGraphList(std::vector<std::string>* outNames) {
+ScopedAStatus PipeQuery::getGraphList(std::vector<std::string>* outNames) {
if (!mRegistry || !outNames) {
- return Status::fromExceptionCode(Status::Exception::EX_ILLEGAL_STATE);
+ return ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_STATE));
}
auto names = mRegistry->getPipeList();
std::copy(names.begin(), names.end(), std::back_inserter(*outNames));
- return Status::ok();
+ return ScopedAStatus::ok();
}
-Status PipeQuery::getPipeRunner(const std::string& graphName, const sp<IClientInfo>& info,
- sp<IPipeRunner>* outRunner) {
+ScopedAStatus PipeQuery::getPipeRunner(const std::string& graphName,
+ const std::shared_ptr<IClientInfo>& info,
+ std::shared_ptr<IPipeRunner>* outRunner) {
*outRunner = nullptr;
if (!mRegistry) {
- return Status::fromExceptionCode(Status::Exception::EX_ILLEGAL_STATE);
+ return ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_STATE));
}
std::unique_ptr<ClientHandle> clientHandle = std::make_unique<PipeClient>(info);
auto pipeHandle = mRegistry->getClientPipeHandle(graphName, std::move(clientHandle));
if (!pipeHandle) {
- return Status::fromExceptionCode(Status::Exception::EX_ILLEGAL_STATE);
+ return ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_STATE));
}
auto pipeRunner = pipeHandle->getInterface();
*outRunner = pipeRunner->runner;
- return Status::ok();
+ return ScopedAStatus::ok();
}
-String16 PipeQuery::getIfaceName() {
- return this->getInterfaceDescriptor();
+const char* PipeQuery::getIfaceName() {
+ return this->descriptor;
}
} // namespace implementation
} // namespace V1_0
diff --git a/computepipe/router/1.0/PipeRegistration.cpp b/computepipe/router/1.0/PipeRegistration.cpp
index 1a5eb8e..cff413c 100644
--- a/computepipe/router/1.0/PipeRegistration.cpp
+++ b/computepipe/router/1.0/PipeRegistration.cpp
@@ -22,31 +22,31 @@
namespace V1_0 {
namespace implementation {
-using namespace android::binder;
using namespace android::automotive::computepipe;
-using namespace android::automotive::computepipe::runner;
+using namespace aidl::android::automotive::computepipe::runner;
+using namespace ndk;
// Methods from ::android::automotive::computepipe::registry::V1_0::IPipeRegistration follow.
-Status PipeRegistration::registerPipeRunner(const std::string& graphName,
- const sp<IPipeRunner>& graphRunner) {
+ScopedAStatus PipeRegistration::registerPipeRunner(const std::string& graphName,
+ const std::shared_ptr<IPipeRunner>& graphRunner) {
if (!mRegistry) {
- return Status::fromExceptionCode(Status::Exception::EX_ILLEGAL_STATE);
+ return ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_STATE));
}
std::unique_ptr<PipeHandle<PipeRunner>> handle = std::make_unique<RunnerHandle>(graphRunner);
auto err = mRegistry->RegisterPipe(std::move(handle), graphName);
return convertToBinderStatus(err);
}
-Status PipeRegistration::convertToBinderStatus(Error err) {
+ScopedAStatus PipeRegistration::convertToBinderStatus(Error err) {
switch (err) {
case OK:
- return Status::ok();
+ return ScopedAStatus::ok();
default:
- return Status::fromExceptionCode(Status::Exception::EX_ILLEGAL_STATE);
+ return ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_STATE));
}
}
-String16 PipeRegistration::getIfaceName() {
- return this->getInterfaceDescriptor();
+const char* PipeRegistration::getIfaceName() {
+ return this->descriptor;
}
} // namespace implementation
} // namespace V1_0
diff --git a/computepipe/router/1.0/PipeRunner.cpp b/computepipe/router/1.0/PipeRunner.cpp
index 616e86b..cdf1cb1 100644
--- a/computepipe/router/1.0/PipeRunner.cpp
+++ b/computepipe/router/1.0/PipeRunner.cpp
@@ -16,6 +16,8 @@
#include "PipeRunner.h"
+#include <android/binder_ibinder.h>
+
#include <mutex>
namespace android {
@@ -25,34 +27,27 @@
namespace V1_0 {
namespace implementation {
-using namespace android::automotive::computepipe::runner;
+using namespace aidl::android::automotive::computepipe::runner;
+using namespace ndk;
-PipeRunner::PipeRunner(const sp<IPipeRunner>& graphRunner) : runner(graphRunner) {
+PipeRunner::PipeRunner(const std::shared_ptr<IPipeRunner>& graphRunner) : runner(graphRunner) {
}
-void PipeMonitor::binderDied(const wp<android::IBinder>& /* base */) {
- mNotifier();
-}
-
-RunnerHandle::RunnerHandle(const sp<IPipeRunner>& r) : PipeHandle(std::make_unique<PipeRunner>(r)) {
+RunnerHandle::RunnerHandle(const std::shared_ptr<IPipeRunner>& r)
+ : PipeHandle(std::make_unique<PipeRunner>(r)),
+ mDeathMonitor(AIBinder_DeathRecipient_new(RemoteMonitor::BinderDiedCallback)) {
}
bool RunnerHandle::startPipeMonitor() {
- sp<PipeMonitor> monitor = new PipeMonitor([this]() { this->markDead(); });
- // We store a weak reference to be able to perform an unlink
- mPipeMonitor = monitor;
- sp<IBinder> iface = IInterface::asBinder(mInterface->runner);
- return iface->linkToDeath(monitor) == OK;
-}
-
-void RunnerHandle::markDead() {
- std::lock_guard<std::mutex> lock(mStateLock);
- mAlive = false;
+ mState = std::make_shared<RemoteState>();
+ auto monitor = new RemoteMonitor(mState);
+ auto status = ScopedAStatus::fromStatus(
+ AIBinder_linkToDeath(mInterface->runner->asBinder().get(), mDeathMonitor.get(), monitor));
+ return status.isOk();
}
bool RunnerHandle::isAlive() {
- std::lock_guard<std::mutex> lock(mStateLock);
- return mAlive;
+ return mState->isAlive();
}
PipeHandle<PipeRunner>* RunnerHandle::clone() const {
@@ -60,8 +55,6 @@
}
RunnerHandle::~RunnerHandle() {
- sp<IBinder> iface = IInterface::asBinder(mInterface->runner);
- iface->unlinkToDeath(mPipeMonitor.promote());
}
} // namespace implementation
diff --git a/computepipe/router/1.0/RemoteState.cpp b/computepipe/router/1.0/RemoteState.cpp
new file mode 100644
index 0000000..9d81fb6
--- /dev/null
+++ b/computepipe/router/1.0/RemoteState.cpp
@@ -0,0 +1,52 @@
+/**
+ * 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.
+ */
+
+#include "RemoteState.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace router {
+namespace V1_0 {
+namespace implementation {
+
+void RemoteState::markDead() {
+ std::lock_guard<std::mutex> lock(mStateLock);
+ mAlive = false;
+}
+
+bool RemoteState::isAlive() {
+ std::lock_guard<std::mutex> lock(mStateLock);
+ return mAlive;
+}
+
+void RemoteMonitor::binderDied() {
+ auto state = mState.lock();
+ if (state != nullptr) {
+ state->markDead();
+ }
+}
+
+void RemoteMonitor::BinderDiedCallback(void* cookie) {
+ auto monitor = static_cast<RemoteMonitor*>(cookie);
+ monitor->binderDied();
+}
+} // namespace implementation
+} // namespace V1_0
+} // namespace router
+} // namespace computepipe
+} // namespace automotive
+} // namespace android
diff --git a/computepipe/router/1.0/RouterSvc.cpp b/computepipe/router/1.0/RouterSvc.cpp
index 57ef9a0..0b296e6 100644
--- a/computepipe/router/1.0/RouterSvc.cpp
+++ b/computepipe/router/1.0/RouterSvc.cpp
@@ -15,8 +15,11 @@
*/
#include "RouterSvc.h"
+#include <android/binder_interface_utils.h>
+#include <android/binder_manager.h>
#include <binder/IServiceManager.h>
+#include "PipeQuery.h"
#include "PipeRegistration.h"
#include "Registry.h"
@@ -49,15 +52,14 @@
}
Error RouterSvc::initRegistrationEngine() {
- mRegisterEngine = new PipeRegistration(mRegistry);
+ mRegisterEngine = ndk::SharedRefBase::make<PipeRegistration>(mRegistry);
if (!mRegisterEngine) {
ALOGE("unable to allocate registration engine");
return NOMEM;
}
- std::string name =
- std::string() + String8(mRegisterEngine->getIfaceName()).c_str() + "/" + kRouterName;
- auto status = defaultServiceManager()->addService(String16(name.c_str()), mRegisterEngine);
- if (status != android::OK) {
+ std::string name = std::string() + mRegisterEngine->getIfaceName() + "/" + kRouterName;
+ auto status = AServiceManager_addService(mRegisterEngine->asBinder().get(), name.c_str());
+ if (status != STATUS_OK) {
ALOGE("unable to add registration service %s", name.c_str());
return INTERNAL_ERR;
}
@@ -65,15 +67,14 @@
}
Error RouterSvc::initQueryEngine() {
- mQueryEngine = new PipeQuery(mRegistry);
+ mQueryEngine = ndk::SharedRefBase::make<PipeQuery>(mRegistry);
if (!mQueryEngine) {
ALOGE("unable to allocate query service");
return NOMEM;
}
- std::string name =
- std::string() + String8(mQueryEngine->getIfaceName()).c_str() + "/" + kRouterName;
- auto status = defaultServiceManager()->addService(String16(name.c_str()), mQueryEngine);
- if (status != android::OK) {
+ std::string name = std::string() + mQueryEngine->getIfaceName() + "/" + kRouterName;
+ auto status = AServiceManager_addService(mQueryEngine->asBinder().get(), name.c_str());
+ if (status != STATUS_OK) {
ALOGE("unable to add query service %s", name.c_str());
return INTERNAL_ERR;
}
diff --git a/computepipe/router/1.0/RouterSvc.h b/computepipe/router/1.0/RouterSvc.h
index 3d19807..08ea59c 100644
--- a/computepipe/router/1.0/RouterSvc.h
+++ b/computepipe/router/1.0/RouterSvc.h
@@ -50,8 +50,8 @@
router::Error initRegistrationEngine();
std::string mSvcName = "ComputePipeRouter";
- sp<PipeQuery> mQueryEngine;
- sp<PipeRegistration> mRegisterEngine;
+ std::shared_ptr<PipeQuery> mQueryEngine;
+ std::shared_ptr<PipeRegistration> mRegisterEngine;
std::shared_ptr<RouterRegistry> mRegistry;
};
} // namespace implementation
diff --git a/computepipe/router/1.0/include/PipeClient.h b/computepipe/router/1.0/include/PipeClient.h
index ea934ee..03fc8f3 100644
--- a/computepipe/router/1.0/include/PipeClient.h
+++ b/computepipe/router/1.0/include/PipeClient.h
@@ -17,12 +17,15 @@
#ifndef ANDROID_AUTOMOTIVE_COMPUTEPIPE_ROUTER_V1_0_PIPECLIENT
#define ANDROID_AUTOMOTIVE_COMPUTEPIPE_ROUTER_V1_0_PIPECLIENT
-#include <android/automotive/computepipe/registry/IClientInfo.h>
+#include <aidl/android/automotive/computepipe/registry/IClientInfo.h>
+#include <android/binder_auto_utils.h>
#include <functional>
+#include <memory>
#include <mutex>
#include "ClientHandle.h"
+#include "RemoteState.h"
namespace android {
namespace automotive {
@@ -32,39 +35,23 @@
namespace implementation {
/**
- * Tracks Client Death
- */
-struct ClientMonitor : public IBinder::DeathRecipient {
- public:
- /* override method to track client death */
- virtual void binderDied(const wp<android::IBinder>& base) override;
- /* query for client death */
- bool isAlive();
-
- private:
- std::function<void()> mHandleCb;
- bool mAlive = true;
- std::mutex mStateLock;
-};
-
-/**
* PipeClient: Encapsulated the IPC interface to the client.
*
* Allows for querrying the client state
*/
class PipeClient : public ClientHandle {
public:
- explicit PipeClient(const sp<android::automotive::computepipe::registry::IClientInfo>& info)
- : mClientInfo(info) {
- }
+ explicit PipeClient(
+ const std::shared_ptr<aidl::android::automotive::computepipe::registry::IClientInfo>& info);
bool startClientMonitor() override;
uint32_t getClientId() override;
bool isAlive() override;
~PipeClient();
private:
- sp<ClientMonitor> mClientMonitor;
- sp<android::automotive::computepipe::registry::IClientInfo> mClientInfo;
+ ::ndk::ScopedAIBinder_DeathRecipient mDeathMonitor;
+ std::shared_ptr<RemoteState> mState;
+ const std::shared_ptr<aidl::android::automotive::computepipe::registry::IClientInfo> mClientInfo;
};
} // namespace implementation
diff --git a/computepipe/router/1.0/include/PipeQuery.h b/computepipe/router/1.0/include/PipeQuery.h
index ee17bc0..4cf80ac 100644
--- a/computepipe/router/1.0/include/PipeQuery.h
+++ b/computepipe/router/1.0/include/PipeQuery.h
@@ -17,7 +17,9 @@
#ifndef ANDROID_AUTOMOTIVE_COMPUTEPIPE_ROUTER_V1_0_PIPEQUERY
#define ANDROID_AUTOMOTIVE_COMPUTEPIPE_ROUTER_V1_0_PIPEQUERY
-#include <android/automotive/computepipe/registry/BnPipeQuery.h>
+#include <aidl/android/automotive/computepipe/registry/BnPipeQuery.h>
+
+#include <memory>
#include "PipeRunner.h"
#include "Registry.h"
@@ -29,16 +31,17 @@
namespace V1_0 {
namespace implementation {
-class PipeQuery : public android::automotive::computepipe::registry::BnPipeQuery {
+class PipeQuery : public aidl::android::automotive::computepipe::registry::BnPipeQuery {
public:
explicit PipeQuery(std::shared_ptr<PipeRegistry<PipeRunner>> r) : mRegistry(r) {
}
- binder::Status getGraphList(::std::vector<std::string>* outNames) override;
- binder::Status getPipeRunner(
+ ndk::ScopedAStatus getGraphList(::std::vector<std::string>* outNames) override;
+ ndk::ScopedAStatus getPipeRunner(
const std::string& graphName,
- const sp<::android::automotive::computepipe::registry::IClientInfo>& info,
- sp<::android::automotive::computepipe::runner::IPipeRunner>* outRunner) override;
- String16 getIfaceName();
+ const std::shared_ptr<aidl::android::automotive::computepipe::registry::IClientInfo>& info,
+ std::shared_ptr<aidl::android::automotive::computepipe::runner::IPipeRunner>* outRunner)
+ override;
+ const char* getIfaceName();
private:
std::shared_ptr<PipeRegistry<PipeRunner>> mRegistry;
diff --git a/computepipe/router/1.0/include/PipeRegistration.h b/computepipe/router/1.0/include/PipeRegistration.h
index 2258d72..abd5a99 100644
--- a/computepipe/router/1.0/include/PipeRegistration.h
+++ b/computepipe/router/1.0/include/PipeRegistration.h
@@ -16,7 +16,7 @@
#ifndef ANDROID_AUTOMOTIVE_COMPUTEPIPE_ROUTER_V1_0_PIPEREGISTRATION
#define ANDROID_AUTOMOTIVE_COMPUTEPIPE_ROUTER_V1_0_PIPEREGISTRATION
-#include <android/automotive/computepipe/registry/BnPipeRegistration.h>
+#include <aidl/android/automotive/computepipe/registry/BnPipeRegistration.h>
#include <memory>
#include <utility>
@@ -31,21 +31,22 @@
namespace V1_0 {
namespace implementation {
-class PipeRegistration : public android::automotive::computepipe::registry::BnPipeRegistration {
+class PipeRegistration
+ : public aidl::android::automotive::computepipe::registry::BnPipeRegistration {
public:
// Method from ::android::automotive::computepipe::registry::V1_0::IPipeRegistration
- android::binder::Status registerPipeRunner(
+ ndk::ScopedAStatus registerPipeRunner(
const std::string& graphName,
- const ::android::sp<::android::automotive::computepipe::runner::IPipeRunner>& graphRunner)
- override;
+ const std::shared_ptr<aidl::android::automotive::computepipe::runner::IPipeRunner>&
+ graphRunner) override;
explicit PipeRegistration(std::shared_ptr<PipeRegistry<PipeRunner>> r) : mRegistry(r) {
}
- String16 getIfaceName();
+ const char* getIfaceName();
private:
// Convert internal registry error codes to PipeStatus
- android::binder::Status convertToBinderStatus(Error err);
+ ndk::ScopedAStatus convertToBinderStatus(Error err);
std::shared_ptr<PipeRegistry<PipeRunner>> mRegistry;
};
diff --git a/computepipe/router/1.0/include/PipeRunner.h b/computepipe/router/1.0/include/PipeRunner.h
index 43a777a..d3d0453 100644
--- a/computepipe/router/1.0/include/PipeRunner.h
+++ b/computepipe/router/1.0/include/PipeRunner.h
@@ -16,12 +16,14 @@
#ifndef ANDROID_AUTOMOTIVE_COMPUTEPIPE_ROUTER_V1_0_PIPERUNNER
#define ANDROID_AUTOMOTIVE_COMPUTEPIPE_ROUTER_V1_0_PIPERUNNER
-#include <android/automotive/computepipe/runner/IPipeRunner.h>
+#include <aidl/android/automotive/computepipe/runner/IPipeRunner.h>
#include <functional>
+#include <memory>
#include <mutex>
#include "PipeHandle.h"
+#include "RemoteState.h"
namespace android {
namespace automotive {
@@ -34,12 +36,12 @@
* Wrapper for IPC handle
*/
struct PipeRunner {
- explicit PipeRunner(const sp<android::automotive::computepipe::runner::IPipeRunner>& graphRunner);
- sp<android::automotive::computepipe::runner::IPipeRunner> runner;
+ explicit PipeRunner(
+ const std::shared_ptr<aidl::android::automotive::computepipe::runner::IPipeRunner>&
+ graphRunner);
+ std::shared_ptr<aidl::android::automotive::computepipe::runner::IPipeRunner> runner;
};
-class PipeMonitor;
-
/**
* Runner Handle to be stored with registry.
*
@@ -48,7 +50,8 @@
*/
class RunnerHandle : public android::automotive::computepipe::router::PipeHandle<PipeRunner> {
public:
- explicit RunnerHandle(const sp<android::automotive::computepipe::runner::IPipeRunner>& r);
+ explicit RunnerHandle(
+ const std::shared_ptr<aidl::android::automotive::computepipe::runner::IPipeRunner>& r);
/**
* override registry pipehandle methods
*/
@@ -58,28 +61,8 @@
~RunnerHandle();
private:
- /**
- * method used by monitor to report death
- */
- void markDead();
- bool mAlive = true;
- std::mutex mStateLock;
- // Instance of the monitor for the associated runner
- wp<PipeMonitor> mPipeMonitor;
-};
-
-/**
- * Monitors binder death notifications to handle death of the graph runner
- * process
- */
-class PipeMonitor : public IBinder::DeathRecipient {
- public:
- PipeMonitor(std::function<void()> cb) : mNotifier(cb) {
- }
- void binderDied(const wp<android::IBinder>& base) override;
-
- private:
- std::function<void()> mNotifier;
+ std::shared_ptr<RemoteState> mState;
+ ndk::ScopedAIBinder_DeathRecipient mDeathMonitor;
};
} // namespace implementation
diff --git a/computepipe/router/1.0/include/RemoteState.h b/computepipe/router/1.0/include/RemoteState.h
new file mode 100644
index 0000000..6fa34df
--- /dev/null
+++ b/computepipe/router/1.0/include/RemoteState.h
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_AUTOMOTIVE_COMPUTEPIPE_ROUTER_V1_0_REMOTESTATE
+#define ANDROID_AUTOMOTIVE_COMPUTEPIPE_ROUTER_V1_0_REMOTESTATE
+
+#include <utils/RefBase.h>
+
+#include <memory>
+#include <mutex>
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace router {
+namespace V1_0 {
+namespace implementation {
+
+/**
+ * Wrapper for the Runner State machine
+ */
+class RemoteState {
+ public:
+ RemoteState() = default;
+ void markDead();
+ bool isAlive();
+
+ private:
+ std::mutex mStateLock;
+ bool mAlive = true;
+};
+
+/**
+ * Monitor for tracking remote state
+ */
+class RemoteMonitor : public RefBase {
+ public:
+ explicit RemoteMonitor(const std::weak_ptr<RemoteState>& s) : mState(s) {
+ }
+ static void BinderDiedCallback(void* cookie);
+ void binderDied();
+
+ private:
+ std::weak_ptr<RemoteState> mState;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace router
+} // namespace computepipe
+} // namespace automotive
+} // namespace android
+#endif
diff --git a/computepipe/router/1.0/service.cpp b/computepipe/router/1.0/service.cpp
index c671d0f..6135836 100644
--- a/computepipe/router/1.0/service.cpp
+++ b/computepipe/router/1.0/service.cpp
@@ -1,5 +1,4 @@
-#include <binder/IPCThreadState.h>
-#include <binder/ProcessState.h>
+#include <android/binder_process.h>
#include <utils/Errors.h>
#include <utils/Log.h>
@@ -29,9 +28,9 @@
ALOGE("Bad Args");
exit(2);
}
- android::ProcessState::self()->startThreadPool();
+ ABinderProcess_startThreadPool();
std::thread registrationThread(startService);
- android::IPCThreadState::self()->joinThreadPool();
+ ABinderProcess_joinThreadPool();
ALOGE("Router thread joined IPC pool");
return 1;
}
diff --git a/computepipe/runner/Android.bp b/computepipe/runner/Android.bp
index 0007512..33684e7 100644
--- a/computepipe/runner/Android.bp
+++ b/computepipe/runner/Android.bp
@@ -18,5 +18,8 @@
static_libs: [
"libcomputepipeprotos",
],
- visibility:["//packages/services/Car/computepipe/runner:__subpackages__"],
+ visibility:[
+ "//packages/services/Car/computepipe/runner:__subpackages__",
+ "//packages/services/Car/computepipe/tests:__subpackages__",
+ ],
}
diff --git a/computepipe/runner/stream_manager/Android.bp b/computepipe/runner/stream_manager/Android.bp
new file mode 100644
index 0000000..70d98c5
--- /dev/null
+++ b/computepipe/runner/stream_manager/Android.bp
@@ -0,0 +1,35 @@
+// 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.
+
+cc_library {
+ name: "libcomputepipe_stream_manager",
+ srcs: [
+ "Factory.cpp",
+ "SemanticManager.cpp",
+ ],
+ export_include_dirs: ["include"],
+ visibility: [
+ "//packages/services/Car/computepipe/runner:__subpackages__",
+ "//packages/services/Car/computepipe/tests:__subpackages__",
+ ],
+ header_libs: [
+ "computepipe_runner_includes",
+ ],
+ static_libs: [
+ "libcomputepipeprotos",
+ ],
+ include_dirs: [
+ "packages/services/Car/computepipe",
+ ],
+}
diff --git a/computepipe/runner/stream_manager/Factory.cpp b/computepipe/runner/stream_manager/Factory.cpp
new file mode 100644
index 0000000..27fc442
--- /dev/null
+++ b/computepipe/runner/stream_manager/Factory.cpp
@@ -0,0 +1,43 @@
+// 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.
+
+#include "OutputConfig.pb.h"
+#include "SemanticManager.h"
+#include "StreamManager.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner {
+namespace stream_manager {
+
+std::unique_ptr<StreamManager> StreamManagerFactory::getStreamManager(
+ const proto::OutputConfig& config) {
+ if (!config.has_type()) {
+ return nullptr;
+ }
+ switch (config.type()) {
+ case proto::PacketType::SEMANTIC_DATA:
+ return std::make_unique<SemanticManager>(config.stream_name(), config.type());
+ default:
+ return nullptr;
+ }
+ return nullptr;
+}
+
+} // namespace stream_manager
+} // namespace runner
+} // namespace computepipe
+} // namespace automotive
+} // namespace android
diff --git a/computepipe/runner/stream_manager/SemanticManager.cpp b/computepipe/runner/stream_manager/SemanticManager.cpp
new file mode 100644
index 0000000..e9482d2
--- /dev/null
+++ b/computepipe/runner/stream_manager/SemanticManager.cpp
@@ -0,0 +1,133 @@
+#include "SemanticManager.h"
+
+#include <cstdlib>
+
+#include "types/Status.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner {
+namespace stream_manager {
+
+proto::PacketType SemanticHandle::getType() {
+ return mType;
+}
+
+uint64_t SemanticHandle::getTimeStamp() {
+ return mTimestamp;
+}
+
+uint32_t SemanticHandle::getSize() {
+ return mSize;
+}
+
+const char* SemanticHandle::getData() {
+ return mData;
+}
+
+native_handle_t SemanticHandle::getNativeHandle() {
+ native_handle_t temp;
+ temp.numFds = 0;
+ temp.numInts = 0;
+ return temp;
+}
+
+Status SemanticHandle::setMemInfo(const char* data, uint32_t size, uint64_t timestamp,
+ const proto::PacketType& type) {
+ if (data == nullptr || size == 0 || size > kMaxSemanticDataSize) {
+ return INVALID_ARGUMENT;
+ }
+ mData = (char*)malloc(size);
+ if (!mData) {
+ return NO_MEMORY;
+ }
+ memcpy(mData, data, size);
+ mType = type;
+ mTimestamp = timestamp;
+ mSize = size;
+ return SUCCESS;
+}
+
+/* Destroy local copy */
+SemanticHandle::~SemanticHandle() {
+ free(mData);
+}
+
+Status SemanticManager::setIpcDispatchCallback(
+ std::function<Status(const std::shared_ptr<MemHandle>)>& cb) {
+ mDispatchCallback = cb;
+ std::lock_guard<std::mutex> lock(mStateLock);
+ mState = RESET;
+ return SUCCESS;
+}
+
+// TODO: b/146495240 Add support for batching
+Status SemanticManager::setMaxInFlightPackets(uint32_t /* maxPackets */) {
+ if (!mDispatchCallback) {
+ return ILLEGAL_STATE;
+ }
+ mState = CONFIG_DONE;
+ return SUCCESS;
+}
+
+Status SemanticManager::start() {
+ std::lock_guard<std::mutex> lock(mStateLock);
+ if (mState != CONFIG_DONE) {
+ return ILLEGAL_STATE;
+ }
+ mState = RUNNING;
+ return SUCCESS;
+}
+
+Status SemanticManager::stop(bool /* flush */) {
+ std::lock_guard<std::mutex> lock(mStateLock);
+ if (mState != RUNNING) {
+ return ILLEGAL_STATE;
+ }
+ /*
+ * We skip directly to config_done as there is no outstanding cleanup
+ * required
+ */
+ mState = CONFIG_DONE;
+ return SUCCESS;
+}
+
+Status SemanticManager::cleanup() {
+ std::lock_guard<std::mutex> lock(mStateLock);
+ mState = RESET;
+ return SUCCESS;
+}
+
+Status SemanticManager::freePacket(const std::shared_ptr<MemHandle>& /* handle */) {
+ return SUCCESS;
+}
+
+Status SemanticManager::queuePacket(const char* data, const uint32_t size, uint64_t timestamp) {
+ std::lock_guard<std::mutex> lock(mStateLock);
+ // We drop the packet since we have received the stop notifications.
+ if (mState != RUNNING) {
+ return SUCCESS;
+ }
+ // Invalid state.
+ if (mDispatchCallback == nullptr) {
+ return INTERNAL_ERROR;
+ }
+ auto memHandle = std::make_shared<SemanticHandle>();
+ auto status = memHandle->setMemInfo(data, size, timestamp, mType);
+ if (status != SUCCESS) {
+ return status;
+ }
+ mDispatchCallback(memHandle);
+ return SUCCESS;
+}
+
+SemanticManager::SemanticManager(std::string name, const proto::PacketType& type)
+ : StreamManager(name, type) {
+}
+
+} // namespace stream_manager
+} // namespace runner
+} // namespace computepipe
+} // namespace automotive
+} // namespace android
diff --git a/computepipe/runner/stream_manager/SemanticManager.h b/computepipe/runner/stream_manager/SemanticManager.h
new file mode 100644
index 0000000..8a7cf94
--- /dev/null
+++ b/computepipe/runner/stream_manager/SemanticManager.h
@@ -0,0 +1,81 @@
+// 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.
+
+#ifndef COMPUTEPIPE_RUNNER_STREAM_MANAGER_SEMANTIC_MANAGER_H
+#define COMPUTEPIPE_RUNNER_STREAM_MANAGER_SEMANTIC_MANAGER_H
+
+#include <mutex>
+
+#include "OutputConfig.pb.h"
+#include "StreamManager.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner {
+namespace stream_manager {
+
+class SemanticHandle : public MemHandle {
+ public:
+ static constexpr uint32_t kMaxSemanticDataSize = 1024;
+ proto::PacketType getType() override;
+ /* Retrieve packet time stamp */
+ uint64_t getTimeStamp() override;
+ /* Get size */
+ uint32_t getSize() override;
+ /* Get data, raw pointer. Only implemented for copy semantics */
+ const char* getData() override;
+ /* Get native handle. data with zero copy semantics */
+ native_handle_t getNativeHandle() override;
+ /* set info for the memory. Make a copy */
+ Status setMemInfo(const char* data, uint32_t size, uint64_t timestamp,
+ const proto::PacketType& type);
+ /* Destroy local copy */
+ ~SemanticHandle();
+
+ private:
+ char* mData = nullptr;
+ uint32_t mSize;
+ uint64_t mTimestamp;
+ proto::PacketType mType;
+};
+
+class SemanticManager : public StreamManager {
+ public:
+ Status setIpcDispatchCallback(
+ std::function<Status(const std::shared_ptr<MemHandle>)>& cb) override;
+ /* Set Max in flight packets based on client specification */
+ Status setMaxInFlightPackets(uint32_t maxPackets) override;
+ /* Start stream manager */
+ Status start() override;
+ /* Stop stream manager */
+ Status stop(bool flush) override;
+ /* initiate cleanup. Forget maxinflightPackets */
+ Status cleanup() override;
+ /* Free previously dispatched packet. Once client has confirmed usage */
+ Status freePacket(const std::shared_ptr<MemHandle>& memhandle) override;
+ /* Queue packet produced by graph stream */
+ Status queuePacket(const char* data, const uint32_t size, uint64_t timestamp) override;
+ explicit SemanticManager(std::string name, const proto::PacketType& type);
+
+ private:
+ std::mutex mStateLock;
+ std::function<Status(const std::shared_ptr<MemHandle>&)> mDispatchCallback = nullptr;
+};
+} // namespace stream_manager
+} // namespace runner
+} // namespace computepipe
+} // namespace automotive
+} // namespace android
+#endif
diff --git a/computepipe/runner/stream_manager/include/StreamManager.h b/computepipe/runner/stream_manager/include/StreamManager.h
new file mode 100644
index 0000000..e6aaad2
--- /dev/null
+++ b/computepipe/runner/stream_manager/include/StreamManager.h
@@ -0,0 +1,105 @@
+// 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.
+
+#ifndef COMPUTEPIPE_RUNNER_STREAM_MANAGER_H
+#define COMPUTEPIPE_RUNNER_STREAM_MANAGER_H
+
+#include <functional>
+#include <memory>
+#include <string>
+
+#include "MemHandle.h"
+#include "OutputConfig.pb.h"
+#include "types/Status.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner {
+namespace stream_manager {
+
+/**
+ * Manager the operations of an output stream from the graph.
+ * Should be constructed using the StreamManagerFactory.
+ * The manager instance for a given stream depends on the streams
+ * description specified in OuputConfig.
+ */
+
+class StreamManager {
+ public:
+ enum State {
+ /* State on construction. */
+ RESET = 0,
+ /* State once inflight packets set */
+ CONFIG_DONE = 1,
+ /* State once packets are */
+ RUNNING = 2,
+ /**
+ * State once stop issued
+ * Returns to config done, once all in flight packets handled.
+ */
+ STOPPED = 3,
+ };
+ /* Constructor for StreamManager Base class */
+ explicit StreamManager(std::string streamName, const proto::PacketType& type)
+ : mName(streamName), mType(type) {
+ }
+ /**
+ * IPC dispatch routine invoked by Stream manager, to send output packet to client.
+ * Callback must be set before any client specific configs are applied.
+ */
+ virtual Status setIpcDispatchCallback(std::function<Status(std::shared_ptr<MemHandle>)>& cb) = 0;
+ /* Retrieves the current state */
+ State getState() {
+ return mState;
+ }
+ /* Sets max in flight packets based on client specification */
+ virtual Status setMaxInFlightPackets(uint32_t maxPackets) = 0;
+ /* Starts stream manager */
+ virtual Status start() = 0;
+ /* Stops stream manager */
+ virtual Status stop(bool flush) = 0;
+ /* Initiates cleanup. Forgets maxinflightPackets */
+ virtual Status cleanup() = 0;
+ /* Frees previously dispatched packet. Once client has confirmed usage */
+ virtual Status freePacket(const std::shared_ptr<MemHandle>& memhandle) = 0;
+ /* Queue's packet produced by graph stream */
+ virtual Status queuePacket(const char* data, const uint32_t size, uint64_t timestamp) = 0;
+ /* Destructor */
+ virtual ~StreamManager() = default;
+
+ protected:
+ std::string mName;
+ proto::PacketType mType;
+ State mState = RESET;
+};
+
+/**
+ * Factory for generating stream manager instances
+ */
+class StreamManagerFactory {
+ public:
+ std::unique_ptr<StreamManager> getStreamManager(const proto::OutputConfig& config);
+ StreamManagerFactory(const StreamManagerFactory&) = delete;
+ StreamManagerFactory& operator=(const StreamManagerFactory&) = delete;
+ StreamManagerFactory() = default;
+};
+
+} // namespace stream_manager
+} // namespace runner
+} // namespace computepipe
+} // namespace automotive
+} // namespace android
+
+#endif
diff --git a/computepipe/runner/utils/Android.bp b/computepipe/runner/utils/Android.bp
index b820de0..74c6656 100644
--- a/computepipe/runner/utils/Android.bp
+++ b/computepipe/runner/utils/Android.bp
@@ -35,11 +35,14 @@
"liblog",
"libutils",
"android.automotive.computepipe.runner-ndk_platform",
+ "android.automotive.computepipe.registry-ndk_platform",
"libprotobuf-cpp-lite",
],
visibility:["//packages/services/Car/computepipe/runner:__subpackages__"],
srcs: [
+ "InterfaceImpl.cc",
+ "PipeOptionsConverter.cc",
"RunnerInterface.cc",
],
}
diff --git a/computepipe/runner/utils/DebuggerInterface.cc b/computepipe/runner/utils/DebuggerInterface.cc
new file mode 100644
index 0000000..66556da
--- /dev/null
+++ b/computepipe/runner/utils/DebuggerInterface.cc
@@ -0,0 +1,13 @@
+// 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.
diff --git a/computepipe/runner/utils/InterfaceImpl.cc b/computepipe/runner/utils/InterfaceImpl.cc
new file mode 100644
index 0000000..245e59b
--- /dev/null
+++ b/computepipe/runner/utils/InterfaceImpl.cc
@@ -0,0 +1,234 @@
+// 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.c
+
+#define LOG_TAG "RunnerIpcInterface"
+
+#include "InterfaceImpl.h"
+
+#include <android-base/logging.h>
+#include "PacketDescriptor.pb.h"
+#include "PipeOptionsConverter.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner_utils {
+namespace {
+
+using ::aidl::android::automotive::computepipe::runner::IPipeStateCallback;
+using ::aidl::android::automotive::computepipe::runner::IPipeStream;
+using ::aidl::android::automotive::computepipe::runner::PipeDescriptor;
+using ::aidl::android::automotive::computepipe::runner::PipeState;
+using ::ndk::ScopedAStatus;
+
+ScopedAStatus ToNdkStatus(Status status) {
+ switch (status) {
+ case SUCCESS:
+ return ScopedAStatus::ok();
+ case INTERNAL_ERROR:
+ return ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED);
+ case INVALID_ARGUMENT:
+ return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ case FATAL_ERROR:
+ default:
+ return ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED);
+ }
+}
+
+PipeState ToAidlState(GraphState state) {
+ switch (state) {
+ case RESET:
+ return PipeState::RESET;
+ case CONFIG_DONE:
+ return PipeState::CONFIG_DONE;
+ case RUNNING:
+ return PipeState::RUNNING;
+ case DONE:
+ return PipeState::DONE;
+ case ERR_HALT:
+ default:
+ return PipeState::ERR_HALT;
+ }
+}
+
+void deathNotifier(void* cookie) {
+ InterfaceImpl* iface = static_cast<InterfaceImpl*>(cookie);
+ iface->clientDied();
+}
+
+} // namespace
+
+// Thread-safe function to deliver new packets to client.
+Status InterfaceImpl::newPacketNotification(int32_t streamId,
+ const std::shared_ptr<MemHandle>& packetHandle) {
+ // TODO(146464279) implement.
+ (void)packetHandle;
+ return Status::SUCCESS;
+}
+
+Status InterfaceImpl::stateUpdateNotification(const GraphState newState) {
+ (void)mClientStateChangeCallback->handleState(ToAidlState(newState));
+ return Status::SUCCESS;
+}
+
+ScopedAStatus InterfaceImpl::getPipeDescriptor(PipeDescriptor* _aidl_return) {
+ if (_aidl_return == nullptr) {
+ return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ *_aidl_return = OptionsToPipeDesciptor(mGraphOptions);
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus InterfaceImpl::setPipeInputSource(int32_t configId) {
+ if (!isClientInitDone()) {
+ return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+ }
+
+ proto::ConfigurationCommand configurationCommand;
+ configurationCommand.mutable_set_input_source()->set_source_id(configId);
+
+ Status status = mRunnerInterfaceCallbacks.mProcessConfigurationCommand(configurationCommand);
+ return ToNdkStatus(status);
+}
+
+ScopedAStatus InterfaceImpl::setPipeOffloadOptions(int32_t configId) {
+ if (!isClientInitDone()) {
+ return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+ }
+
+ proto::ConfigurationCommand configurationCommand;
+ configurationCommand.mutable_set_offload_offload()->set_offload_option_id(configId);
+
+ Status status = mRunnerInterfaceCallbacks.mProcessConfigurationCommand(configurationCommand);
+ return ToNdkStatus(status);
+}
+
+ScopedAStatus InterfaceImpl::setPipeTermination(int32_t configId) {
+ if (!isClientInitDone()) {
+ return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+ }
+
+ proto::ConfigurationCommand configurationCommand;
+ configurationCommand.mutable_set_termination_option()->set_termination_option_id(configId);
+
+ Status status = mRunnerInterfaceCallbacks.mProcessConfigurationCommand(configurationCommand);
+ return ToNdkStatus(status);
+}
+
+ScopedAStatus InterfaceImpl::init(const std::shared_ptr<IPipeStateCallback>& stateCb) {
+ if (isClientInitDone()) {
+ return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+ }
+
+ AIBinder_DeathRecipient* recipient = AIBinder_DeathRecipient_new(&deathNotifier);
+ AIBinder_linkToDeath(stateCb->asBinder().get(), recipient, this);
+
+ mClientStateChangeCallback = stateCb;
+ return ScopedAStatus::ok();
+}
+
+bool InterfaceImpl::isClientInitDone() {
+ if (mClientStateChangeCallback == nullptr) {
+ return false;
+ }
+ return true;
+}
+
+void InterfaceImpl::clientDied() {
+ LOG(INFO) << "Client has died";
+ releaseRunner();
+}
+
+ScopedAStatus InterfaceImpl::setPipeOutputConfig(int32_t streamId, int32_t maxInFlightCount,
+ const std::shared_ptr<IPipeStream>& handler) {
+ if (!isClientInitDone()) {
+ return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+ }
+
+ if (mPacketHandlers.find(streamId) != mPacketHandlers.end()) {
+ LOG(INFO) << "Handler for stream id " << streamId
+ << " has already"
+ " been registered.";
+ return ToNdkStatus(INVALID_ARGUMENT);
+ }
+
+ mPacketHandlers.insert(std::pair<int, std::shared_ptr<IPipeStream>>(streamId, handler));
+
+ proto::ConfigurationCommand configurationCommand;
+ configurationCommand.mutable_set_output_stream()->set_stream_id(streamId);
+ configurationCommand.mutable_set_output_stream()->set_max_inflight_packets_count(
+ maxInFlightCount);
+ Status status = mRunnerInterfaceCallbacks.mProcessConfigurationCommand(configurationCommand);
+
+ if (status != SUCCESS) {
+ LOG(INFO) << "Failed to register handler for stream id " << streamId;
+ mPacketHandlers.erase(streamId);
+ }
+ return ToNdkStatus(status);
+}
+
+ScopedAStatus InterfaceImpl::applyPipeConfigs() {
+ if (!isClientInitDone()) {
+ return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+ }
+
+ proto::ControlCommand controlCommand;
+ *controlCommand.mutable_apply_configs() = proto::ApplyConfigs();
+
+ Status status = mRunnerInterfaceCallbacks.mProcessControlCommand(controlCommand);
+ return ToNdkStatus(status);
+}
+
+ScopedAStatus InterfaceImpl::startPipe() {
+ proto::ControlCommand controlCommand;
+ *controlCommand.mutable_start_graph() = proto::StartGraph();
+
+ Status status = mRunnerInterfaceCallbacks.mProcessControlCommand(controlCommand);
+ return ToNdkStatus(status);
+}
+
+ScopedAStatus InterfaceImpl::stopPipe() {
+ proto::ControlCommand controlCommand;
+ *controlCommand.mutable_stop_graph() = proto::StopGraph();
+
+ Status status = mRunnerInterfaceCallbacks.mProcessControlCommand(controlCommand);
+ return ToNdkStatus(status);
+}
+
+ScopedAStatus InterfaceImpl::doneWithPacket(int32_t id) {
+ // TODO(146464279) implement.
+ return ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus InterfaceImpl::getPipeDebugger(
+ std::shared_ptr<aidl::android::automotive::computepipe::runner::IPipeDebugger>* _aidl_return) {
+ // TODO(146464281) implement.
+ return ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus InterfaceImpl::releaseRunner() {
+ proto::ControlCommand controlCommand;
+ *controlCommand.mutable_death_notification() = proto::DeathNotification();
+
+ Status status = mRunnerInterfaceCallbacks.mProcessControlCommand(controlCommand);
+
+ mClientStateChangeCallback = nullptr;
+ mPacketHandlers.clear();
+ return ToNdkStatus(status);
+}
+
+} // namespace runner_utils
+} // namespace computepipe
+} // namespace automotive
+} // namespace android
diff --git a/computepipe/runner/utils/InterfaceImpl.h b/computepipe/runner/utils/InterfaceImpl.h
new file mode 100644
index 0000000..26684c2
--- /dev/null
+++ b/computepipe/runner/utils/InterfaceImpl.h
@@ -0,0 +1,97 @@
+// 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.
+
+#ifndef COMPUTEPIPE_RUNNER_UTILS_INTERFACEIMPL_H_
+#define COMPUTEPIPE_RUNNER_UTILS_INTERFACEIMPL_H_
+#include <aidl/android/automotive/computepipe/runner/BnPipeRunner.h>
+
+#include <map>
+#include <memory>
+#include <string>
+
+#include "RunnerInterfaceCallbacks.h"
+#include "MemHandle.h"
+#include "types/GraphState.h"
+#include "types/Status.h"
+
+#include "Options.pb.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner_utils {
+
+// RunnerInterface registers an IPipeRunner interface with computepipe router.
+// RunnerInterface handles binder IPC calls and invokes appropriate callbacks.
+class InterfaceImpl : public aidl::android::automotive::computepipe::runner::BnPipeRunner {
+ public:
+ explicit InterfaceImpl(const proto::Options graphOptions,
+ const RunnerInterfaceCallbacks& runnerInterfaceCallbacks)
+ : mGraphOptions(graphOptions), mRunnerInterfaceCallbacks(runnerInterfaceCallbacks) {
+ }
+
+ ~InterfaceImpl() {
+ }
+
+ Status newPacketNotification(int32_t streamId, const std::shared_ptr<MemHandle>& packetHandle);
+
+ Status stateUpdateNotification(const GraphState newState);
+
+ // Methods from android::automotive::computepipe::runner::BnPipeRunner
+ ndk::ScopedAStatus init(
+ const std::shared_ptr<aidl::android::automotive::computepipe::runner::IPipeStateCallback>&
+ stateCb) override;
+ ndk::ScopedAStatus getPipeDescriptor(
+ aidl::android::automotive::computepipe::runner::PipeDescriptor* _aidl_return) override;
+ ndk::ScopedAStatus setPipeInputSource(int32_t configId) override;
+ ndk::ScopedAStatus setPipeOffloadOptions(int32_t configId) override;
+ ndk::ScopedAStatus setPipeTermination(int32_t configId) override;
+ ndk::ScopedAStatus setPipeOutputConfig(
+ int32_t streamId, int32_t maxInFlightCount,
+ const std::shared_ptr<aidl::android::automotive::computepipe::runner::IPipeStream>& handler)
+ override;
+ ndk::ScopedAStatus applyPipeConfigs() override;
+ ndk::ScopedAStatus startPipe() override;
+ ndk::ScopedAStatus stopPipe() override;
+ ndk::ScopedAStatus doneWithPacket(int32_t id) override;
+
+ ndk::ScopedAStatus getPipeDebugger(
+ std::shared_ptr<aidl::android::automotive::computepipe::runner::IPipeDebugger>* _aidl_return)
+ override;
+
+ ndk::ScopedAStatus releaseRunner() override;
+
+ void clientDied();
+
+ private:
+ const proto::Options mGraphOptions;
+ const RunnerInterfaceCallbacks& mRunnerInterfaceCallbacks;
+
+ bool isClientInitDone();
+
+ // If value of mClientStateChangeCallback is null pointer, client has not
+ // invoked init.
+ std::shared_ptr<aidl::android::automotive::computepipe::runner::IPipeStateCallback>
+ mClientStateChangeCallback = nullptr;
+
+ std::map<int, std::shared_ptr<aidl::android::automotive::computepipe::runner::IPipeStream>>
+ mPacketHandlers;
+};
+
+} // namespace runner_utils
+} // namespace computepipe
+} // namespace automotive
+} // namespace android
+
+#endif // COMPUTEPIPE_RUNNER_UTILS_INTERFACEIMPL_H_
diff --git a/computepipe/runner/utils/PipeOptionsConverter.cc b/computepipe/runner/utils/PipeOptionsConverter.cc
new file mode 100644
index 0000000..e117251
--- /dev/null
+++ b/computepipe/runner/utils/PipeOptionsConverter.cc
@@ -0,0 +1,172 @@
+// 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.
+
+#include "PipeOptionsConverter.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner_utils {
+
+using ::aidl::android::automotive::computepipe::runner::PipeDescriptor;
+using ::aidl::android::automotive::computepipe::runner::PipeInputConfig;
+using ::aidl::android::automotive::computepipe::runner::PipeInputConfigFormatType;
+using ::aidl::android::automotive::computepipe::runner::PipeInputConfigInputType;
+using ::aidl::android::automotive::computepipe::runner::PipeOffloadConfig;
+using ::aidl::android::automotive::computepipe::runner::PipeOffloadConfigOffloadType;
+using ::aidl::android::automotive::computepipe::runner::PipeOutputConfig;
+using ::aidl::android::automotive::computepipe::runner::PipeOutputConfigPacketType;
+using ::aidl::android::automotive::computepipe::runner::PipeTerminationConfig;
+using ::aidl::android::automotive::computepipe::runner::PipeTerminationConfigTerminationType;
+
+namespace {
+
+PipeInputConfigInputType ConvertInputType(proto::InputConfig_InputType type) {
+ switch (type) {
+ case proto::InputConfig_InputType_DRIVER_VIEW_CAMERA:
+ return PipeInputConfigInputType::DRIVER_VIEW_CAMERA;
+ case proto::InputConfig_InputType_OCCUPANT_VIEW_CAMERA:
+ return PipeInputConfigInputType::OCCUPANT_VIEW_CAMERA;
+ case proto::InputConfig_InputType_EXTERNAL_CAMERA:
+ return PipeInputConfigInputType::EXTERNAL_CAMERA;
+ case proto::InputConfig_InputType_SURROUND_VIEW_CAMERA:
+ return PipeInputConfigInputType::SURROUND_VIEW_CAMERA;
+ case proto::InputConfig_InputType_VIDEO_FILE:
+ return PipeInputConfigInputType::VIDEO_FILE;
+ }
+}
+
+PipeInputConfigFormatType ConvertInputFormat(proto::InputConfig_FormatType type) {
+ switch (type) {
+ case proto::InputConfig_FormatType_RGB:
+ return PipeInputConfigFormatType::RGB;
+ case proto::InputConfig_FormatType_NIR:
+ return PipeInputConfigFormatType::NIR;
+ case proto::InputConfig_FormatType_NIR_DEPTH:
+ return PipeInputConfigFormatType::NIR_DEPTH;
+ }
+}
+
+PipeOffloadConfigOffloadType ConvertOffloadType(proto::OffloadOption_OffloadType type) {
+ switch (type) {
+ case proto::OffloadOption_OffloadType_CPU:
+ return PipeOffloadConfigOffloadType::CPU;
+ case proto::OffloadOption_OffloadType_GPU:
+ return PipeOffloadConfigOffloadType::GPU;
+ case proto::OffloadOption_OffloadType_NEURAL_ENGINE:
+ return PipeOffloadConfigOffloadType::NEURAL_ENGINE;
+ case proto::OffloadOption_OffloadType_CV_ENGINE:
+ return PipeOffloadConfigOffloadType::CV_ENGINE;
+ }
+}
+
+PipeOutputConfigPacketType ConvertOutputType(proto::PacketType type) {
+ switch (type) {
+ case proto::PacketType::SEMANTIC_DATA:
+ return PipeOutputConfigPacketType::SEMANTIC_DATA;
+ case proto::PacketType::PIXEL_DATA:
+ return PipeOutputConfigPacketType::PIXEL_DATA;
+ case proto::PacketType::PIXEL_ZERO_COPY_DATA:
+ return PipeOutputConfigPacketType::PIXEL_ZERO_COPY_DATA;
+ }
+}
+
+PipeTerminationConfigTerminationType ConvertTerminationType(
+ proto::TerminationOption_TerminationType type) {
+ switch (type) {
+ case proto::TerminationOption_TerminationType_CLIENT_STOP:
+ return PipeTerminationConfigTerminationType::CLIENT_STOP;
+ case proto::TerminationOption_TerminationType_MIN_PACKET_COUNT:
+ return PipeTerminationConfigTerminationType::MIN_PACKET_COUNT;
+ case proto::TerminationOption_TerminationType_MAX_RUN_TIME:
+ return PipeTerminationConfigTerminationType::MAX_RUN_TIME;
+ case proto::TerminationOption_TerminationType_EVENT:
+ return PipeTerminationConfigTerminationType::EVENT;
+ }
+}
+
+PipeInputConfig ConvertInputConfigProto(proto::InputConfig proto) {
+ PipeInputConfig aidlConfig;
+ aidlConfig.options.type = ConvertInputType(proto.type());
+ aidlConfig.options.format = ConvertInputFormat(proto.format());
+ aidlConfig.options.width = proto.width();
+ aidlConfig.options.height = proto.height();
+ aidlConfig.options.stride = proto.stride();
+ aidlConfig.options.camId = proto.cam_id();
+ aidlConfig.configId = proto.config_id();
+ return aidlConfig;
+}
+
+PipeOffloadConfig ConvertOffloadConfigProto(proto::OffloadConfig proto) {
+ PipeOffloadConfig aidlConfig;
+
+ for (int i = 0; i < proto.options().offload_types_size(); i++) {
+ auto offloadType =
+ static_cast<proto::OffloadOption_OffloadType>(proto.options().offload_types()[i]);
+ PipeOffloadConfigOffloadType aidlType = ConvertOffloadType(offloadType);
+ aidlConfig.options.type.emplace_back(aidlType);
+ aidlConfig.options.isVirtual.emplace_back(proto.options().is_virtual()[i]);
+ }
+
+ aidlConfig.configId = proto.config_id();
+ return aidlConfig;
+}
+
+PipeOutputConfig ConvertOutputConfigProto(proto::OutputConfig proto) {
+ PipeOutputConfig aidlConfig;
+ aidlConfig.output.name = proto.stream_name();
+ aidlConfig.output.type = ConvertOutputType(proto.type());
+ aidlConfig.outputId = proto.stream_id();
+ return aidlConfig;
+}
+
+PipeTerminationConfig ConvertTerminationConfigProto(proto::TerminationConfig proto) {
+ PipeTerminationConfig aidlConfig;
+ aidlConfig.options.type = ConvertTerminationType(proto.options().type());
+ aidlConfig.options.qualifier = proto.options().qualifier();
+ aidlConfig.configId = proto.config_id();
+ return aidlConfig;
+}
+
+} // namespace
+
+PipeDescriptor OptionsToPipeDesciptor(proto::Options options) {
+ PipeDescriptor desc;
+ for (int i = 0; i < options.input_configs_size(); i++) {
+ PipeInputConfig inputConfig = ConvertInputConfigProto(options.input_configs()[i]);
+ desc.inputConfig.emplace_back(inputConfig);
+ }
+
+ for (int i = 0; i < options.offload_configs_size(); i++) {
+ PipeOffloadConfig offloadConfig = ConvertOffloadConfigProto(options.offload_configs()[i]);
+ desc.offloadConfig.emplace_back(offloadConfig);
+ }
+
+ for (int i = 0; i < options.termination_configs_size(); i++) {
+ PipeTerminationConfig terminationConfig =
+ ConvertTerminationConfigProto(options.termination_configs()[i]);
+ desc.terminationConfig.emplace_back(terminationConfig);
+ }
+
+ for (int i = 0; i < options.output_configs_size(); i++) {
+ PipeOutputConfig outputConfig = ConvertOutputConfigProto(options.output_configs()[i]);
+ desc.outputConfig.emplace_back(outputConfig);
+ }
+ return desc;
+}
+
+} // namespace runner_utils
+} // namespace computepipe
+} // namespace automotive
+} // namespace android
diff --git a/computepipe/runner/utils/PipeOptionsConverter.h b/computepipe/runner/utils/PipeOptionsConverter.h
new file mode 100644
index 0000000..dc44eb1
--- /dev/null
+++ b/computepipe/runner/utils/PipeOptionsConverter.h
@@ -0,0 +1,35 @@
+// 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.
+
+#ifndef COMPUTEPIPE_RUNNER_UTILS_PIPEOPTIONSCONVERTER_H_
+#define COMPUTEPIPE_RUNNER_UTILS_PIPEOPTIONSCONVERTER_H_
+
+#include <aidl/android/automotive/computepipe/runner/BnPipeRunner.h>
+
+#include "Options.pb.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner_utils {
+
+aidl::android::automotive::computepipe::runner::PipeDescriptor OptionsToPipeDesciptor(
+ proto::Options options);
+
+} // namespace runner_utils
+} // namespace computepipe
+} // namespace automotive
+} // namespace android
+
+#endif // COMPUTEPIPE_RUNNER_UTILS_PIPEOPTIONSCONVERTER_H_
diff --git a/computepipe/runner/utils/RunnerInterface.cc b/computepipe/runner/utils/RunnerInterface.cc
index 4724092..66c2bea 100644
--- a/computepipe/runner/utils/RunnerInterface.cc
+++ b/computepipe/runner/utils/RunnerInterface.cc
@@ -12,13 +12,106 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#define LOG_TAG "RunnerIpcInterface"
+
#include "RunnerInterface.h"
+#include <thread>
+
+#include <aidl/android/automotive/computepipe/registry/IPipeRegistration.h>
+#include <android/binder_manager.h>
+#include <android-base/logging.h>
+
namespace android {
namespace automotive {
namespace computepipe {
namespace runner_utils {
+using ::aidl::android::automotive::computepipe::registry::IPipeRegistration;
+using ::ndk::ScopedAStatus;
+
+namespace {
+const char kRegistryInterfaceName[] = "router";
+
+void deathNotifier(void* cookie) {
+ RunnerInterface* runnerIface = static_cast<RunnerInterface*>(cookie);
+ runnerIface->routerDied();
+}
+
+} // namespace
+
+Status RunnerInterface::init() {
+ if (mPipeRunner) {
+ return Status::INVALID_ARGUMENT;
+ }
+
+ mPipeRunner = std::make_shared<InterfaceImpl>(mGraphOptions, mRunnerInterfaceCallbacks);
+ std::thread t(&RunnerInterface::tryRegisterPipeRunner, this);
+ t.detach();
+ return Status::SUCCESS;
+}
+
+bool RunnerInterface::tryRegisterPipeRunner() {
+ if (!mPipeRunner) {
+ LOG(ERROR) << "Init must be called before attempting to connect to router.";
+ return false;
+ }
+
+ const std::string instanceName =
+ std::string() + IPipeRegistration::descriptor + "/" + kRegistryInterfaceName;
+
+ for (int i =0; i < mMaxRouterConnectionAttempts; i++) {
+ if (i != 0) {
+ sleep(mRouterConnectionAttemptIntervalSeconds);
+ }
+
+ ndk::SpAIBinder binder(AServiceManager_getService(instanceName.c_str()));
+ if (binder.get() == nullptr) {
+ LOG(ERROR) << "Failed to connect to router service";
+ continue;
+ }
+
+ // Connected to router registry, register the runner and dealth callback.
+ std::shared_ptr<IPipeRegistration> registryService = IPipeRegistration::fromBinder(binder);
+ ndk::ScopedAStatus status =
+ registryService->registerPipeRunner(mGraphOptions.graph_name().c_str(), mPipeRunner);
+
+ if (!status.isOk()) {
+ LOG(ERROR) << "Failed to register runner instance at router registy.";
+ continue;
+ }
+
+ AIBinder_DeathRecipient* recipient = AIBinder_DeathRecipient_new(&deathNotifier);
+ AIBinder_linkToDeath(registryService->asBinder().get(), recipient, this);
+ LOG(ERROR) << "Runner was registered at router registry.";
+ return true;
+ }
+
+ LOG(ERROR) << "Max connection attempts reached, router connection attempts failed.";
+ return false;
+}
+
+void RunnerInterface::routerDied() {
+ std::thread t(&RunnerInterface::tryRegisterPipeRunner, this);
+ t.detach();
+}
+
+// Thread-safe function to deliver new packets to client.
+Status RunnerInterface::newPacketNotification(int32_t streamId,
+ const std::shared_ptr<MemHandle>& packetHandle) {
+ if (!mPipeRunner) {
+ return Status::INVALID_ARGUMENT;
+ }
+ return mPipeRunner->newPacketNotification(streamId, packetHandle);
+}
+
+Status RunnerInterface::stateUpdateNotification(const GraphState newState) {
+ if (!mPipeRunner) {
+ return Status::INVALID_ARGUMENT;
+ }
+ return mPipeRunner->stateUpdateNotification(newState);
+}
+
} // namespace runner_utils
} // namespace computepipe
} // namespace automotive
diff --git a/computepipe/runner/utils/RunnerInterface.h b/computepipe/runner/utils/RunnerInterface.h
index bc6856e..2397628 100644
--- a/computepipe/runner/utils/RunnerInterface.h
+++ b/computepipe/runner/utils/RunnerInterface.h
@@ -16,13 +16,16 @@
#define COMPUTEPIPE_RUNNER_UTILS_RUNNERINTERFACE_H_
#include <aidl/android/automotive/computepipe/runner/BnPipeRunner.h>
+#include <memory>
#include <string>
-#include "MemHandle.h"
+#include "InterfaceImpl.h"
#include "RunnerInterfaceCallbacks.h"
#include "types/GraphState.h"
#include "types/Status.h"
+#include "Options.pb.h"
+
namespace android {
namespace automotive {
namespace computepipe {
@@ -30,47 +33,40 @@
// RunnerInterface registers an IPipeRunner interface with computepipe router.
// RunnerInterface handles binder IPC calls and invokes appropriate callbacks.
-class RunnerInterface : public aidl::android::automotive::computepipe::runner::BnPipeRunner {
+class RunnerInterface {
public:
- explicit RunnerInterface(const std::string& graphName,
+ explicit RunnerInterface(const proto::Options graphOptions,
const RunnerInterfaceCallbacks& runnerInterfaceCallbacks)
- : mGraphName(graphName), mRunnerInterfaceCallbacks(runnerInterfaceCallbacks) {
+ : mGraphOptions(graphOptions), mRunnerInterfaceCallbacks(runnerInterfaceCallbacks) {
}
- // Init() should be invoked when the process is ready to receive commands
+ ~RunnerInterface() {
+ }
+
+ // init() should be invoked when the process is ready to receive commands
// from Clients.
- Status Init();
+ Status init();
// Thread-safe function to deliver new packets to client.
- Status NewPacketNotification(int32_t streamId, const std::shared_ptr<MemHandle>& packetHandle);
+ Status newPacketNotification(int32_t streamId, const std::shared_ptr<MemHandle>& packetHandle);
// Thread-safe function to notify clients of new state.
- Status StateUpdateNotification(const GraphState newState);
+ Status stateUpdateNotification(const GraphState newState);
- // Methods from android::automotive::computepipe::runner::BnPipeRunner
- ndk::ScopedAStatus init(
- const std::shared_ptr<aidl::android::automotive::computepipe::runner::IPipeStateCallback>&
- stateCb) override;
- ndk::ScopedAStatus getPipeDescriptor(
- aidl::android::automotive::computepipe::runner::PipeDescriptor* _aidl_return) override;
- ndk::ScopedAStatus setPipeInputSource(int32_t configId) override;
- ndk::ScopedAStatus setPipeOffloadOptions(int32_t configId) override;
- ndk::ScopedAStatus setPipeTermination(int32_t configId) override;
- ndk::ScopedAStatus setPipeOutputConfig(
- int32_t streamId, int32_t maxInFlightCount,
- const std::shared_ptr<aidl::android::automotive::computepipe::runner::IPipeStream>& handler)
- override;
- ndk::ScopedAStatus applyPipeConfigs() override;
- ndk::ScopedAStatus startPipe() override;
- ndk::ScopedAStatus stopPipe() override;
- ndk::ScopedAStatus doneWithPacket(int32_t id) override;
+ void routerDied();
private:
- std::string mGraphName;
- const RunnerInterfaceCallbacks& mRunnerInterfaceCallbacks;
+ // Attempt to register pipe runner with router. Returns true on success.
+ // This is a blocking API, calling thread will be blocked until router connection is
+ // established or max attempts are made without success.
+ bool tryRegisterPipeRunner();
- std::map<int, std::shared_ptr<aidl::android::automotive::computepipe::runner::IPipeStateCallback>>
- mPacketHandlers;
+ const int mMaxRouterConnectionAttempts = 10;
+ const int mRouterConnectionAttemptIntervalSeconds = 2;
+
+ const proto::Options mGraphOptions;
+ const RunnerInterfaceCallbacks mRunnerInterfaceCallbacks;
+ std::shared_ptr<InterfaceImpl> mPipeRunner = nullptr;
};
} // namespace runner_utils
diff --git a/computepipe/runner/utils/RunnerInterfaceCallbacks.h b/computepipe/runner/utils/RunnerInterfaceCallbacks.h
index b3e29f6..f2f8ece 100644
--- a/computepipe/runner/utils/RunnerInterfaceCallbacks.h
+++ b/computepipe/runner/utils/RunnerInterfaceCallbacks.h
@@ -16,12 +16,12 @@
#define COMPUTEPIPE_RUNNER_UTILS_RUNNERINTERFACECALLBACKS_H_
#include <functional>
+#include <memory>
#include <string>
#include "ConfigurationCommand.pb.h"
#include "ControlCommand.pb.h"
#include "MemHandle.h"
-#include "RunnerInterface.h"
#include "types/Status.h"
namespace android {
@@ -32,12 +32,12 @@
struct RunnerInterfaceCallbacks {
explicit RunnerInterfaceCallbacks(
std::function<Status(const proto::ControlCommand&)> processControlCommand,
- std::function<Status(const proto::ConfigurationCommand&)>
- processConfigurationCommand,
- std::function<Status(const std::shared_ptr<MemHandle>&)> releasePacket) :
- mProcessControlCommand(processControlCommand),
- mProcessConfigurationCommand(processConfigurationCommand),
- mReleasePacket(releasePacket) {}
+ std::function<Status(const proto::ConfigurationCommand&)> processConfigurationCommand,
+ std::function<Status(const std::shared_ptr<MemHandle>&)> releasePacket)
+ : mProcessControlCommand(processControlCommand),
+ mProcessConfigurationCommand(processConfigurationCommand),
+ mReleasePacket(releasePacket) {
+ }
const std::function<Status(const proto::ControlCommand&)> mProcessControlCommand;
const std::function<Status(const proto::ConfigurationCommand&)>
diff --git a/computepipe/tests/Android.bp b/computepipe/tests/Android.bp
index 84d072d..18919d2 100644
--- a/computepipe/tests/Android.bp
+++ b/computepipe/tests/Android.bp
@@ -13,68 +13,26 @@
// limitations under the License.
cc_test {
- name: "registry_test",
- test_suites: ["device-tests"],
- srcs: [
- "RegistryTest.cpp",
- "FakeRunner.cpp",
- ],
- static_libs: [
- "libgtest",
- "libgmock",
- ],
- header_libs: [
- "computepipe_router_headers",
- ],
- shared_libs: [
- "libbinder",
- "libutils",
- "android.automotive.computepipe.registry-cpp",
- "android.automotive.computepipe.runner-cpp",
- ],
-}
-
-cc_test {
- name: "pipecontext_test",
- test_suites: ["device-tests"],
- srcs: [
- "PipeContextTest.cpp",
- "FakeRunner.cpp",
- ],
- static_libs: [
- "libgtest",
- "libgmock",
- ],
- header_libs: [
- "computepipe_router_headers",
- ],
- shared_libs: [
- "libbinder",
- "libutils",
- "android.automotive.computepipe.runner-cpp",
- ],
-}
-
-cc_test {
name: "piperegistration_test",
test_suites: ["device-tests"],
srcs: [
"PipeRegistrationTest.cpp",
- "FakeRunner.cpp",
+ "FakeRunner.cpp",
],
static_libs: [
"libgtest",
"libgmock",
],
header_libs: [
- "computepipe_router_headers",
+ "computepipe_router_headers",
],
shared_libs: [
+ "libbinder_ndk",
"libbinder",
"libutils",
"android.automotive.computepipe.router@1.0-impl",
- "android.automotive.computepipe.runner-cpp",
- "android.automotive.computepipe.registry-cpp",
+ "android.automotive.computepipe.runner-ndk_platform",
+ "android.automotive.computepipe.registry-ndk_platform",
],
}
@@ -83,20 +41,21 @@
test_suites: ["device-tests"],
srcs: [
"PipeQueryTest.cpp",
- "FakeRunner.cpp",
+ "FakeRunner.cpp",
],
static_libs: [
"libgtest",
"libgmock",
],
header_libs: [
- "computepipe_router_headers",
+ "computepipe_router_headers",
],
shared_libs: [
"libbinder",
+ "libbinder_ndk",
"libutils",
"android.automotive.computepipe.router@1.0-impl",
- "android.automotive.computepipe.runner-cpp",
- "android.automotive.computepipe.registry-cpp",
+ "android.automotive.computepipe.runner-ndk_platform",
+ "android.automotive.computepipe.registry-ndk_platform",
],
}
diff --git a/computepipe/tests/FakeRunner.cpp b/computepipe/tests/FakeRunner.cpp
index e8334bd..a3c0237 100644
--- a/computepipe/tests/FakeRunner.cpp
+++ b/computepipe/tests/FakeRunner.cpp
@@ -21,70 +21,76 @@
namespace computepipe {
namespace tests {
-using namespace android::binder;
-using namespace android::automotive::computepipe::runner;
+using namespace aidl::android::automotive::computepipe::runner;
// Methods from ::android::automotive::computepipe::runner::V1_0::IFakeRunnerV1_0 follow.
-Status FakeRunner::init(const sp<IPipeStateCallback>& stateCb) {
- mStateCallback = stateCb;
- return Status::ok();
+
+::ndk::ScopedAStatus FakeRunner::init(
+ const std::shared_ptr<
+ ::aidl::android::automotive::computepipe::runner::IPipeStateCallback>& /* in_statecb */) {
+ return ndk::ScopedAStatus::ok();
}
-Status FakeRunner::getPipeDescriptor(
- ::android::automotive::computepipe::runner::PipeDescriptor* _aidl_return) {
- (void)_aidl_return;
- return Status::ok();
+::ndk::ScopedAStatus FakeRunner::getPipeDescriptor(
+ ::aidl::android::automotive::computepipe::runner::PipeDescriptor* desc) {
+ *desc = mDesc;
+ return ndk::ScopedAStatus::ok();
+}
+::ndk::ScopedAStatus FakeRunner::setPipeInputSource(int32_t /*in_configId*/) {
+ ::ndk::ScopedAStatus _aidl_status;
+ _aidl_status.set(AStatus_fromStatus(STATUS_UNKNOWN_TRANSACTION));
+ return _aidl_status;
+}
+::ndk::ScopedAStatus FakeRunner::setPipeOffloadOptions(int32_t /*in_configId*/) {
+ ::ndk::ScopedAStatus _aidl_status;
+ _aidl_status.set(AStatus_fromStatus(STATUS_UNKNOWN_TRANSACTION));
+ return _aidl_status;
+}
+::ndk::ScopedAStatus FakeRunner::setPipeTermination(int32_t /*in_configId*/) {
+ ::ndk::ScopedAStatus _aidl_status;
+ _aidl_status.set(AStatus_fromStatus(STATUS_UNKNOWN_TRANSACTION));
+ return _aidl_status;
}
-Status FakeRunner::setPipeInputSource(int32_t configId) {
- (void)configId;
- return Status::ok();
+::ndk::ScopedAStatus FakeRunner::setPipeOutputConfig(
+ int32_t /*in_configId*/, int32_t /*in_maxInFlightCount*/,
+ const std::shared_ptr<
+ ::aidl::android::automotive::computepipe::runner::IPipeStream>& /*in_handler*/) {
+ ::ndk::ScopedAStatus _aidl_status;
+ _aidl_status.set(AStatus_fromStatus(STATUS_UNKNOWN_TRANSACTION));
+ return _aidl_status;
}
-
-Status FakeRunner::setPipeOffloadOptions(int32_t configId) {
- (void)configId;
- return Status::ok();
+::ndk::ScopedAStatus FakeRunner::applyPipeConfigs() {
+ ::ndk::ScopedAStatus _aidl_status;
+ _aidl_status.set(AStatus_fromStatus(STATUS_UNKNOWN_TRANSACTION));
+ return _aidl_status;
}
-
-Status FakeRunner::setPipeTermination(int32_t configId) {
- (void)configId;
- return Status::ok();
+::ndk::ScopedAStatus FakeRunner::startPipe() {
+ ::ndk::ScopedAStatus _aidl_status;
+ _aidl_status.set(AStatus_fromStatus(STATUS_UNKNOWN_TRANSACTION));
+ return _aidl_status;
}
-
-Status FakeRunner::setPipeOutputConfig(int32_t configId, int32_t maxInFlightCount,
- const ::android::sp<IPipeStream>& handler) {
- (void)configId;
- (void)maxInFlightCount;
- mOutputCallbacks.push_back(handler);
- return Status::ok();
+::ndk::ScopedAStatus FakeRunner::stopPipe() {
+ ::ndk::ScopedAStatus _aidl_status;
+ _aidl_status.set(AStatus_fromStatus(STATUS_UNKNOWN_TRANSACTION));
+ return _aidl_status;
}
-
-Status FakeRunner::applyPipeConfigs() {
- return Status::ok();
+::ndk::ScopedAStatus FakeRunner::doneWithPacket(int32_t /*in_id*/) {
+ ::ndk::ScopedAStatus _aidl_status;
+ _aidl_status.set(AStatus_fromStatus(STATUS_UNKNOWN_TRANSACTION));
+ return _aidl_status;
}
-
-Status FakeRunner::startPipe() {
- return Status::ok();
+::ndk::ScopedAStatus FakeRunner::getPipeDebugger(
+ std::shared_ptr<::aidl::android::automotive::computepipe::runner::IPipeDebugger>* /*_aidl_return*/) {
+ ::ndk::ScopedAStatus _aidl_status;
+ _aidl_status.set(AStatus_fromStatus(STATUS_UNKNOWN_TRANSACTION));
+ return _aidl_status;
}
-
-Status FakeRunner::stopPipe() {
- return Status::ok();
+::ndk::ScopedAStatus FakeRunner::releaseRunner() {
+ ::ndk::ScopedAStatus _aidl_status;
+ _aidl_status.set(AStatus_fromStatus(STATUS_UNKNOWN_TRANSACTION));
+ return _aidl_status;
}
-
-Status FakeRunner::doneWithPacket(int32_t id) {
- (void)id;
- return Status::ok();
-}
-
-Status FakeRunner::getPipeDebugger(sp<IPipeDebugger>* _aidl_return) {
- (void)_aidl_return;
- return Status::ok();
-}
-
-Status FakeRunner::releaseRunner() {
- return Status::ok();
-}
-
} // namespace tests
} // namespace computepipe
} // namespace automotive
diff --git a/computepipe/tests/FakeRunner.h b/computepipe/tests/FakeRunner.h
index 4760432..23a5806 100644
--- a/computepipe/tests/FakeRunner.h
+++ b/computepipe/tests/FakeRunner.h
@@ -17,7 +17,8 @@
#ifndef ANDROID_AUTOMOTIVE_COMPUTEPIPE_TESTS
#define ANDROID_AUTOMOTIVE_COMPUTEPIPE_TESTS
-#include <android/automotive/computepipe/runner/BnPipeRunner.h>
+#include <aidl/android/automotive/computepipe/runner/BnPipeRunner.h>
+#include <aidl/android/automotive/computepipe/runner/IPipeRunner.h>
#include <memory>
@@ -31,42 +32,37 @@
// This is a fake runner class whose various methods can be mocked in order
// to test the Runner logic.
-class FakeRunner : public runner::BnPipeRunner {
+class FakeRunner : public aidl::android::automotive::computepipe::runner::BnPipeRunner {
public:
- ::android::binder::Status init(
- const ::android::sp<::android::automotive::computepipe::runner::IPipeStateCallback>& stateCb)
- override;
- ::android::binder::Status getPipeDescriptor(
- ::android::automotive::computepipe::runner::PipeDescriptor* _aidl_return) override;
- ::android::binder::Status setPipeInputSource(int32_t configId) override;
- ::android::binder::Status setPipeOffloadOptions(int32_t configId) override;
- ::android::binder::Status setPipeTermination(int32_t configId) override;
- ::android::binder::Status setPipeOutputConfig(
- int32_t configId, int32_t maxInFlightCount,
- const ::android::sp<::android::automotive::computepipe::runner::IPipeStream>& handler)
- override;
- ::android::binder::Status applyPipeConfigs() override;
- ::android::binder::Status startPipe() override;
- ::android::binder::Status stopPipe() override;
- ::android::binder::Status doneWithPacket(int32_t id) override;
- ::android::binder::Status getPipeDebugger(
- ::android::sp<::android::automotive::computepipe::runner::IPipeDebugger>* _aidl_return)
- override;
- ::android::binder::Status releaseRunner() override;
- status_t linkToDeath(const sp<DeathRecipient>& recipient, void* cookie = nullptr,
- uint32_t flags = 0) override {
- (void)recipient;
- (void)cookie;
- (void)flags;
- return OK;
- };
+ ::ndk::ScopedAStatus init(
+ const std::shared_ptr<::aidl::android::automotive::computepipe::runner::IPipeStateCallback>&
+ in_statecb) override;
+ ::ndk::ScopedAStatus getPipeDescriptor(
+ ::aidl::android::automotive::computepipe::runner::PipeDescriptor* _aidl_return) override;
+ ::ndk::ScopedAStatus setPipeInputSource(int32_t in_configId) override;
+ ::ndk::ScopedAStatus setPipeOffloadOptions(int32_t in_configId) override;
+ ::ndk::ScopedAStatus setPipeTermination(int32_t in_configId) override;
+ ::ndk::ScopedAStatus setPipeOutputConfig(
+ int32_t in_configId, int32_t in_maxInFlightCount,
+ const std::shared_ptr<::aidl::android::automotive::computepipe::runner::IPipeStream>&
+ in_handler) override;
+ ::ndk::ScopedAStatus applyPipeConfigs() override;
+ ::ndk::ScopedAStatus startPipe() override;
+ ::ndk::ScopedAStatus stopPipe() override;
+ ::ndk::ScopedAStatus doneWithPacket(int32_t in_id) override;
+ ::ndk::ScopedAStatus getPipeDebugger(
+ std::shared_ptr<::aidl::android::automotive::computepipe::runner::IPipeDebugger>*
+ _aidl_return) override;
+ ::ndk::ScopedAStatus releaseRunner() override;
~FakeRunner() {
mOutputCallbacks.clear();
}
private:
- std::vector<wp<::android::automotive::computepipe::runner::IPipeStream>> mOutputCallbacks;
- wp<::android::automotive::computepipe::runner::IPipeStateCallback> mStateCallback;
+ aidl::android::automotive::computepipe::runner::PipeDescriptor mDesc;
+ std::vector<std::shared_ptr<aidl::android::automotive::computepipe::runner::IPipeStream>>
+ mOutputCallbacks;
+ std::shared_ptr<aidl::android::automotive::computepipe::runner::IPipeStateCallback> mStateCallback;
};
} // namespace tests
diff --git a/computepipe/tests/PipeContextTest.cpp b/computepipe/tests/PipeContextTest.cpp
deleted file mode 100644
index 3a0405e..0000000
--- a/computepipe/tests/PipeContextTest.cpp
+++ /dev/null
@@ -1,94 +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.
- */
-
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-#include <stdio.h>
-
-#include <list>
-#include <string>
-#include <utility>
-
-#include "FakeRunner.h"
-#include "PipeContext.h"
-
-using namespace ::android::automotive::computepipe::router;
-using namespace ::android::automotive::computepipe::tests;
-using namespace ::testing;
-
-/**
- * Wraps a FakeRunner instance
- */
-struct WrapRunner {
- WrapRunner(const android::sp<FakeRunner>& r) : mRunner(r) {
- }
- android::wp<FakeRunner> mRunner;
-};
-
-/**
- * Implements PipeHandle methods and manages the underlying IPC
- * object
- */
-class FakePipeHandle : public PipeHandle<WrapRunner> {
- public:
- explicit FakePipeHandle(const android::sp<FakeRunner>& r)
- : PipeHandle(std::make_unique<WrapRunner>(r)) {
- }
- bool isAlive() override {
- auto pRunner = mInterface->mRunner.promote();
- if (pRunner == nullptr) {
- return false;
- } else {
- return true;
- }
- }
- bool startPipeMonitor() override {
- return true;
- }
- PipeHandle<WrapRunner>* clone() const override {
- return new FakePipeHandle(mInterface->mRunner.promote());
- }
- ~FakePipeHandle() {
- mInterface = nullptr;
- }
-};
-
-TEST(PipeContextTest, IsAliveTest) {
- android::sp<FakeRunner> runner = new FakeRunner();
- std::unique_ptr<PipeHandle<WrapRunner>> pHandle = std::make_unique<FakePipeHandle>(runner);
- ASSERT_TRUE(pHandle->isAlive());
-
- PipeContext pContext(std::move(pHandle), "random");
- ASSERT_TRUE(pContext.isAlive());
- runner.clear();
- ASSERT_FALSE(pContext.isAlive());
-}
-
-TEST(PipeContextTest, GetHandleTest) {
- android::sp<FakeRunner> dummy = new FakeRunner();
- std::unique_ptr<PipeHandle<WrapRunner>> pHandle = std::make_unique<FakePipeHandle>(dummy);
- PipeContext pContext(std::move(pHandle), "random");
-
- std::unique_ptr<PipeHandle<WrapRunner>> dupHandle = pContext.dupPipeHandle();
- android::sp<FakeRunner> dummy2 = dupHandle->getInterface()->mRunner.promote();
- ASSERT_THAT(dummy2->getStrongCount(), Eq(2));
- dummy2.clear();
-
- ASSERT_TRUE(dupHandle->isAlive());
- dummy.clear();
- ASSERT_FALSE(dupHandle->isAlive());
- ASSERT_FALSE(pContext.isAlive());
-}
diff --git a/computepipe/tests/PipeQueryTest.cpp b/computepipe/tests/PipeQueryTest.cpp
index 2a1a137..acdee1d 100644
--- a/computepipe/tests/PipeQueryTest.cpp
+++ b/computepipe/tests/PipeQueryTest.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include <android/automotive/computepipe/registry/BnClientInfo.h>
+#include <aidl/android/automotive/computepipe/registry/BnClientInfo.h>
#include <binder/IInterface.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
@@ -32,9 +32,8 @@
using namespace android::automotive::computepipe::router;
using namespace android::automotive::computepipe::router::V1_0::implementation;
using namespace android::automotive::computepipe::tests;
-using namespace android::automotive::computepipe::runner;
-using namespace android::automotive::computepipe::registry;
-using namespace android::binder;
+using namespace aidl::android::automotive::computepipe::runner;
+using namespace aidl::android::automotive::computepipe::registry;
using namespace ::testing;
/**
@@ -42,17 +41,10 @@
*/
class FakeClientInfo : public BnClientInfo {
public:
- Status getClientId(int32_t* id) override {
+ ndk::ScopedAStatus getClientId(int32_t* id) override {
*id = 1;
- return Status::ok();
+ return ndk::ScopedAStatus::ok();
}
- android::status_t linkToDeath(const android::sp<DeathRecipient>& recipient,
- void* cookie = nullptr, uint32_t flags = 0) override {
- (void)recipient;
- (void)cookie;
- (void)flags;
- return OK;
- };
};
/**
@@ -86,7 +78,7 @@
/**
* Utility to generate fake runners
*/
- void addFakeRunner(const std::string& name, const android::sp<IPipeRunner>& runnerIface) {
+ void addFakeRunner(const std::string& name, const std::shared_ptr<IPipeRunner>& runnerIface) {
std::unique_ptr<PipeHandle<PipeRunner>> handle = std::make_unique<RunnerHandle>(runnerIface);
Error status = mRegistry->RegisterPipe(std::move(handle), name);
ASSERT_THAT(status, testing::Eq(Error::OK));
@@ -108,10 +100,10 @@
// Check retrieval of inserted entries
TEST_F(PipeQueryTest, GetGraphListTest) {
- android::sp<IPipeRunner> dummy1 = new FakeRunner();
+ std::shared_ptr<IPipeRunner> dummy1 = ndk::SharedRefBase::make<FakeRunner>();
addFakeRunner("dummy1", dummy1);
- android::sp<IPipeRunner> dummy2 = new FakeRunner();
- addFakeRunner("dummy2", dummy1);
+ std::shared_ptr<IPipeRunner> dummy2 = ndk::SharedRefBase::make<FakeRunner>();
+ addFakeRunner("dummy2", dummy2);
std::vector<std::string>* outNames = new std::vector<std::string>();
std::unique_ptr<PipeQuery> qIface = std::make_unique<PipeQuery>(mRegistry);
@@ -126,26 +118,12 @@
// Check successful retrieval of runner
TEST_F(PipeQueryTest, GetRunnerTest) {
- android::sp<IPipeRunner> dummy1 = new FakeRunner();
+ std::shared_ptr<IPipeRunner> dummy1 = ndk::SharedRefBase::make<FakeRunner>();
addFakeRunner("dummy1", dummy1);
std::unique_ptr<PipeQuery> qIface = std::make_unique<PipeQuery>(mRegistry);
- android::sp<IClientInfo> info = new FakeClientInfo();
- android::sp<IPipeRunner> runner;
+ std::shared_ptr<IClientInfo> info = ndk::SharedRefBase::make<FakeClientInfo>();
+ std::shared_ptr<IPipeRunner> runner;
ASSERT_TRUE(qIface->getPipeRunner("dummy1", info, &runner).isOk());
EXPECT_THAT(runner, testing::NotNull());
}
-
-// Check retrieval of dead runner
-TEST_F(PipeQueryTest, DeadRunnerTest) {
- android::sp<IPipeRunner> dummy1 = new FakeRunner();
- addFakeRunner("dummy1", dummy1);
-
- std::unique_ptr<PipeQuery> qIface = std::make_unique<PipeQuery>(mRegistry);
- dummy1.clear();
- removeRunner("dummy1");
- android::sp<IClientInfo> info = new FakeClientInfo();
- android::sp<IPipeRunner> runner;
- qIface->getPipeRunner("dummy1", info, &runner);
- EXPECT_THAT(runner, testing::IsNull());
-}
diff --git a/computepipe/tests/PipeRegistrationTest.cpp b/computepipe/tests/PipeRegistrationTest.cpp
index c5287c6..1caf07b 100644
--- a/computepipe/tests/PipeRegistrationTest.cpp
+++ b/computepipe/tests/PipeRegistrationTest.cpp
@@ -30,10 +30,8 @@
using namespace android::automotive::computepipe::router;
using namespace android::automotive::computepipe::router::V1_0::implementation;
using namespace android::automotive::computepipe::tests;
-using namespace android::automotive::computepipe::runner;
-using namespace android::automotive::computepipe::registry;
-using namespace android::binder;
-using android::sp;
+using namespace aidl::android::automotive::computepipe::runner;
+using namespace aidl::android::automotive::computepipe::registry;
/**
* Test fixture that manages the underlying registry creation and tear down
*/
@@ -52,15 +50,17 @@
// Valid registration succeeds
TEST_F(PipeRegistrationTest, RegisterFakeRunner) {
- sp<IPipeRunner> dummy = new FakeRunner();
- std::unique_ptr<IPipeRegistration> rIface(new PipeRegistration(this->mRegistry));
+ std::shared_ptr<IPipeRunner> dummy = ndk::SharedRefBase::make<FakeRunner>();
+ std::shared_ptr<IPipeRegistration> rIface =
+ ndk::SharedRefBase::make<PipeRegistration>(this->mRegistry);
EXPECT_TRUE(rIface->registerPipeRunner("dummy", dummy).isOk());
}
// Duplicate registration fails
TEST_F(PipeRegistrationTest, RegisterDuplicateRunner) {
- sp<IPipeRunner> dummy = new FakeRunner();
- std::unique_ptr<IPipeRegistration> rIface(new PipeRegistration(this->mRegistry));
+ std::shared_ptr<IPipeRunner> dummy = ndk::SharedRefBase::make<FakeRunner>();
+ std::shared_ptr<IPipeRegistration> rIface =
+ ndk::SharedRefBase::make<PipeRegistration>(this->mRegistry);
ASSERT_TRUE(rIface->registerPipeRunner("dummy", dummy).isOk());
EXPECT_FALSE(rIface->registerPipeRunner("dummy", dummy).isOk());
}
diff --git a/computepipe/tests/RegistryTest.cpp b/computepipe/tests/RegistryTest.cpp
deleted file mode 100644
index c31f6a1..0000000
--- a/computepipe/tests/RegistryTest.cpp
+++ /dev/null
@@ -1,156 +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.
- */
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-#include <stdio.h>
-
-#include <list>
-#include <string>
-
-#include "FakeRunner.h"
-#include "Registry.h"
-
-using namespace ::android::automotive::computepipe::router;
-using namespace ::android::automotive::computepipe::tests;
-using namespace ::android;
-using namespace ::testing;
-
-class FakeClient : public ClientHandle {
- public:
- uint32_t getClientId() override {
- return 0;
- }
- bool isAlive() override {
- return true;
- }
- bool startClientMonitor() override {
- return true;
- }
- ~FakeClient() {
- }
-};
-
-/**
- * Wraps a FakeRunner instance
- */
-struct WrapRunner {
- WrapRunner(const sp<FakeRunner>& r) : mRunner(r) {
- }
- android::wp<FakeRunner> mRunner;
-};
-
-/**
- * Implements PipeHandle methods and manages the underlying IPC
- * object
- */
-class FakePipeHandle : public PipeHandle<WrapRunner> {
- public:
- explicit FakePipeHandle(const sp<FakeRunner>& r) : PipeHandle(std::make_unique<WrapRunner>(r)) {
- }
- bool isAlive() override {
- auto pRunner = mInterface->mRunner.promote();
- if (pRunner == nullptr) {
- return false;
- } else {
- return true;
- }
- }
- bool startPipeMonitor() override {
- return true;
- }
- PipeHandle<WrapRunner>* clone() const override {
- return new FakePipeHandle(mInterface->mRunner.promote());
- }
- ~FakePipeHandle() {
- mInterface = nullptr;
- }
-};
-
-/**
- * Test for PipeRegistry::getRunner()
- * Check if the api does not mistakenly increment the refcount
- * Check if the api correctly handles bad client
- * Check if the api correctly handles multiclient error
- * Check if the api correctly handles a deleted runner retrieval
- * Check if registry implementation correctly deletes entry for
- * dead runner
- */
-TEST(RegistryTest, GetRunnerTest) {
- PipeRegistry<WrapRunner> registry;
- sp<FakeRunner> runner = new FakeRunner();
- std::unique_ptr<PipeHandle<WrapRunner>> handle = std::make_unique<FakePipeHandle>(runner);
- ASSERT_THAT(runner, testing::NotNull());
- // Verify refcount
- registry.RegisterPipe(std::move(handle), "random");
- EXPECT_THAT(runner->getStrongCount(), Eq(1));
- // Verify bad client
- EXPECT_THAT(registry.getClientPipeHandle("random", nullptr), IsNull());
- // Verify correct retrieval
- std::unique_ptr<ClientHandle> client = std::make_unique<FakeClient>();
- ASSERT_THAT(client, NotNull());
- EXPECT_THAT(registry.getClientPipeHandle("random", std::move(client)), NotNull());
- // verify multiclient failure
- client.reset(new FakeClient());
- EXPECT_THAT(registry.getClientPipeHandle("random", std::move(client)), IsNull());
- // Verify deleted runner
- sp<FakeRunner> dummy;
- dummy = new FakeRunner();
- std::unique_ptr<PipeHandle<WrapRunner>> dummyHandle = std::make_unique<FakePipeHandle>(dummy);
- registry.RegisterPipe(std::move(dummyHandle), "dummy");
- dummy.clear();
- client.reset(new FakeClient());
- EXPECT_THAT(registry.getClientPipeHandle("dummy", std::move(client)), IsNull());
-}
-
-/**
- * Test for PipeRegistry::getPipeList()
- * Check if the api correctly handles empty db
- */
-TEST(RegistryTest, GetPipeListTest) {
- PipeRegistry<WrapRunner> registry;
- // Confirm entry registry
- std::list<std::string> names = registry.getPipeList();
- ASSERT_THAT(names.size(), Eq(0));
- // Confirm 1 entry
- sp<FakeRunner> runner = new FakeRunner();
- std::unique_ptr<PipeHandle<WrapRunner>> handle = std::make_unique<FakePipeHandle>(runner);
- registry.RegisterPipe(std::move(handle), "random");
- names = registry.getPipeList();
- ASSERT_THAT(names.size(), Eq(1));
- ASSERT_STREQ((*names.begin()).c_str(), "random");
-}
-
-/**
- * Test for PipeRegistry::registerPipe()
- * Check if the api correctly rejects duplicate entries
- * Check if the api correctly handles reregistration of a deleted runner
- */
-TEST(RegistryTest, RegisterPipeTest) {
- PipeRegistry<WrapRunner> registry;
- sp<FakeRunner> runner = new FakeRunner();
- std::unique_ptr<PipeHandle<WrapRunner>> handle = std::make_unique<FakePipeHandle>(runner);
- Error status = registry.RegisterPipe(std::move(handle), "random");
- ASSERT_THAT(status, Eq(Error::OK));
- // Duplicate entry
- status = registry.RegisterPipe(nullptr, "random");
- ASSERT_THAT(status, Eq(Error::DUPLICATE_PIPE));
- // Deleted runner
- runner.clear();
- runner = new FakeRunner();
- handle.reset(new FakePipeHandle(runner));
- status = registry.RegisterPipe(std::move(handle), "random");
- ASSERT_THAT(status, Eq(Error::OK));
-}
diff --git a/computepipe/tests/runner/Android.bp b/computepipe/tests/runner/Android.bp
new file mode 100644
index 0000000..a3edb37
--- /dev/null
+++ b/computepipe/tests/runner/Android.bp
@@ -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.
+
+cc_test {
+ name: "computepipe_semantic_manager_test",
+ test_suites: ["device-tests"],
+ srcs: [
+ "SemanticManagerTest.cpp",
+ ],
+ static_libs: [
+ "libgtest",
+ "libgmock",
+ "libcomputepipeprotos",
+ ],
+ shared_libs: [
+ "libcomputepipe_stream_manager",
+ "libprotobuf-cpp-full",
+ ],
+ header_libs: [
+ "computepipe_runner_includes",
+ ],
+ include_dirs: [
+ "packages/services/Car/computepipe"
+ ],
+}
diff --git a/computepipe/tests/runner/SemanticManagerTest.cpp b/computepipe/tests/runner/SemanticManagerTest.cpp
new file mode 100644
index 0000000..6316e5c
--- /dev/null
+++ b/computepipe/tests/runner/SemanticManagerTest.cpp
@@ -0,0 +1,93 @@
+/*
+ * 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.
+ */
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "OutputConfig.pb.h"
+#include "StreamManager.h"
+#include "gmock/gmock-matchers.h"
+#include "types/Status.h"
+
+using namespace android::automotive::computepipe::runner::stream_manager;
+using namespace android::automotive::computepipe;
+
+class SemanticManagerTest : public ::testing::Test {
+ protected:
+ static constexpr uint32_t kMaxSemanticDataSize = 1024;
+ /**
+ * Setup for the test fixture to initialize the semantic manager
+ * After this, the semantic manager should be in RESET state.
+ */
+ void SetUp() override {
+ proto::OutputConfig config;
+ config.set_type(proto::PacketType::SEMANTIC_DATA);
+ config.set_stream_name("semantic_stream");
+ mStreamManager = mFactory.getStreamManager(config);
+ std::function<Status(std::shared_ptr<MemHandle>)> cb =
+ [this](std::shared_ptr<MemHandle> handle) -> Status {
+ this->mPacketSize = handle->getSize();
+ this->mCurrentPacket = (char*)malloc(this->mPacketSize);
+ memcpy(mCurrentPacket, handle->getData(), this->mPacketSize);
+
+ return SUCCESS;
+ };
+ ASSERT_EQ(mStreamManager->setIpcDispatchCallback(cb), Status::SUCCESS);
+ }
+ void deleteCurrentPacket() {
+ if (mCurrentPacket) {
+ free(mCurrentPacket);
+ mCurrentPacket = nullptr;
+ }
+ }
+ void TearDown() override {
+ if (mCurrentPacket) {
+ free(mCurrentPacket);
+ }
+ mStreamManager = nullptr;
+ }
+ std::unique_ptr<StreamManager> mStreamManager;
+ StreamManagerFactory mFactory;
+ char* mCurrentPacket = nullptr;
+ uint32_t mPacketSize;
+};
+
+/**
+ * Checks the ability to start semantic stream management
+ * without config state
+ */
+TEST_F(SemanticManagerTest, NoConfigTest) {
+ EXPECT_EQ(mStreamManager->start(), Status::ILLEGAL_STATE);
+ mStreamManager->setMaxInFlightPackets(0);
+ EXPECT_EQ(mStreamManager->start(), Status::SUCCESS);
+}
+
+/**
+ * Checks Packet Queing without start.
+ * Checks Packet Queuing with bad arguments.
+ * Checks successful packet queuing.
+ */
+TEST_F(SemanticManagerTest, PacketQueueTest) {
+ ASSERT_EQ(mStreamManager->setMaxInFlightPackets(0), Status::SUCCESS);
+ ASSERT_EQ(mStreamManager->start(), Status::SUCCESS);
+ std::string fakeData("FakeData");
+ uint32_t size = fakeData.size();
+ EXPECT_EQ(mStreamManager->queuePacket(nullptr, size, 0), Status::INVALID_ARGUMENT);
+ EXPECT_EQ(mStreamManager->queuePacket(fakeData.c_str(), kMaxSemanticDataSize + 1, 0),
+ Status::INVALID_ARGUMENT);
+ EXPECT_EQ(mStreamManager->queuePacket(fakeData.c_str(), size, 0), Status::SUCCESS);
+ EXPECT_STREQ(mCurrentPacket, fakeData.c_str());
+}
diff --git a/computepipe/types/Status.h b/computepipe/types/Status.h
index ca2bc6e..4bd126f 100644
--- a/computepipe/types/Status.h
+++ b/computepipe/types/Status.h
@@ -23,6 +23,7 @@
SUCCESS = 0,
INTERNAL_ERROR,
INVALID_ARGUMENT,
+ ILLEGAL_STATE,
NO_MEMORY,
FATAL_ERROR,
};
diff --git a/service/res/values-af/strings.xml b/service/res/values-af/strings.xml
index 3de7e5e..e553b4c 100644
--- a/service/res/values-af/strings.xml
+++ b/service/res/values-af/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Aktiveer of deaktiveer motor se kenmerke"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Aktiveer of deaktiveer motor se kenmerke."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"My Toestel"</string>
</resources>
diff --git a/service/res/values-am/strings.xml b/service/res/values-am/strings.xml
index e53d167..da70c27 100644
--- a/service/res/values-am/strings.xml
+++ b/service/res/values-am/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"የመኪና ባህሪዎችን አንቃ ወይም አሰናክል"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"የመኪና ባህሪዎችን አንቃ ወይም አሰናክል"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"የእኔ መሣሪያ"</string>
</resources>
diff --git a/service/res/values-ar/strings.xml b/service/res/values-ar/strings.xml
index 7653861..9492091 100644
--- a/service/res/values-ar/strings.xml
+++ b/service/res/values-ar/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"تفعيل ميزات السيارة أو إيقافها"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"تفعيل ميزات السيارة أو إيقافها"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"جهازي"</string>
</resources>
diff --git a/service/res/values-az/strings.xml b/service/res/values-az/strings.xml
index 645d40e..bedd037 100644
--- a/service/res/values-az/strings.xml
+++ b/service/res/values-az/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Avtomobilin xüsusiyyətlərini aktiv və ya deaktiv etmək"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Avtomobilin xüsusiyyətlərini aktiv və ya deaktiv etmək."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Cihazım"</string>
</resources>
diff --git a/service/res/values-b+sr+Latn/strings.xml b/service/res/values-b+sr+Latn/strings.xml
index 61cbab2..f78007a 100644
--- a/service/res/values-b+sr+Latn/strings.xml
+++ b/service/res/values-b+sr+Latn/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Omogućavanje ili onemogućavanje funkcija automobila"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Omogućavanje ili onemogućavanje funkcija automobila."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Moj uređaj"</string>
</resources>
diff --git a/service/res/values-be/strings.xml b/service/res/values-be/strings.xml
index aeea7f8..22986a6 100644
--- a/service/res/values-be/strings.xml
+++ b/service/res/values-be/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Уключыць або выключыць функцыі аўтамабіля"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Уключыць або выключыць функцыі аўтамабіля."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Мая прылада"</string>
</resources>
diff --git a/service/res/values-bg/strings.xml b/service/res/values-bg/strings.xml
index 0b14653..d9f0d04 100644
--- a/service/res/values-bg/strings.xml
+++ b/service/res/values-bg/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Активиране или деактивиране на функциите на автомобила"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Активиране или деактивиране на функциите на автомобила."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Моето устройство"</string>
</resources>
diff --git a/service/res/values-bn/strings.xml b/service/res/values-bn/strings.xml
index c1b0ac3..1cf6aff 100644
--- a/service/res/values-bn/strings.xml
+++ b/service/res/values-bn/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"গাড়ির ফিচার চালু বা বন্ধ করুন"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"গাড়ির ফিচার চালু বা বন্ধ করুন।"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"আমার ডিভাইস"</string>
</resources>
diff --git a/service/res/values-bs/strings.xml b/service/res/values-bs/strings.xml
index 5c5aae8..bcebee2 100644
--- a/service/res/values-bs/strings.xml
+++ b/service/res/values-bs/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Omogućavanje ili onemogućavanje funkcija automobila"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Omogućavanje ili onemogućavanje funkcija automobila."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Moj uređaj"</string>
</resources>
diff --git a/service/res/values-ca/strings.xml b/service/res/values-ca/strings.xml
index c2e5203..f3d70d6 100644
--- a/service/res/values-ca/strings.xml
+++ b/service/res/values-ca/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Activa o desactiva les funcions del cotxe"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Activa o desactiva les funcions del cotxe."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"El meu dispositiu"</string>
</resources>
diff --git a/service/res/values-cs/strings.xml b/service/res/values-cs/strings.xml
index bc041df..8c81008 100644
--- a/service/res/values-cs/strings.xml
+++ b/service/res/values-cs/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Zapnout nebo vypnout funkce auta"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Zapnout nebo vypnout funkce auta."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Moje zařízení"</string>
</resources>
diff --git a/service/res/values-da/strings.xml b/service/res/values-da/strings.xml
index 2c827a7..3df61c9 100644
--- a/service/res/values-da/strings.xml
+++ b/service/res/values-da/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Aktivér eller deaktiver bilens funktioner"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Aktivér eller deaktiver bilens funktioner."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Min enhed"</string>
</resources>
diff --git a/service/res/values-de/strings.xml b/service/res/values-de/strings.xml
index 19faf92..feb75cf 100644
--- a/service/res/values-de/strings.xml
+++ b/service/res/values-de/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Funktionen des Autos aktivieren oder deaktivieren"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Funktionen des Autos aktivieren oder deaktivieren."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Mein Gerät"</string>
</resources>
diff --git a/service/res/values-el/strings.xml b/service/res/values-el/strings.xml
index ad24be7..fc105a2 100644
--- a/service/res/values-el/strings.xml
+++ b/service/res/values-el/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Ενεργοποίηση ή απενεργοποίηση των λειτουργιών του αυτοκινήτου."</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Ενεργοποίηση ή απενεργοποίηση των λειτουργιών του αυτοκινήτου."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Η συσκευή μου"</string>
</resources>
diff --git a/service/res/values-en-rAU/strings.xml b/service/res/values-en-rAU/strings.xml
index 83bb45e..7f736af 100644
--- a/service/res/values-en-rAU/strings.xml
+++ b/service/res/values-en-rAU/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Enable or disable car’s features"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Enable or disable car’s features."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"My Device"</string>
</resources>
diff --git a/service/res/values-en-rCA/strings.xml b/service/res/values-en-rCA/strings.xml
index 83bb45e..7f736af 100644
--- a/service/res/values-en-rCA/strings.xml
+++ b/service/res/values-en-rCA/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Enable or disable car’s features"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Enable or disable car’s features."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"My Device"</string>
</resources>
diff --git a/service/res/values-en-rGB/strings.xml b/service/res/values-en-rGB/strings.xml
index 83bb45e..7f736af 100644
--- a/service/res/values-en-rGB/strings.xml
+++ b/service/res/values-en-rGB/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Enable or disable car’s features"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Enable or disable car’s features."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"My Device"</string>
</resources>
diff --git a/service/res/values-en-rIN/strings.xml b/service/res/values-en-rIN/strings.xml
index 83bb45e..7f736af 100644
--- a/service/res/values-en-rIN/strings.xml
+++ b/service/res/values-en-rIN/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Enable or disable car’s features"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Enable or disable car’s features."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"My Device"</string>
</resources>
diff --git a/service/res/values-en-rXC/strings.xml b/service/res/values-en-rXC/strings.xml
index b3c00ac..9d39a3f 100644
--- a/service/res/values-en-rXC/strings.xml
+++ b/service/res/values-en-rXC/strings.xml
@@ -201,5 +201,7 @@
<string name="car_permission_desc_set_car_vendor_category_9" msgid="7274990520545034656">"Control vendor specific properties in category 9."</string>
<string name="car_permission_label_set_car_vendor_category_10" msgid="366813764827342987">"control vendor specific properties in category 10"</string>
<string name="car_permission_desc_set_car_vendor_category_10" msgid="6353592281201463231">"Control vendor specific properties in category 10."</string>
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Enable or disable car’s features"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Enable or disable car’s features."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"My Device"</string>
</resources>
diff --git a/service/res/values-es-rUS/strings.xml b/service/res/values-es-rUS/strings.xml
index de37dc5..38a3882 100644
--- a/service/res/values-es-rUS/strings.xml
+++ b/service/res/values-es-rUS/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Habilitar o inhabilitar las funciones del vehículo"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Habilitar o inhabilitar las funciones del vehículo"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Mi dispositivo"</string>
</resources>
diff --git a/service/res/values-es/strings.xml b/service/res/values-es/strings.xml
index f7e6ab9..b78a053 100644
--- a/service/res/values-es/strings.xml
+++ b/service/res/values-es/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Habilitar o inhabilitar las funciones de un coche"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Habilitar o inhabilitar las funciones de un coche."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Mi dispositivo"</string>
</resources>
diff --git a/service/res/values-et/strings.xml b/service/res/values-et/strings.xml
index bc54338..5397d85 100644
--- a/service/res/values-et/strings.xml
+++ b/service/res/values-et/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Auto funktsioonide lubamine ja keelamine"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Võimalik on lubada ja keelata auto funktsioone."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Minu seade"</string>
</resources>
diff --git a/service/res/values-eu/strings.xml b/service/res/values-eu/strings.xml
index f265e60..aa1e7ce 100644
--- a/service/res/values-eu/strings.xml
+++ b/service/res/values-eu/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Gaitu edo desgaitu autoaren eginbideak"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Gaitu edo desgaitu autoaren eginbideak."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Nire gailua"</string>
</resources>
diff --git a/service/res/values-fa/strings.xml b/service/res/values-fa/strings.xml
index 0772793..9f87f87 100644
--- a/service/res/values-fa/strings.xml
+++ b/service/res/values-fa/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"فعال کردن یا غیرفعال کردن ویژگیهای خودرو"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"ویژگیهای خودرو را فعال یا غیرفعال کنید."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"دستگاه من"</string>
</resources>
diff --git a/service/res/values-fi/strings.xml b/service/res/values-fi/strings.xml
index 258a75d..3a7f71c 100644
--- a/service/res/values-fi/strings.xml
+++ b/service/res/values-fi/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Ota auton ominaisuuksia käyttöön tai poista niitä käytöstä"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Ota auton ominaisuuksia käyttöön tai poista niitä käytöstä."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Oma laite"</string>
</resources>
diff --git a/service/res/values-fr-rCA/strings.xml b/service/res/values-fr-rCA/strings.xml
index 308e519..e049a65 100644
--- a/service/res/values-fr-rCA/strings.xml
+++ b/service/res/values-fr-rCA/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Activez ou désactivez les fonctionnalités du véhicule"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Activez ou désactivez les fonctionnalités du véhicule."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Mon appareil"</string>
</resources>
diff --git a/service/res/values-fr/strings.xml b/service/res/values-fr/strings.xml
index 4a18ffd..96a6b90 100644
--- a/service/res/values-fr/strings.xml
+++ b/service/res/values-fr/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Activer ou désactiver les fonctionnalités de la voiture"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Activez ou désactivez les fonctionnalités de la voiture."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Mon appareil"</string>
</resources>
diff --git a/service/res/values-gl/strings.xml b/service/res/values-gl/strings.xml
index 205b75c..c01e5d1 100644
--- a/service/res/values-gl/strings.xml
+++ b/service/res/values-gl/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Activar ou desactivar funcións do coche"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Activa ou desactiva as funcións do coche."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Dispositivo"</string>
</resources>
diff --git a/service/res/values-gu/strings.xml b/service/res/values-gu/strings.xml
index a3af09e..1a02106 100644
--- a/service/res/values-gu/strings.xml
+++ b/service/res/values-gu/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"કારની સુવિધા ચાલુ અથવા બંધ કરો"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"કારની સુવિધા ચાલુ અથવા બંધ કરો."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"મારું ડિવાઇસ"</string>
</resources>
diff --git a/service/res/values-hi/strings.xml b/service/res/values-hi/strings.xml
index 13a9786..9c678da 100644
--- a/service/res/values-hi/strings.xml
+++ b/service/res/values-hi/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"कार की सुविधाएं चालू या बंद करें"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"कार की सुविधाएं चालू या बंद करें."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"मेरा डिवाइस"</string>
</resources>
diff --git a/service/res/values-hr/strings.xml b/service/res/values-hr/strings.xml
index e65ccce..e59af0f 100644
--- a/service/res/values-hr/strings.xml
+++ b/service/res/values-hr/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Omogućivanje ili onemogućivanje značajki automobila"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Omogućivanje ili onemogućivanje značajki automobila."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Moj uređaj"</string>
</resources>
diff --git a/service/res/values-hu/strings.xml b/service/res/values-hu/strings.xml
index 611d228..16b6252 100644
--- a/service/res/values-hu/strings.xml
+++ b/service/res/values-hu/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Az autó funkcióinak engedélyezése vagy tiltása"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Az autó funkcióinak engedélyezése vagy tiltása."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Saját eszköz"</string>
</resources>
diff --git a/service/res/values-hy/strings.xml b/service/res/values-hy/strings.xml
index 2049a35..4f1dfb9 100644
--- a/service/res/values-hy/strings.xml
+++ b/service/res/values-hy/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Միացնել կամ անջատել մեքենայի գործառույթները"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Միացնել կամ անջատել մեքենայի գործառույթները"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Իմ սարքը"</string>
</resources>
diff --git a/service/res/values-in/strings.xml b/service/res/values-in/strings.xml
index 5ae6988..ebaa012 100644
--- a/service/res/values-in/strings.xml
+++ b/service/res/values-in/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Aktifkan atau nonaktifkan fitur mobil"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Aktifkan atau nonaktifkan fitur mobil."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Perangkat Saya"</string>
</resources>
diff --git a/service/res/values-is/strings.xml b/service/res/values-is/strings.xml
index 40f6059..7908dea 100644
--- a/service/res/values-is/strings.xml
+++ b/service/res/values-is/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Kveikja eða slökkva á bíleiginleikum"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Kveikja eða slökkva á bíleiginleikum."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Tækið mitt"</string>
</resources>
diff --git a/service/res/values-it/strings.xml b/service/res/values-it/strings.xml
index ca529ce..f437b5b 100644
--- a/service/res/values-it/strings.xml
+++ b/service/res/values-it/strings.xml
@@ -16,7 +16,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_permission_label" msgid="741004755205554376">"Accesso alle informazioni dell\'automobile"</string>
+ <string name="car_permission_label" msgid="741004755205554376">"Accesso alle informazioni dell\'auto"</string>
<string name="car_permission_desc" msgid="162499818870052725">"Consente di accedere alle informazioni dell\'automobile."</string>
<string name="car_permission_label_camera" msgid="3725702064841827180">"Accesso alla videocamera dell\'automobile"</string>
<string name="car_permission_desc_camera" msgid="917024932164501426">"Consente di accedere alle videocamere dell\'automobile."</string>
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Attiva o disattiva le funzionalità dell\'auto"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Attiva o disattiva le funzionalità dell\'auto."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Mio dispositivo"</string>
</resources>
diff --git a/service/res/values-ja/strings.xml b/service/res/values-ja/strings.xml
index 8bede1c..6e519d5 100644
--- a/service/res/values-ja/strings.xml
+++ b/service/res/values-ja/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"車の機能を有効または無効にします"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"車の機能を有効または無効にします。"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"自分のデバイス"</string>
</resources>
diff --git a/service/res/values-ka/strings.xml b/service/res/values-ka/strings.xml
index f7b23e6..85e8fb4 100644
--- a/service/res/values-ka/strings.xml
+++ b/service/res/values-ka/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"მანქანის ფუნქციების ჩართვა ან გათიშვა"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"მანქანის ფუნქციების ჩართვა ან გათიშვა."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"ჩემი მოწყობილობა"</string>
</resources>
diff --git a/service/res/values-kk/strings.xml b/service/res/values-kk/strings.xml
index 261b8bd..00ae0b3 100644
--- a/service/res/values-kk/strings.xml
+++ b/service/res/values-kk/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Көлік функцияларын қосыңыз немесе өшіріңіз."</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Көлік функцияларын қосыңыз немесе өшіріңіз."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Құрылғым"</string>
</resources>
diff --git a/service/res/values-km/strings.xml b/service/res/values-km/strings.xml
index bbf85fe..b061796 100644
--- a/service/res/values-km/strings.xml
+++ b/service/res/values-km/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"បើក ឬបិទមុខងាររបស់រថយន្ត"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"បើក ឬបិទមុខងាររបស់រថយន្ត។"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"ឧបករណ៍របស់ខ្ញុំ"</string>
</resources>
diff --git a/service/res/values-kn/strings.xml b/service/res/values-kn/strings.xml
index f5d36b2..67e0811 100644
--- a/service/res/values-kn/strings.xml
+++ b/service/res/values-kn/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"ಕಾರ್ ಫೀಚರ್ಗಳನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ ಅಥವಾ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"ಕಾರ್ ಫೀಚರ್ಗಳನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ ಅಥವಾ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"ನನ್ನ ಸಾಧನ"</string>
</resources>
diff --git a/service/res/values-ko/strings.xml b/service/res/values-ko/strings.xml
index 04a1185..b69c9d5 100644
--- a/service/res/values-ko/strings.xml
+++ b/service/res/values-ko/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"차량 기능 사용 설정 또는 사용 중지"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"차량 기능 사용 설정 또는 사용 중지"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"내 기기"</string>
</resources>
diff --git a/service/res/values-ky/strings.xml b/service/res/values-ky/strings.xml
index d20da61..b24e8b7 100644
--- a/service/res/values-ky/strings.xml
+++ b/service/res/values-ky/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Унаанын функцияларын иштетүү же өчүрүү"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Унаанын функцияларын иштетүү же өчүрүү."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Түзмөгүм"</string>
</resources>
diff --git a/service/res/values-lo/strings.xml b/service/res/values-lo/strings.xml
index 7aa2623..bf12e92 100644
--- a/service/res/values-lo/strings.xml
+++ b/service/res/values-lo/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"ເປີດນຳໃຊ້ ຫຼື ປິດການນຳໃຊ້ຄຸນສົມບັດຂອງລົດ"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"ເປີດນຳໃຊ້ ຫຼື ປິດການນຳໃຊ້ຄຸນສົມບັດຂອງລົດ."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"ອຸປະກອນຂອງຂ້ອຍ"</string>
</resources>
diff --git a/service/res/values-lt/strings.xml b/service/res/values-lt/strings.xml
index 264615e..dcbae8f 100644
--- a/service/res/values-lt/strings.xml
+++ b/service/res/values-lt/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Įgalinti arba išjungti automobilio funkcijas"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Įgalinkite arba išjunkite automobilio funkcijas."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Mano įrenginys"</string>
</resources>
diff --git a/service/res/values-lv/strings.xml b/service/res/values-lv/strings.xml
index 9f22db7..af448a8 100644
--- a/service/res/values-lv/strings.xml
+++ b/service/res/values-lv/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Iespējot vai atspējot automašīnas funkcijas"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Iespējojiet vai atspējojiet automašīnas funkcijas."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Mana ierīce"</string>
</resources>
diff --git a/service/res/values-mk/strings.xml b/service/res/values-mk/strings.xml
index 09cc7f0..a969bfe 100644
--- a/service/res/values-mk/strings.xml
+++ b/service/res/values-mk/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Овозможување или оневозможување функции на автомобилот"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Овозможување или оневозможување функции на автомобилот."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Мојот уред"</string>
</resources>
diff --git a/service/res/values-ml/strings.xml b/service/res/values-ml/strings.xml
index 33cfb07..1fb8d71 100644
--- a/service/res/values-ml/strings.xml
+++ b/service/res/values-ml/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"കാറിന്റെ ഫീച്ചറുകൾ പ്രവർത്തനക്ഷമമോ പ്രവർത്തനരഹിതമോ ആക്കുക"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"കാറിന്റെ ഫീച്ചറുകൾ പ്രവർത്തനക്ഷമമോ പ്രവർത്തനരഹിതമോ ആക്കുക."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"എന്റെ ഉപകരണം"</string>
</resources>
diff --git a/service/res/values-mn/strings.xml b/service/res/values-mn/strings.xml
index 3fa74a1..b3dfa8d 100644
--- a/service/res/values-mn/strings.xml
+++ b/service/res/values-mn/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Автомашины онцлогуудыг идэвхжүүлэх эсвэл идэвхгүй болгох"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Автомашины онцлогуудыг идэвхжүүлж эсвэл идэвхгүй болгоно уу."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Миний төхөөрөмж"</string>
</resources>
diff --git a/service/res/values-mr/strings.xml b/service/res/values-mr/strings.xml
index 5e1646d..7b808c5 100644
--- a/service/res/values-mr/strings.xml
+++ b/service/res/values-mr/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"कारची वैशिष्ट्ये सुरू किंवा बंद करा"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"कारची वैशिष्ट्ये सुरू किंवा बंद करा."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"माझे डिव्हाइस"</string>
</resources>
diff --git a/service/res/values-ms/strings.xml b/service/res/values-ms/strings.xml
index 378a3e3..1e33af3 100644
--- a/service/res/values-ms/strings.xml
+++ b/service/res/values-ms/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Dayakan atau lumpuhkan ciri kereta"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Dayakan atau lumpuhkan ciri kereta."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Peranti Saya"</string>
</resources>
diff --git a/service/res/values-my/strings.xml b/service/res/values-my/strings.xml
index a40f5e2..a8f140e 100644
--- a/service/res/values-my/strings.xml
+++ b/service/res/values-my/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"ကား၏ ဝန်ဆောင်မှုများကို ပိတ်ရန် သို့မဟုတ် ပိတ်ရန်"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"ကား၏ ဝန်ဆောင်မှုများကို ဖွင့်ရန် သို့မဟုတ် ပိတ်ရန်။"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"ကျွန်ုပ်၏စက်"</string>
</resources>
diff --git a/service/res/values-nb/strings.xml b/service/res/values-nb/strings.xml
index db40e5b..e0fa6a4 100644
--- a/service/res/values-nb/strings.xml
+++ b/service/res/values-nb/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Slå bilens funksjoner på eller av"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Slå bilens funksjoner på eller av."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Enheten min"</string>
</resources>
diff --git a/service/res/values-nl/strings.xml b/service/res/values-nl/strings.xml
index c55e392..8914b1f 100644
--- a/service/res/values-nl/strings.xml
+++ b/service/res/values-nl/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Functies van de auto in- of uitschakelen"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Functies van de auto in- of uitschakelen."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Mijn apparaat"</string>
</resources>
diff --git a/service/res/values-or/strings.xml b/service/res/values-or/strings.xml
index 2564aea..c9023a0 100644
--- a/service/res/values-or/strings.xml
+++ b/service/res/values-or/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"କାରର ଫିଚର୍ଗୁଡ଼ିକୁ ସକ୍ଷମ କିମ୍ବା ଅକ୍ଷମ କରନ୍ତୁ"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"କାରର ଫିଚର୍ଗୁଡ଼ିକୁ ସକ୍ଷମ କିମ୍ବା ଅକ୍ଷମ କରନ୍ତୁ।"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"ମୋ ଡିଭାଇସ୍"</string>
</resources>
diff --git a/service/res/values-pa/strings.xml b/service/res/values-pa/strings.xml
index 0565429..4f81704 100644
--- a/service/res/values-pa/strings.xml
+++ b/service/res/values-pa/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"ਕਾਰ ਦੀਆਂ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਚਾਲੂ ਜਾਂ ਬੰਦ ਕਰੋ"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"ਕਾਰ ਦੀਆਂ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਚਾਲੂ ਜਾਂ ਬੰਦ ਕਰੋ।"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"ਮੇਰਾ ਡੀਵਾਈਸ"</string>
</resources>
diff --git a/service/res/values-pl/strings.xml b/service/res/values-pl/strings.xml
index f1cf903..9bb407c 100644
--- a/service/res/values-pl/strings.xml
+++ b/service/res/values-pl/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Włączanie i wyłączanie funkcji samochodu"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Włączanie i wyłączanie funkcji samochodu."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Moje urządzenie"</string>
</resources>
diff --git a/service/res/values-pt-rPT/strings.xml b/service/res/values-pt-rPT/strings.xml
index 0c31c54..fa45b32 100644
--- a/service/res/values-pt-rPT/strings.xml
+++ b/service/res/values-pt-rPT/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Ativar ou desativar as funcionalidades do automóvel"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Ative ou desative as funcionalidades do automóvel."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Dispositivo"</string>
</resources>
diff --git a/service/res/values-pt/strings.xml b/service/res/values-pt/strings.xml
index feafc24..a3b5ed2 100644
--- a/service/res/values-pt/strings.xml
+++ b/service/res/values-pt/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Ativar ou desativar os recursos do carro"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Ativar ou desativar os recursos do carro."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Meu dispositivo"</string>
</resources>
diff --git a/service/res/values-ro/strings.xml b/service/res/values-ro/strings.xml
index ac6a608..16e6fa4 100644
--- a/service/res/values-ro/strings.xml
+++ b/service/res/values-ro/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Activați sau dezactivați funcțiile mașinii"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Activați sau dezactivați funcțiile mașinii."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Dispozitivul meu"</string>
</resources>
diff --git a/service/res/values-ru/strings.xml b/service/res/values-ru/strings.xml
index 0da8875..7b1a10d 100644
--- a/service/res/values-ru/strings.xml
+++ b/service/res/values-ru/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Включение и отключение функций автомобиля"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Включение и отключение функций автомобиля."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Мое устройство"</string>
</resources>
diff --git a/service/res/values-si/strings.xml b/service/res/values-si/strings.xml
index b234af5..9c14d20 100644
--- a/service/res/values-si/strings.xml
+++ b/service/res/values-si/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"මෝටර් රථයේ විශේෂාංග සබල හෝ අබල කරන්න"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"මෝටර් රථයේ විශේෂාංග සබල හෝ අබල කරන්න."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"මගේ උපාංගය"</string>
</resources>
diff --git a/service/res/values-sk/strings.xml b/service/res/values-sk/strings.xml
index f9a506c..db03691 100644
--- a/service/res/values-sk/strings.xml
+++ b/service/res/values-sk/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Povoliť alebo zakázať funkcie auta"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Povoľte alebo zakážte funkcie auta."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Moje zariadenie"</string>
</resources>
diff --git a/service/res/values-sl/strings.xml b/service/res/values-sl/strings.xml
index 70dfe32..f86a63c 100644
--- a/service/res/values-sl/strings.xml
+++ b/service/res/values-sl/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Omogočanje ali onemogočanje funkcij avtomobila."</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Omogočanje ali onemogočanje funkcij avtomobila."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Moja naprava"</string>
</resources>
diff --git a/service/res/values-sq/strings.xml b/service/res/values-sq/strings.xml
index be397a3..81a89ab 100644
--- a/service/res/values-sq/strings.xml
+++ b/service/res/values-sq/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Aktivizo ose çaktivizo veçoritë e makinës"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Aktivizo ose çaktivizo veçoritë e makinës."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Pajisja ime"</string>
</resources>
diff --git a/service/res/values-sr/strings.xml b/service/res/values-sr/strings.xml
index 6c845f2..989e1fd 100644
--- a/service/res/values-sr/strings.xml
+++ b/service/res/values-sr/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Омогућавање или онемогућавање функција аутомобила"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Омогућавање или онемогућавање функција аутомобила."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Мој уређај"</string>
</resources>
diff --git a/service/res/values-sv/strings.xml b/service/res/values-sv/strings.xml
index 55fe5c6..05a1c11 100644
--- a/service/res/values-sv/strings.xml
+++ b/service/res/values-sv/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Aktivera eller inaktivera funktioner i bilen"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Aktivera eller inaktivera funktioner i bilen."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Min enhet"</string>
</resources>
diff --git a/service/res/values-sw/strings.xml b/service/res/values-sw/strings.xml
index 6057799..48e8864 100644
--- a/service/res/values-sw/strings.xml
+++ b/service/res/values-sw/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Washa au uzime vipengele vya gari"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Washa au uzime vipengele vya gari."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Kifaa Changu"</string>
</resources>
diff --git a/service/res/values-ta/strings.xml b/service/res/values-ta/strings.xml
index 44cd094..6f8a0df 100644
--- a/service/res/values-ta/strings.xml
+++ b/service/res/values-ta/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"காரின் அம்சங்களை இயக்கும் அல்லது முடக்கும்"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"காரின் அம்சங்களை இயக்கும் அல்லது முடக்கும்."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"எனது சாதனம்"</string>
</resources>
diff --git a/service/res/values-th/strings.xml b/service/res/values-th/strings.xml
index a94a676..f0584da 100644
--- a/service/res/values-th/strings.xml
+++ b/service/res/values-th/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"เปิดหรือปิดใช้ฟีเจอร์ของรถยนต์"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"เปิดหรือปิดใช้ฟีเจอร์ของรถยนต์"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"อุปกรณ์ของฉัน"</string>
</resources>
diff --git a/service/res/values-tl/strings.xml b/service/res/values-tl/strings.xml
index 181bbe8..1944897 100644
--- a/service/res/values-tl/strings.xml
+++ b/service/res/values-tl/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"I-enable o i-disable ang mga feature ng kotse."</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"I-enable o i-disable ang mga feature ng kotse."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Aking Device"</string>
</resources>
diff --git a/service/res/values-tr/strings.xml b/service/res/values-tr/strings.xml
index c1fc8fe..ef9bfb9 100644
--- a/service/res/values-tr/strings.xml
+++ b/service/res/values-tr/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Arabanın özelliklerini etkinleştirin veya devre dışı bırakın"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Arabanın özelliklerini etkinleştirin veya devre dışı bırakın."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Cihazım"</string>
</resources>
diff --git a/service/res/values-uk/strings.xml b/service/res/values-uk/strings.xml
index 7be2722..e1f1b5c 100644
--- a/service/res/values-uk/strings.xml
+++ b/service/res/values-uk/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Вмикати чи вимикати функції автомобіля"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Вмикати чи вимикати функції автомобіля"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Мій пристрій"</string>
</resources>
diff --git a/service/res/values-ur/strings.xml b/service/res/values-ur/strings.xml
index d0758f8..c7c2474 100644
--- a/service/res/values-ur/strings.xml
+++ b/service/res/values-ur/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"کار کی خصوصیات کو فعال یا غیر فعال کریں"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"کار کی خصوصیات کو فعال یا غیر فعال کریں۔"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"میرا آلہ"</string>
</resources>
diff --git a/service/res/values-uz/strings.xml b/service/res/values-uz/strings.xml
index 9e0bc06..5bfbccd 100644
--- a/service/res/values-uz/strings.xml
+++ b/service/res/values-uz/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Avtomobil funksiyalarini yoqish yoki faolsizlantirish"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Avtomobil funksiyalarini yoqish yoki faolsizlantirish"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Qurilmam"</string>
</resources>
diff --git a/service/res/values-vi/strings.xml b/service/res/values-vi/strings.xml
index f53ad02..699aa6c 100644
--- a/service/res/values-vi/strings.xml
+++ b/service/res/values-vi/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Bật hoặc tắt các tính năng của ô tô"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Bật hoặc tắt các tính năng của ô tô."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Thiết bị của tôi"</string>
</resources>
diff --git a/service/res/values-zh-rCN/strings.xml b/service/res/values-zh-rCN/strings.xml
index fdb86f7..531e2f7 100644
--- a/service/res/values-zh-rCN/strings.xml
+++ b/service/res/values-zh-rCN/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"启用或停用汽车的功能"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"启用或停用汽车的功能。"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"我的设备"</string>
</resources>
diff --git a/service/res/values-zh-rHK/strings.xml b/service/res/values-zh-rHK/strings.xml
index eb6b25a..3f8f3fc 100644
--- a/service/res/values-zh-rHK/strings.xml
+++ b/service/res/values-zh-rHK/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"啟用或停用汽車的功能"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"啟用或停用汽車的功能。"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"我的裝置"</string>
</resources>
diff --git a/service/res/values-zh-rTW/strings.xml b/service/res/values-zh-rTW/strings.xml
index 163eb0f..ee45563 100644
--- a/service/res/values-zh-rTW/strings.xml
+++ b/service/res/values-zh-rTW/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"啟用或停用車輛的功能"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"啟用或停用車輛的功能。"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"我的裝置"</string>
</resources>
diff --git a/service/res/values-zu/strings.xml b/service/res/values-zu/strings.xml
index f6b49a1..3b794bd 100644
--- a/service/res/values-zu/strings.xml
+++ b/service/res/values-zu/strings.xml
@@ -275,5 +275,7 @@
<skip />
<!-- no translation found for car_permission_desc_set_car_vendor_category_10 (6353592281201463231) -->
<skip />
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Nika amandla noma khubaza izici zemoto."</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Nika amandla noma khubaza izici zemoto."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Idivayisi yami"</string>
</resources>
diff --git a/service/res/values/strings.xml b/service/res/values/strings.xml
index a24c240..61ec62f 100644
--- a/service/res/values/strings.xml
+++ b/service/res/values/strings.xml
@@ -271,184 +271,184 @@
<string name="car_permission_desc_car_test_service">Control car\u2019s test mode</string>
<!-- Permission text: apps control vendor properties related with window [CHAR LIMIT=NONE] -->
- <string name="car_permission_label_set_car_vendor_category_window">control vendor specific window properties</string>
+ <string name="car_permission_label_set_car_vendor_category_window" translatable="false">control vendor specific window properties</string>
<!-- Permission text: apps control vendor properties related with window [CHAR LIMIT=NONE] -->
- <string name="car_permission_desc_set_car_vendor_category_window">Control vendor specific window properties.</string>
+ <string name="car_permission_desc_set_car_vendor_category_window" translatable="false">Control vendor specific window properties.</string>
<!-- Permission text: apps access vendor properties related with window [CHAR LIMIT=NONE] -->
- <string name="car_permission_label_get_car_vendor_category_window">access vendor specific window properties</string>
+ <string name="car_permission_label_get_car_vendor_category_window" translatable="false">access vendor specific window properties</string>
<!-- Permission text: apps access vendor properties related with window [CHAR LIMIT=NONE] -->
- <string name="car_permission_desc_get_car_vendor_category_window">Access vendor specific window properties.</string>
+ <string name="car_permission_desc_get_car_vendor_category_window" translatable="false">Access vendor specific window properties.</string>
<!-- Permission text: apps control vendor properties related with door [CHAR LIMIT=NONE] -->
- <string name="car_permission_label_set_car_vendor_category_door">control vendor specific door properties</string>
+ <string name="car_permission_label_set_car_vendor_category_door" translatable="false">control vendor specific door properties</string>
<!-- Permission text: apps control vendor properties related with door [CHAR LIMIT=NONE] -->
- <string name="car_permission_desc_set_car_vendor_category_door">Control vendor specific door properties.</string>
+ <string name="car_permission_desc_set_car_vendor_category_door" translatable="false">Control vendor specific door properties.</string>
<!-- Permission text: apps access vendor properties related with door [CHAR LIMIT=NONE] -->
- <string name="car_permission_label_get_car_vendor_category_door">access vendor specific door properties</string>
+ <string name="car_permission_label_get_car_vendor_category_door" translatable="false">access vendor specific door properties</string>
<!-- Permission text: apps access vendor properties related with door [CHAR LIMIT=NONE] -->
- <string name="car_permission_desc_get_car_vendor_category_door">Access vendor specific door properties.</string>
+ <string name="car_permission_desc_get_car_vendor_category_door" translatable="false">Access vendor specific door properties.</string>
<!-- Permission text: apps control vendor properties related with seat [CHAR LIMIT=NONE] -->
- <string name="car_permission_label_set_car_vendor_category_seat">control vendor specific seat properties</string>
+ <string name="car_permission_label_set_car_vendor_category_seat" translatable="false">control vendor specific seat properties</string>
<!-- Permission text: apps control vendor properties related with seat [CHAR LIMIT=NONE] -->
- <string name="car_permission_desc_set_car_vendor_category_seat">Control vendor specific seat properties.</string>
+ <string name="car_permission_desc_set_car_vendor_category_seat" translatable="false">Control vendor specific seat properties.</string>
<!-- Permission text: apps access vendor properties related with seat [CHAR LIMIT=NONE] -->
- <string name="car_permission_label_get_car_vendor_category_seat">access vendor specific seat properties</string>
+ <string name="car_permission_label_get_car_vendor_category_seat" translatable="false">access vendor specific seat properties</string>
<!-- Permission text: apps access vendor properties related with seat [CHAR LIMIT=NONE] -->
- <string name="car_permission_desc_get_car_vendor_category_seat">Access vendor specific seat properties.</string>
+ <string name="car_permission_desc_get_car_vendor_category_seat" translatable="false">Access vendor specific seat properties.</string>
<!-- Permission text: apps control vendor properties related with mirror [CHAR LIMIT=NONE] -->
- <string name="car_permission_label_set_car_vendor_category_mirror">control vendor specific mirror properties</string>
+ <string name="car_permission_label_set_car_vendor_category_mirror" translatable="false">control vendor specific mirror properties</string>
<!-- Permission text: apps control vendor properties related with mirror [CHAR LIMIT=NONE] -->
- <string name="car_permission_desc_set_car_vendor_category_mirror">Control vendor specific mirror properties.</string>
+ <string name="car_permission_desc_set_car_vendor_category_mirror" translatable="false">Control vendor specific mirror properties.</string>
<!-- Permission text: apps access vendor properties related with mirror [CHAR LIMIT=NONE] -->
- <string name="car_permission_label_get_car_vendor_category_mirror">access vendor specific mirror properties</string>
+ <string name="car_permission_label_get_car_vendor_category_mirror" translatable="false">access vendor specific mirror properties</string>
<!-- Permission text: apps access vendor properties related with mirror [CHAR LIMIT=NONE] -->
- <string name="car_permission_desc_get_car_vendor_category_mirror">Access vendor specific mirror properties.</string>
+ <string name="car_permission_desc_get_car_vendor_category_mirror" translatable="false">Access vendor specific mirror properties.</string>
<!-- Permission text: apps control vendor properties related with info [CHAR LIMIT=NONE] -->
- <string name="car_permission_label_set_car_vendor_category_info">control vendor specific information properties</string>
+ <string name="car_permission_label_set_car_vendor_category_info" translatable="false">control vendor specific information properties</string>
<!-- Permission text: apps control vendor properties related with info [CHAR LIMIT=NONE] -->
- <string name="car_permission_desc_set_car_vendor_category_info">Control vendor specific information properties.</string>
+ <string name="car_permission_desc_set_car_vendor_category_info" translatable="false">Control vendor specific information properties.</string>
<!-- Permission text: apps access vendor properties related with info [CHAR LIMIT=NONE] -->
- <string name="car_permission_label_get_car_vendor_category_info">access vendor specific information properties</string>
+ <string name="car_permission_label_get_car_vendor_category_info" translatable="false">access vendor specific information properties</string>
<!-- Permission text: apps access vendor properties related with info [CHAR LIMIT=NONE] -->
- <string name="car_permission_desc_get_car_vendor_category_info">Access vendor specific information properties.</string>
+ <string name="car_permission_desc_get_car_vendor_category_info" translatable="false">Access vendor specific information properties.</string>
<!-- Permission text: apps control vendor properties related with engine [CHAR LIMIT=NONE] -->
- <string name="car_permission_label_set_car_vendor_category_engine">control vendor specific engine properties</string>
+ <string name="car_permission_label_set_car_vendor_category_engine" translatable="false">control vendor specific engine properties</string>
<!-- Permission text: apps control vendor properties related with engine [CHAR LIMIT=NONE] -->
- <string name="car_permission_desc_set_car_vendor_category_engine">Control vendor specific engine properties.</string>
+ <string name="car_permission_desc_set_car_vendor_category_engine" translatable="false">Control vendor specific engine properties.</string>
<!-- Permission text: apps access vendor properties related with engine [CHAR LIMIT=NONE] -->
- <string name="car_permission_label_get_car_vendor_category_engine">access vendor specific engine properties</string>
+ <string name="car_permission_label_get_car_vendor_category_engine" translatable="false">access vendor specific engine properties</string>
<!-- Permission text: apps access vendor properties related with engine [CHAR LIMIT=NONE] -->
- <string name="car_permission_desc_get_car_vendor_category_engine">Access vendor specific engine properties.</string>
+ <string name="car_permission_desc_get_car_vendor_category_engine" translatable="false">Access vendor specific engine properties.</string>
<!-- Permission text: apps control vendor properties related with hvac [CHAR LIMIT=NONE] -->
- <string name="car_permission_label_set_car_vendor_category_hvac">control vendor specific hvac properties</string>
+ <string name="car_permission_label_set_car_vendor_category_hvac" translatable="false">control vendor specific hvac properties</string>
<!-- Permission text: apps control vendor properties related with hvac [CHAR LIMIT=NONE] -->
- <string name="car_permission_desc_set_car_vendor_category_hvac">Control vendor specific hvac properties.</string>
+ <string name="car_permission_desc_set_car_vendor_category_hvac" translatable="false">Control vendor specific hvac properties.</string>
<!-- Permission text: apps access vendor properties related with hvac [CHAR LIMIT=NONE] -->
- <string name="car_permission_label_get_car_vendor_category_hvac">access vendor specific hvac properties</string>
+ <string name="car_permission_label_get_car_vendor_category_hvac" translatable="false">access vendor specific hvac properties</string>
<!-- Permission text: apps access vendor properties related with hvac [CHAR LIMIT=NONE] -->
- <string name="car_permission_desc_get_car_vendor_category_hvac">Access vendor specific hvac properties.</string>
+ <string name="car_permission_desc_get_car_vendor_category_hvac" translatable="false">Access vendor specific hvac properties.</string>
<!-- Permission text: apps control vendor properties related with light [CHAR LIMIT=NONE] -->
- <string name="car_permission_label_set_car_vendor_category_light">control vendor specific light properties</string>
+ <string name="car_permission_label_set_car_vendor_category_light" translatable="false">control vendor specific light properties</string>
<!-- Permission text: apps control vendor properties related with light [CHAR LIMIT=NONE] -->
- <string name="car_permission_desc_set_car_vendor_category_light">Control vendor specific light properties.</string>
+ <string name="car_permission_desc_set_car_vendor_category_light" translatable="false">Control vendor specific light properties.</string>
<!-- Permission text: apps access vendor properties related with light [CHAR LIMIT=NONE] -->
- <string name="car_permission_label_get_car_vendor_category_light">access vendor specific light properties</string>
+ <string name="car_permission_label_get_car_vendor_category_light" translatable="false">access vendor specific light properties</string>
<!-- Permission text: apps access vendor properties related with light [CHAR LIMIT=NONE] -->
- <string name="car_permission_desc_get_car_vendor_category_light">Access vendor specific light properties.</string>
+ <string name="car_permission_desc_get_car_vendor_category_light" translatable="false">Access vendor specific light properties.</string>
<!-- Permission text: apps access properties in category 1 [CHAR LIMIT=NONE] -->
- <string name="car_permission_label_get_car_vendor_category_1">access vendor specific properties in category 1</string>
+ <string name="car_permission_label_get_car_vendor_category_1" translatable="false">access vendor specific properties in category 1</string>
<!-- Permission text: apps access vendor properties in category 1 [CHAR LIMIT=NONE] -->
- <string name="car_permission_desc_get_car_vendor_category_1">Access vendor specific properties in category 1.</string>
+ <string name="car_permission_desc_get_car_vendor_category_1" translatable="false">Access vendor specific properties in category 1.</string>
<!-- Permission text: apps access vendor properties in category 2 [CHAR LIMIT=NONE] -->
- <string name="car_permission_label_get_car_vendor_category_2">access vendor specific properties in category 2</string>
+ <string name="car_permission_label_get_car_vendor_category_2" translatable="false">access vendor specific properties in category 2</string>
<!-- Permission text: apps access vendor properties in category 2 [CHAR LIMIT=NONE] -->
- <string name="car_permission_desc_get_car_vendor_category_2">Access vendor specific properties in category 2.</string>
+ <string name="car_permission_desc_get_car_vendor_category_2" translatable="false">Access vendor specific properties in category 2.</string>
<!-- Permission text: apps access properties in category 3 [CHAR LIMIT=NONE] -->
- <string name="car_permission_label_get_car_vendor_category_3">access vendor specific properties in category 3</string>
+ <string name="car_permission_label_get_car_vendor_category_3" translatable="false">access vendor specific properties in category 3</string>
<!-- Permission text: apps access properties in category 3 [CHAR LIMIT=NONE] -->
- <string name="car_permission_desc_get_car_vendor_category_3">Access vendor specific properties in category 3.</string>
+ <string name="car_permission_desc_get_car_vendor_category_3" translatable="false">Access vendor specific properties in category 3.</string>
<!-- Permission text: apps access vendor properties in category 4 [CHAR LIMIT=NONE] -->
- <string name="car_permission_label_get_car_vendor_category_4">access vendor specific properties in category 4</string>
+ <string name="car_permission_label_get_car_vendor_category_4" translatable="false">access vendor specific properties in category 4</string>
<!-- Permission text: apps access vendor properties in category 4 [CHAR LIMIT=NONE] -->
- <string name="car_permission_desc_get_car_vendor_category_4">Access vendor specific properties in category 4.</string>
+ <string name="car_permission_desc_get_car_vendor_category_4" translatable="false">Access vendor specific properties in category 4.</string>
<!-- Permission text: apps access vendor properties in category 5 [CHAR LIMIT=NONE] -->
- <string name="car_permission_label_get_car_vendor_category_5">access vendor specific properties in category 5</string>
+ <string name="car_permission_label_get_car_vendor_category_5" translatable="false">access vendor specific properties in category 5</string>
<!-- Permission text: apps access vendor properties in category 5 [CHAR LIMIT=NONE] -->
- <string name="car_permission_desc_get_car_vendor_category_5">Access vendor specific properties in category 5.</string>
+ <string name="car_permission_desc_get_car_vendor_category_5" translatable="false">Access vendor specific properties in category 5.</string>
<!-- Permission text: apps access vendor properties in category 6 [CHAR LIMIT=NONE] -->
- <string name="car_permission_label_get_car_vendor_category_6">access vendor specific properties in category 6</string>
+ <string name="car_permission_label_get_car_vendor_category_6" translatable="false">access vendor specific properties in category 6</string>
<!-- Permission text: apps access and control vendor properties in category 6 [CHAR LIMIT=NONE] -->
- <string name="car_permission_desc_get_car_vendor_category_6">Access vendor specific properties in category 6.</string>
+ <string name="car_permission_desc_get_car_vendor_category_6" translatable="false">Access vendor specific properties in category 6.</string>
<!-- Permission text: apps access vendor properties in category 7 [CHAR LIMIT=NONE] -->
- <string name="car_permission_label_get_car_vendor_category_7">access vendor specific properties in category 7</string>
+ <string name="car_permission_label_get_car_vendor_category_7" translatable="false">access vendor specific properties in category 7</string>
<!-- Permission text: apps access vendor properties in category 7 [CHAR LIMIT=NONE] -->
- <string name="car_permission_desc_get_car_vendor_category_7">Access vendor specific properties in category 7.</string>
+ <string name="car_permission_desc_get_car_vendor_category_7" translatable="false">Access vendor specific properties in category 7.</string>
<!-- Permission text: apps access vendor properties in category 8 [CHAR LIMIT=NONE] -->
- <string name="car_permission_label_get_car_vendor_category_8">access vendor specific properties in category 8</string>
+ <string name="car_permission_label_get_car_vendor_category_8" translatable="false">access vendor specific properties in category 8</string>
<!-- Permission text: apps access vendor properties in category 8 [CHAR LIMIT=NONE] -->
- <string name="car_permission_desc_get_car_vendor_category_8">Access vendor specific properties in category 8.</string>
+ <string name="car_permission_desc_get_car_vendor_category_8" translatable="false">Access vendor specific properties in category 8.</string>
<!-- Permission text: apps access vendor properties in category 9 [CHAR LIMIT=NONE] -->
- <string name="car_permission_label_get_car_vendor_category_9">access vendor specific properties in category 9</string>
+ <string name="car_permission_label_get_car_vendor_category_9" translatable="false">access vendor specific properties in category 9</string>
<!-- Permission text: apps access vendor properties in category 9 [CHAR LIMIT=NONE] -->
- <string name="car_permission_desc_get_car_vendor_category_9">Access vendor specific properties in category 9.</string>
+ <string name="car_permission_desc_get_car_vendor_category_9" translatable="false">Access vendor specific properties in category 9.</string>
<!-- Permission text: apps access vendor properties in category 10 [CHAR LIMIT=NONE] -->
- <string name="car_permission_label_get_car_vendor_category_10">access vendor specific properties in category 10</string>
+ <string name="car_permission_label_get_car_vendor_category_10" translatable="false">access vendor specific properties in category 10</string>
<!-- Permission text: apps access vendor properties in category 10 [CHAR LIMIT=NONE] -->
- <string name="car_permission_desc_get_car_vendor_category_10">Access vendor specific properties in category 10.</string>
+ <string name="car_permission_desc_get_car_vendor_category_10" translatable="false">Access vendor specific properties in category 10.</string>
<!-- Permission text: apps control vendor properties in category 1 [CHAR LIMIT=NONE] -->
- <string name="car_permission_label_set_car_vendor_category_1">control vendor specific properties in category 1</string>
+ <string name="car_permission_label_set_car_vendor_category_1" translatable="false">control vendor specific properties in category 1</string>
<!-- Permission text: apps control vendor properties in category 1 [CHAR LIMIT=NONE] -->
- <string name="car_permission_desc_set_car_vendor_category_1">Control vendor specific properties in category 1.</string>
+ <string name="car_permission_desc_set_car_vendor_category_1" translatable="false">Control vendor specific properties in category 1.</string>
<!-- Permission text: apps control vendor properties in category 2 [CHAR LIMIT=NONE] -->
- <string name="car_permission_label_set_car_vendor_category_2">control vendor specific properties in category 2</string>
+ <string name="car_permission_label_set_car_vendor_category_2" translatable="false">control vendor specific properties in category 2</string>
<!-- Permission text: apps control vendor properties in category 2 [CHAR LIMIT=NONE] -->
- <string name="car_permission_desc_set_car_vendor_category_2">Control vendor specific properties in category 2.</string>
+ <string name="car_permission_desc_set_car_vendor_category_2" translatable="false">Control vendor specific properties in category 2.</string>
<!-- Permission text: apps control vendor properties in category 3 [CHAR LIMIT=NONE] -->
- <string name="car_permission_label_set_car_vendor_category_3">control vendor specific properties in category 3</string>
+ <string name="car_permission_label_set_car_vendor_category_3" translatable="false">control vendor specific properties in category 3</string>
<!-- Permission text: apps control vendor properties in category 3 [CHAR LIMIT=NONE] -->
- <string name="car_permission_desc_set_car_vendor_category_3">Control vendor specific properties in category 3.</string>
+ <string name="car_permission_desc_set_car_vendor_category_3" translatable="false">Control vendor specific properties in category 3.</string>
<!-- Permission text: apps control vendor properties in category 4 [CHAR LIMIT=NONE] -->
- <string name="car_permission_label_set_car_vendor_category_4">control vendor specific properties in category 4</string>
+ <string name="car_permission_label_set_car_vendor_category_4" translatable="false">control vendor specific properties in category 4</string>
<!-- Permission text: apps control vendor properties in category 4 [CHAR LIMIT=NONE] -->
- <string name="car_permission_desc_set_car_vendor_category_4">Control vendor specific properties in category 4.</string>
+ <string name="car_permission_desc_set_car_vendor_category_4" translatable="false">Control vendor specific properties in category 4.</string>
<!-- Permission text: apps control vendor properties in category 5 [CHAR LIMIT=NONE] -->
- <string name="car_permission_label_set_car_vendor_category_5">control vendor specific properties in category 5</string>
+ <string name="car_permission_label_set_car_vendor_category_5" translatable="false">control vendor specific properties in category 5</string>
<!-- Permission text: apps control vendor properties in category 5 [CHAR LIMIT=NONE] -->
- <string name="car_permission_desc_set_car_vendor_category_5">Control vendor specific properties in category 5.</string>
+ <string name="car_permission_desc_set_car_vendor_category_5" translatable="false">Control vendor specific properties in category 5.</string>
<!-- Permission text: apps control vendor properties in category 6 [CHAR LIMIT=NONE] -->
- <string name="car_permission_label_set_car_vendor_category_6">control vendor specific properties in category 6</string>
+ <string name="car_permission_label_set_car_vendor_category_6" translatable="false">control vendor specific properties in category 6</string>
<!-- Permission text: apps control vendor properties in category 6 [CHAR LIMIT=NONE] -->
- <string name="car_permission_desc_set_car_vendor_category_6">Control vendor specific properties in category 6.</string>
+ <string name="car_permission_desc_set_car_vendor_category_6" translatable="false">Control vendor specific properties in category 6.</string>
<!-- Permission text: apps control vendor properties in category 7 [CHAR LIMIT=NONE] -->
- <string name="car_permission_label_set_car_vendor_category_7">control vendor specific properties in category 7</string>
+ <string name="car_permission_label_set_car_vendor_category_7" translatable="false">control vendor specific properties in category 7</string>
<!-- Permission text: apps control vendor properties in category 7 [CHAR LIMIT=NONE] -->
- <string name="car_permission_desc_set_car_vendor_category_7">Control vendor specific properties in category 7.</string>
+ <string name="car_permission_desc_set_car_vendor_category_7" translatable="false">Control vendor specific properties in category 7.</string>
<!-- Permission text: apps control vendor properties in category 8 [CHAR LIMIT=NONE] -->
- <string name="car_permission_label_set_car_vendor_category_8">control vendor specific properties in category 8</string>
+ <string name="car_permission_label_set_car_vendor_category_8" translatable="false">control vendor specific properties in category 8</string>
<!-- Permission text: apps control vendor properties in category 8 [CHAR LIMIT=NONE] -->
- <string name="car_permission_desc_set_car_vendor_category_8">Control vendor specific properties in category 8.</string>
+ <string name="car_permission_desc_set_car_vendor_category_8" translatable="false">Control vendor specific properties in category 8.</string>
<!-- Permission text: apps control vendor properties in category 9 [CHAR LIMIT=NONE] -->
- <string name="car_permission_label_set_car_vendor_category_9">control vendor specific properties in category 9</string>
+ <string name="car_permission_label_set_car_vendor_category_9" translatable="false">control vendor specific properties in category 9</string>
<!-- Permission text: apps control vendor properties in category 9 [CHAR LIMIT=NONE] -->
- <string name="car_permission_desc_set_car_vendor_category_9">Control vendor specific properties in category 9.</string>
+ <string name="car_permission_desc_set_car_vendor_category_9" translatable="false">Control vendor specific properties in category 9.</string>
<!-- Permission text: apps control vendor properties in category 10 [CHAR LIMIT=NONE] -->
- <string name="car_permission_label_set_car_vendor_category_10">control vendor specific properties in category 10</string>
+ <string name="car_permission_label_set_car_vendor_category_10" translatable="false">control vendor specific properties in category 10</string>
<!-- Permission text: apps control vendor properties in category 10 [CHAR LIMIT=NONE] -->
- <string name="car_permission_desc_set_car_vendor_category_10">Control vendor specific properties in category 10.</string>
+ <string name="car_permission_desc_set_car_vendor_category_10" translatable="false">Control vendor specific properties in category 10.</string>
<!-- Permission text: enable or disable car's features [CHAR LIMIT=NONE] -->
<string name="car_permission_label_control_car_features">Enable or disable car\u2019s features</string>
diff --git a/service/src/com/android/car/AppFocusService.java b/service/src/com/android/car/AppFocusService.java
index bb019c2..f3a668b 100644
--- a/service/src/com/android/car/AppFocusService.java
+++ b/service/src/com/android/car/AppFocusService.java
@@ -26,16 +26,18 @@
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
+import android.util.ArraySet;
import android.util.Log;
+import android.util.SparseArray;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import java.io.PrintWriter;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
import java.util.Set;
-import java.util.concurrent.CopyOnWriteArrayList;
/**
* App focus service ensures only one instance of application type is active at a time.
@@ -46,17 +48,32 @@
private static final boolean DBG_EVENT = false;
private final SystemActivityMonitoringService mSystemActivityMonitoringService;
+
+ private final Object mLock = new Object();
+
+ @GuardedBy("mLock")
private final ClientHolder mAllChangeClients;
+
+ @GuardedBy("mLock")
private final OwnershipClientHolder mAllOwnershipClients;
+
/** K: appType, V: client owning it */
- private final HashMap<Integer, OwnershipClientInfo> mFocusOwners = new HashMap<>();
- private final Set<Integer> mActiveAppTypes = new HashSet<>();
- private final CopyOnWriteArrayList<FocusOwnershipCallback> mFocusOwnershipCallbacks =
- new CopyOnWriteArrayList<>();
+ @GuardedBy("mLock")
+ private final SparseArray<OwnershipClientInfo> mFocusOwners = new SparseArray<>();
+
+ @GuardedBy("mLock")
+ private final Set<Integer> mActiveAppTypes = new ArraySet<>();
+
+ @GuardedBy("mLock")
+ private final List<FocusOwnershipCallback> mFocusOwnershipCallbacks = new ArrayList<>();
+
private final BinderInterfaceContainer.BinderEventHandler<IAppFocusListener>
mAllBinderEventHandler = bInterface -> { /* nothing to do.*/ };
+ @GuardedBy("mLock")
private DispatchHandler mDispatchHandler;
+
+ @GuardedBy("mLock")
private HandlerThread mHandlerThread;
public AppFocusService(Context context,
@@ -68,7 +85,7 @@
@Override
public void registerFocusListener(IAppFocusListener listener, int appType) {
- synchronized (this) {
+ synchronized (mLock) {
ClientInfo info = (ClientInfo) mAllChangeClients.getBinderInterface(listener);
if (info == null) {
info = new ClientInfo(mAllChangeClients, listener, Binder.getCallingUid(),
@@ -82,7 +99,7 @@
@Override
public void unregisterFocusListener(IAppFocusListener listener, int appType) {
- synchronized (this) {
+ synchronized (mLock) {
ClientInfo info = (ClientInfo) mAllChangeClients.getBinderInterface(listener);
if (info == null) {
return;
@@ -96,26 +113,26 @@
@Override
public int[] getActiveAppTypes() {
- synchronized (this) {
- return toIntArray(mActiveAppTypes);
+ synchronized (mLock) {
+ return mActiveAppTypes.stream().mapToInt(Integer::intValue).toArray();
}
}
@Override
public boolean isOwningFocus(IAppFocusOwnershipCallback callback, int appType) {
- synchronized (this) {
- OwnershipClientInfo info =
- (OwnershipClientInfo) mAllOwnershipClients.getBinderInterface(callback);
- if (info == null) {
- return false;
- }
- return info.getOwnedAppTypes().contains(appType);
+ OwnershipClientInfo info;
+ synchronized (mLock) {
+ info = (OwnershipClientInfo) mAllOwnershipClients.getBinderInterface(callback);
}
+ if (info == null) {
+ return false;
+ }
+ return info.getOwnedAppTypes().contains(appType);
}
@Override
public int requestAppFocus(IAppFocusOwnershipCallback callback, int appType) {
- synchronized (this) {
+ synchronized (mLock) {
OwnershipClientInfo info =
(OwnershipClientInfo) mAllOwnershipClients.getBinderInterface(callback);
if (info == null) {
@@ -172,7 +189,7 @@
@Override
public void abandonAppFocus(IAppFocusOwnershipCallback callback, int appType) {
- synchronized (this) {
+ synchronized (mLock) {
OwnershipClientInfo info =
(OwnershipClientInfo) mAllOwnershipClients.getBinderInterface(callback);
if (info == null) {
@@ -188,7 +205,8 @@
// ignore as listener doesn't own focus.
return;
}
- if (mFocusOwners.remove(appType) != null) {
+ if (mFocusOwners.contains(appType)) {
+ mFocusOwners.remove(appType);
mActiveAppTypes.remove(appType);
info.removeOwnedAppType(appType);
if (DBG) {
@@ -212,7 +230,7 @@
@Override
public void init() {
- synchronized (this) {
+ synchronized (mLock) {
mHandlerThread = new HandlerThread(AppFocusService.class.getSimpleName());
mHandlerThread.start();
mDispatchHandler = new DispatchHandler(mHandlerThread.getLooper());
@@ -221,16 +239,22 @@
@VisibleForTesting
public Looper getLooper() {
- return mHandlerThread.getLooper();
+ synchronized (mLock) {
+ return mHandlerThread.getLooper();
+ }
}
@Override
public void release() {
- synchronized (this) {
+ synchronized (mLock) {
+ if (mDispatchHandler == null) {
+ return;
+ }
mHandlerThread.quitSafely();
try {
mHandlerThread.join(1000);
} catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
Log.e(CarLog.TAG_APP_FOCUS, "Timeout while waiting for handler thread to join.");
}
mDispatchHandler = null;
@@ -245,15 +269,17 @@
public void onBinderDeath(
BinderInterfaceContainer.BinderInterface<IAppFocusOwnershipCallback> bInterface) {
OwnershipClientInfo info = (OwnershipClientInfo) bInterface;
- for (Integer appType : info.getOwnedAppTypes()) {
- abandonAppFocus(bInterface.binderInterface, appType);
+ synchronized (mLock) {
+ for (Integer appType : info.getOwnedAppTypes()) {
+ abandonAppFocus(bInterface.binderInterface, appType);
+ }
}
}
@Override
public void dump(PrintWriter writer) {
writer.println("**AppFocusService**");
- synchronized (this) {
+ synchronized (mLock) {
writer.println("mActiveAppTypes:" + mActiveAppTypes);
for (BinderInterfaceContainer.BinderInterface<IAppFocusOwnershipCallback> client :
mAllOwnershipClients.getInterfaces()) {
@@ -267,8 +293,8 @@
* Returns true if process with given uid and pid owns provided focus.
*/
public boolean isFocusOwner(int uid, int pid, int appType) {
- synchronized (this) {
- if (mFocusOwners.containsKey(appType)) {
+ synchronized (mLock) {
+ if (mFocusOwners.contains(appType)) {
OwnershipClientInfo clientInfo = mFocusOwners.get(appType);
return clientInfo.getUid() == uid && clientInfo.getPid() == pid;
}
@@ -291,16 +317,15 @@
* {@link FocusOwnershipCallback#onFocusAcquired} call immediately in the same thread.
*/
public void registerContextOwnerChangedCallback(FocusOwnershipCallback callback) {
- mFocusOwnershipCallbacks.add(callback);
-
- HashSet<Map.Entry<Integer, OwnershipClientInfo>> owners;
- synchronized (this) {
- owners = new HashSet<>(mFocusOwners.entrySet());
+ SparseArray<OwnershipClientInfo> owners;
+ synchronized (mLock) {
+ mFocusOwnershipCallbacks.add(callback);
+ owners = mFocusOwners.clone();
}
-
- for (Map.Entry<Integer, OwnershipClientInfo> entry : owners) {
- OwnershipClientInfo clientInfo = entry.getValue();
- callback.onFocusAcquired(entry.getKey(), clientInfo.getUid(), clientInfo.getPid());
+ for (int idx = 0; idx < owners.size(); idx++) {
+ int key = owners.keyAt(idx);
+ OwnershipClientInfo clientInfo = owners.valueAt(idx);
+ callback.onFocusAcquired(key, clientInfo.getUid(), clientInfo.getPid());
}
}
@@ -308,16 +333,19 @@
* Unregisters provided callback.
*/
public void unregisterContextOwnerChangedCallback(FocusOwnershipCallback callback) {
- mFocusOwnershipCallbacks.remove(callback);
+ synchronized (mLock) {
+ mFocusOwnershipCallbacks.remove(callback);
+ }
}
private void updateFocusOwner(int appType, OwnershipClientInfo owner) {
CarServiceUtils.runOnMain(() -> {
- synchronized (this) {
+ List<FocusOwnershipCallback> focusOwnershipCallbacks;
+ synchronized (mLock) {
mFocusOwners.put(appType, owner);
+ focusOwnershipCallbacks = new ArrayList<>(mFocusOwnershipCallbacks);
}
-
- for (FocusOwnershipCallback callback : mFocusOwnershipCallbacks) {
+ for (FocusOwnershipCallback callback : focusOwnershipCallbacks) {
callback.onFocusAcquired(appType, owner.getUid(), owner.getPid());
}
});
@@ -357,11 +385,13 @@
}
}
- private static class ClientInfo extends
+ private class ClientInfo extends
BinderInterfaceContainer.BinderInterface<IAppFocusListener> {
private final int mUid;
private final int mPid;
- private final Set<Integer> mAppTypes = new HashSet<>();
+
+ @GuardedBy("AppFocusService.mLock")
+ private final Set<Integer> mAppTypes = new ArraySet<>();
private ClientInfo(ClientHolder holder, IAppFocusListener binder, int uid, int pid,
int appType) {
@@ -371,32 +401,40 @@
this.mAppTypes.add(appType);
}
- private synchronized Set<Integer> getAppTypes() {
- return mAppTypes;
+ private Set<Integer> getAppTypes() {
+ synchronized (mLock) {
+ return Collections.unmodifiableSet(mAppTypes);
+ }
}
- private synchronized boolean addAppType(Integer appType) {
- return mAppTypes.add(appType);
+ private boolean addAppType(Integer appType) {
+ synchronized (mLock) {
+ return mAppTypes.add(appType);
+ }
}
- private synchronized boolean removeAppType(Integer appType) {
- return mAppTypes.remove(appType);
+ private boolean removeAppType(Integer appType) {
+ synchronized (mLock) {
+ return mAppTypes.remove(appType);
+ }
}
@Override
public String toString() {
- synchronized (this) {
+ synchronized (mLock) {
return "ClientInfo{mUid=" + mUid + ",mPid=" + mPid
+ ",appTypes=" + mAppTypes + "}";
}
}
}
- private static class OwnershipClientInfo extends
+ private class OwnershipClientInfo extends
BinderInterfaceContainer.BinderInterface<IAppFocusOwnershipCallback> {
private final int mUid;
private final int mPid;
- private final Set<Integer> mOwnedAppTypes = new HashSet<>();
+
+ @GuardedBy("AppFocusService.mLock")
+ private final Set<Integer> mOwnedAppTypes = new ArraySet<>();
private OwnershipClientInfo(OwnershipClientHolder holder, IAppFocusOwnershipCallback binder,
int uid, int pid) {
@@ -405,25 +443,31 @@
this.mPid = pid;
}
- private synchronized Set<Integer> getOwnedAppTypes() {
+ private Set<Integer> getOwnedAppTypes() {
if (DBG_EVENT) {
Log.i(CarLog.TAG_APP_FOCUS, "getOwnedAppTypes " + mOwnedAppTypes);
}
- return mOwnedAppTypes;
+ synchronized (mLock) {
+ return Collections.unmodifiableSet(mOwnedAppTypes);
+ }
}
- private synchronized boolean addOwnedAppType(Integer appType) {
+ private boolean addOwnedAppType(Integer appType) {
if (DBG_EVENT) {
Log.i(CarLog.TAG_APP_FOCUS, "addOwnedAppType " + appType);
}
- return mOwnedAppTypes.add(appType);
+ synchronized (mLock) {
+ return mOwnedAppTypes.add(appType);
+ }
}
- private synchronized boolean removeOwnedAppType(Integer appType) {
+ private boolean removeOwnedAppType(Integer appType) {
if (DBG_EVENT) {
Log.i(CarLog.TAG_APP_FOCUS, "removeOwnedAppType " + appType);
}
- return mOwnedAppTypes.remove(appType);
+ synchronized (mLock) {
+ return mOwnedAppTypes.remove(appType);
+ }
}
int getUid() {
@@ -436,7 +480,7 @@
@Override
public String toString() {
- synchronized (this) {
+ synchronized (mLock) {
return "ClientInfo{mUid=" + mUid + ",mPid=" + mPid
+ ",owned=" + mOwnedAppTypes + "}";
}
@@ -488,13 +532,4 @@
}
}
}
-
- private static int[] toIntArray(Set<Integer> intSet) {
- int[] intArr = new int[intSet.size()];
- int index = 0;
- for (Integer value : intSet) {
- intArr[index++] = value;
- }
- return intArr;
- }
}
diff --git a/service/src/com/android/car/CarPowerManagementService.java b/service/src/com/android/car/CarPowerManagementService.java
index 4eb3a96..bcf120c 100644
--- a/service/src/com/android/car/CarPowerManagementService.java
+++ b/service/src/com/android/car/CarPowerManagementService.java
@@ -22,6 +22,7 @@
import android.car.hardware.power.ICarPowerStateListener;
import android.car.userlib.CarUserManagerHelper;
import android.content.Context;
+import android.content.res.Resources;
import android.hardware.automotive.vehicle.V2_0.VehicleApPowerStateReq;
import android.os.Build;
import android.os.Handler;
@@ -99,6 +100,7 @@
private boolean mIsBooting = true;
@GuardedBy("mLock")
private boolean mIsResuming;
+ private final boolean mDisableUserSwitchDuringResume;
private final CarUserManagerHelper mCarUserManagerHelper;
@@ -127,14 +129,21 @@
}
}
- public CarPowerManagementService(
- Context context, PowerHalService powerHal, SystemInterface systemInterface,
- CarUserManagerHelper carUserManagerHelper) {
+ public CarPowerManagementService(Context context, PowerHalService powerHal,
+ SystemInterface systemInterface, CarUserManagerHelper carUserManagerHelper) {
+ this(context, context.getResources(), powerHal, systemInterface, carUserManagerHelper);
+ }
+
+ @VisibleForTesting
+ CarPowerManagementService(Context context, Resources resources, PowerHalService powerHal,
+ SystemInterface systemInterface, CarUserManagerHelper carUserManagerHelper) {
mContext = context;
mHal = powerHal;
mSystemInterface = systemInterface;
mCarUserManagerHelper = carUserManagerHelper;
- sShutdownPrepareTimeMs = mContext.getResources().getInteger(
+ mDisableUserSwitchDuringResume = resources
+ .getBoolean(R.bool.config_disableUserSwitchDuringResume);
+ sShutdownPrepareTimeMs = resources.getInteger(
R.integer.maxGarageModeRunningDurationInSecs) * 1000;
if (sShutdownPrepareTimeMs < MIN_MAX_GARAGE_MODE_DURATION_MS) {
Log.w(CarLog.TAG_POWER,
@@ -157,6 +166,7 @@
mHandlerThread = null;
mHandler = new PowerHandler(Looper.getMainLooper());
mCarUserManagerHelper = null;
+ mDisableUserSwitchDuringResume = true;
}
@VisibleForTesting
@@ -169,6 +179,13 @@
}
}
+ @VisibleForTesting
+ protected HandlerThread getHandlerThread() {
+ synchronized (mLock) {
+ return mHandlerThread;
+ }
+ }
+
@Override
public void init() {
synchronized (mLock) {
@@ -231,10 +248,13 @@
}
@VisibleForTesting
- protected void clearIsBootingOrResuming() {
+ void setStateForTesting(boolean isBooting, boolean isResuming) {
synchronized (mLock) {
- mIsBooting = false;
- mIsResuming = false;
+ Log.d(CarLog.TAG_POWER, "setStateForTesting():"
+ + " booting(" + mIsBooting + ">" + isBooting + ")"
+ + " resuming(" + mIsResuming + ">" + isResuming + ")");
+ mIsBooting = isBooting;
+ mIsResuming = isResuming;
}
}
@@ -331,8 +351,7 @@
Log.i(CarLog.TAG_POWER, "User switch disallowed while booting");
} else if (mIsResuming) {
// The system is resuming after a suspension. Optionally disable user switching.
- allowUserSwitch = !mContext.getResources()
- .getBoolean(R.bool.config_disableUserSwitchDuringResume);
+ allowUserSwitch = !mDisableUserSwitchDuringResume;
mIsBooting = false;
mIsResuming = false;
if (!allowUserSwitch) {
diff --git a/service/src/com/android/car/VmsLayersAvailability.java b/service/src/com/android/car/VmsLayersAvailability.java
index 2e17a89..a9bbc7a 100644
--- a/service/src/com/android/car/VmsLayersAvailability.java
+++ b/service/src/com/android/car/VmsLayersAvailability.java
@@ -109,9 +109,6 @@
mPotentialLayersAndPublishers.clear();
mAvailableAssociatedLayers = Collections.EMPTY_SET;
mUnavailableAssociatedLayers = Collections.EMPTY_SET;
- if (mSeq + 1 < mSeq) {
- throw new IllegalStateException("Sequence is about to loop");
- }
mSeq += 1;
}
}
diff --git a/service/src/com/android/car/pm/CarPackageManagerService.java b/service/src/com/android/car/pm/CarPackageManagerService.java
index f128374..0c4a1fd 100644
--- a/service/src/com/android/car/pm/CarPackageManagerService.java
+++ b/service/src/com/android/car/pm/CarPackageManagerService.java
@@ -212,7 +212,7 @@
if (DBG_POLICY_SET) {
Log.i(CarLog.TAG_PACKAGE, "policy setting from binder call, client:" + packageName);
}
- doSetAppBlockingPolicy(packageName, policy, flags, true /*setNow*/);
+ doSetAppBlockingPolicy(packageName, policy, flags);
}
/**
@@ -223,8 +223,8 @@
mSystemActivityMonitoringService.restartTask(taskId);
}
- private void doSetAppBlockingPolicy(String packageName, CarAppBlockingPolicy policy, int flags,
- boolean setNow) {
+ private void doSetAppBlockingPolicy(String packageName, CarAppBlockingPolicy policy,
+ int flags) {
if (mContext.checkCallingOrSelfPermission(Car.PERMISSION_CONTROL_APP_BLOCKING)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException(
@@ -239,18 +239,22 @@
throw new IllegalArgumentException(
"Cannot set both FLAG_SET_POLICY_ADD and FLAG_SET_POLICY_REMOVE flag");
}
- mHandler.requestUpdatingPolicy(packageName, policy, flags);
- if (setNow) {
- mHandler.requestPolicySetting();
+ synchronized (mLock) {
if ((flags & CarPackageManager.FLAG_SET_POLICY_WAIT_FOR_CHANGE) != 0) {
- synchronized (policy) {
- try {
- policy.wait();
- } catch (InterruptedException e) {
- Log.e(CarLog.TAG_PACKAGE,
- "Interrupted wait during doSetAppBlockingPolicy");
- Thread.currentThread().interrupt();
+ mWaitingPolicies.add(policy);
+ }
+ }
+ mHandler.requestUpdatingPolicy(packageName, policy, flags);
+ if ((flags & CarPackageManager.FLAG_SET_POLICY_WAIT_FOR_CHANGE) != 0) {
+ synchronized (mLock) {
+ try {
+ while (mWaitingPolicies.contains(policy)) {
+ wait();
}
+ } catch (InterruptedException e) {
+ // Pass it over binder call
+ throw new IllegalStateException(
+ "Interrupted while waiting for policy completion", e);
}
}
}
@@ -399,7 +403,8 @@
}
mProxies.clear();
}
- wakeupClientsWaitingForPolicySettingLocked();
+ mWaitingPolicies.clear();
+ notifyAll();
}
mContext.unregisterReceiver(mPackageParsingEventReceiver);
mContext.unregisterReceiver(mUserSwitchedEventReceiver);
@@ -463,23 +468,6 @@
}
}
- @GuardedBy("mLock")
- private void wakeupClientsWaitingForPolicySettingLocked() {
- for (CarAppBlockingPolicy waitingPolicy : mWaitingPolicies) {
- synchronized (waitingPolicy) {
- waitingPolicy.notifyAll();
- }
- }
- mWaitingPolicies.clear();
- }
-
- private void doSetPolicy() {
- synchronized (mLock) {
- wakeupClientsWaitingForPolicySettingLocked();
- }
- blockTopActivitiesIfNecessary();
- }
-
private void doUpdatePolicy(String packageName, CarAppBlockingPolicy policy, int flags) {
if (DBG_POLICY_SET) {
Log.i(CarLog.TAG_PACKAGE, "setting policy from:" + packageName + ",policy:" + policy +
@@ -504,7 +492,8 @@
clientPolicy.replaceWhitelists(whitelistWrapper);
}
if ((flags & CarPackageManager.FLAG_SET_POLICY_WAIT_FOR_CHANGE) != 0) {
- mWaitingPolicies.add(policy);
+ mWaitingPolicies.remove(policy);
+ notifyAll();
}
if (DBG_POLICY_SET) {
Log.i(CarLog.TAG_PACKAGE, "policy set:" + dumpPoliciesLocked(false));
@@ -862,7 +851,6 @@
policyIntent.setAction(CarAppBlockingPolicyService.SERVICE_INTERFACE);
List<ResolveInfo> policyInfos = mPackageManager.queryIntentServices(policyIntent, 0);
if (policyInfos == null) { //no need to wait for service binding and retrieval.
- mHandler.requestPolicySetting();
return;
}
LinkedList<AppBlockingPolicyProxy> proxies = new LinkedList<>();
@@ -899,7 +887,6 @@
private void doHandlePolicyConnection(AppBlockingPolicyProxy proxy,
CarAppBlockingPolicy policy) {
- boolean shouldSetPolicy = false;
synchronized (mLock) {
if (mProxies == null) {
proxy.disconnect();
@@ -907,7 +894,6 @@
}
mProxies.remove(proxy);
if (mProxies.size() == 0) {
- shouldSetPolicy = true;
mProxies = null;
}
}
@@ -917,13 +903,10 @@
Log.i(CarLog.TAG_PACKAGE, "policy setting from policy service:" +
proxy.getPackageName());
}
- doSetAppBlockingPolicy(proxy.getPackageName(), policy, 0, false /*setNow*/);
+ doSetAppBlockingPolicy(proxy.getPackageName(), policy, 0);
}
} finally {
proxy.disconnect();
- if (shouldSetPolicy) {
- mHandler.requestPolicySetting();
- }
}
}
@@ -1194,11 +1177,10 @@
* Reading policy and setting policy can take time. Run it in a separate handler thread.
*/
private class PackageHandler extends Handler {
- private final int MSG_INIT = 0;
- private final int MSG_PARSE_PKG = 1;
- private final int MSG_SET_POLICY = 2;
- private final int MSG_UPDATE_POLICY = 3;
- private final int MSG_RELEASE = 4;
+ private static final int MSG_INIT = 0;
+ private static final int MSG_PARSE_PKG = 1;
+ private static final int MSG_UPDATE_POLICY = 2;
+ private static final int MSG_RELEASE = 3;
private PackageHandler(Looper looper) {
super(looper);
@@ -1210,17 +1192,11 @@
}
private void requestRelease() {
- removeMessages(MSG_SET_POLICY);
removeMessages(MSG_UPDATE_POLICY);
Message msg = obtainMessage(MSG_RELEASE);
sendMessage(msg);
}
- private void requestPolicySetting() {
- Message msg = obtainMessage(MSG_SET_POLICY);
- sendMessage(msg);
- }
-
private void requestUpdatingPolicy(String packageName, CarAppBlockingPolicy policy,
int flags) {
Pair<String, CarAppBlockingPolicy> pair = new Pair<>(packageName, policy);
@@ -1249,9 +1225,6 @@
case MSG_PARSE_PKG:
doParseInstalledPackages();
break;
- case MSG_SET_POLICY:
- doSetPolicy();
- break;
case MSG_UPDATE_POLICY:
Pair<String, CarAppBlockingPolicy> pair =
(Pair<String, CarAppBlockingPolicy>) msg.obj;
diff --git a/tests/BugReportApp/Android.bp b/tests/BugReportApp/Android.bp
new file mode 100644
index 0000000..5034ebf
--- /dev/null
+++ b/tests/BugReportApp/Android.bp
@@ -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.
+
+android_app {
+ name: "BugReportApp",
+
+ srcs: ["src/**/*.java"],
+
+ resource_dirs: ["res"],
+
+ platform_apis: true,
+
+ aaptflags: ["--auto-add-overlay"],
+
+ optimize: {
+ enabled: false,
+ },
+
+ certificate: "platform",
+
+ privileged: true,
+
+ dex_preopt: {
+ enabled: false,
+ },
+
+ libs: [
+ "android.car",
+ ],
+
+ static_libs: [
+ "androidx.recyclerview_recyclerview",
+ "car-br-auto-value-jar",
+ "car-br-google-api-client-android-jar",
+ "car-br-google-api-java-client-jar",
+ "car-br-google-http-client-android-jar",
+ "car-br-google-http-client-jackson2-jar",
+ "car-br-google-http-client-jar",
+ "car-br-google-oauth-client-jar",
+ "car-br-google-storage-services-jar",
+ "car-br-jackson-core-jar",
+ "car-br-grpc-context-jar",
+ "car-br-opencensus-api-jar",
+ "car-br-opencensus-contrib-http-util-jar",
+ "guava",
+ "jsr305",
+ ],
+
+ required: ["privapp_whitelist_com.android.car.bugreport"],
+
+ // Explicitly define annotation processors even if javac can find them from static_libs.
+ plugins: ["car-br-auto-value"],
+}
diff --git a/tests/BugReportApp/Android.mk b/tests/BugReportApp/Android.mk
deleted file mode 100644
index 905bb5a..0000000
--- a/tests/BugReportApp/Android.mk
+++ /dev/null
@@ -1,78 +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.
-#
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-
-LOCAL_PACKAGE_NAME := BugReportApp
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_AAPT_FLAGS := --auto-add-overlay
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-LOCAL_CERTIFICATE := platform
-
-LOCAL_PRIVILEGED_MODULE := true
-
-LOCAL_DEX_PREOPT := false
-
-LOCAL_JAVA_LIBRARIES += \
- android.car
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
- androidx.recyclerview_recyclerview \
- br_google-api-java-client \
- br_google-api-client-android \
- br_google-oauth-client \
- br_google-http-client \
- br_google-http-client-android \
- br_google-http-client-jackson2 \
- br_jackson-core \
- br_gson-2.1 \
- br_google-storage-services \
- br_apache_commons \
- guava \
- jsr305
-
-LOCAL_REQUIRED_MODULES := privapp_whitelist_com.android.car.bugreport
-
-include $(BUILD_PACKAGE)
-
-# ==== prebuilt library ========================
-include $(CLEAR_VARS)
-
-COMMON_LIBS_PATH := ../../../../../prebuilts/tools/common/m2/repository
-
-LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES := \
- br_google-api-java-client:libs/google-api-client-1.25.0.jar \
- br_google-api-client-android:libs/google-api-client-android-1.25.0.jar \
- br_google-oauth-client:libs/google-oauth-client-1.25.0.jar \
- br_google-http-client:libs/google-http-client-1.25.0.jar \
- br_google-http-client-android:libs/google-http-client-android-1.25.0.jar \
- br_jackson-core:libs/jackson-core-2.9.6.jar \
- br_gson-2.1:libs/gson-2.1.jar \
- br_google-http-client-jackson2:libs/google-http-client-jackson2-1.25.0.jar \
- br_google-storage-services:libs/google-api-services-storage-v1-rev136-1.25.0.jar \
- br_apache_commons:$(COMMON_LIBS_PATH)/org/eclipse/tycho/tycho-bundles-external/0.18.1/eclipse/plugins/org.apache.commons.codec_1.4.0.v201209201156.jar
-
-include $(BUILD_MULTI_PREBUILT)
diff --git a/tests/BugReportApp/AndroidManifest.xml b/tests/BugReportApp/AndroidManifest.xml
index cf0a7a9..3a768e8 100644
--- a/tests/BugReportApp/AndroidManifest.xml
+++ b/tests/BugReportApp/AndroidManifest.xml
@@ -16,8 +16,8 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.car.bugreport"
- android:versionCode="8"
- android:versionName="1.6.0">
+ android:versionCode="11"
+ android:versionName="1.7.0">
<uses-permission android:name="android.car.permission.CAR_DRIVING_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
@@ -29,8 +29,13 @@
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.DUMP"/>
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"/>
+ <uses-permission android:name="android.permission.READ_DEVICE_CONFIG"/>
+ <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
- <application android:label="@string/app_name" android:icon="@drawable/ic_launcher">
+ <application android:label="@string/app_name"
+ android:icon="@drawable/ic_launcher"
+ android:requestLegacyExternalStorage="true">
<activity android:name=".BugReportInfoActivity"
android:theme="@android:style/Theme.DeviceDefault.NoActionBar"
android:exported="true"
@@ -42,16 +47,26 @@
</intent-filter>
</activity>
- <!-- singleInstance allows starting bugreport dialog when BugReportInfoActivity is open. -->
+ <!--
+ singleInstance allows starting bugreport dialog when BugReportInfoActivity is open.
+ -->
<activity android:name=".BugReportActivity"
android:theme="@android:style/Theme.DeviceDefault.Dialog"
android:exported="true"
- android:launchMode="singleInstance">
+ android:launchMode="singleInstance"
+ android:excludeFromRecents="true">
<meta-data android:name="distractionOptimized" android:value="true"/>
+ <intent-filter>
+ <action android:name="com.android.car.bugreport.action.START_SILENT"/>
+ </intent-filter>
</activity>
<service android:name=".BugReportService"
- android:exported="false"/>
+ android:exported="true">
+ <intent-filter>
+ <action android:name="com.android.car.bugreport.action.START_SILENT"/>
+ </intent-filter>
+ </service>
<service android:name="com.android.car.bugreport.UploadJob"
android:permission="android.permission.BIND_JOB_SERVICE"
diff --git a/tests/BugReportApp/README.md b/tests/BugReportApp/README.md
index 63a931a..695c819 100644
--- a/tests/BugReportApp/README.md
+++ b/tests/BugReportApp/README.md
@@ -38,16 +38,31 @@
[overlayed](https://source.android.com/setup/develop/new-device#use-resource-overlays)
for specific products.
+### Config
+
+Configs are defined in `Config.java`.
+
### System Properties
-- `android.car.bugreport.disableautoupload` - set it to `true` to disable auto-upload to Google
- Cloud, and allow users to manually upload or copy the bugreports to flash drive.
+- `android.car.bugreport.enableautoupload` - please see Config#ENABLE_AUTO_UPLOAD to learn more.
+- `android.car.bugreport.force_enable` - set it `true` to enable bugreport app on **all builds**.
### Upload configuration
BugReport app uses `res/raw/gcs_credentials.json` for authentication and
`res/values/configs.xml` for obtaining GCS bucket name.
+## Starting bugreporting
+
+The app supports following intents:
+
+1. `adb shell am start com.android.car.bugreport/.BugReportActivity`
+ - generates `MetaBugReport.Type.INTERACTIVE` bug report, shows audio message dialog before
+ collecting bugreport.
+2. `adb shell am start-foreground-service -a com.android.car.bugreport.action.START_SILENT com.android.car.bugreport/.BugReportService`
+ - generates `MetaBugReport.Type.SILENT` bug report, without audio message. It shows audio dialog
+ after collecting bugreport.
+
## Testing
### Manually testing the app using the test script
diff --git a/tests/BugReportApp/libs/Android.bp b/tests/BugReportApp/libs/Android.bp
new file mode 100644
index 0000000..8f36053
--- /dev/null
+++ b/tests/BugReportApp/libs/Android.bp
@@ -0,0 +1,95 @@
+// 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.
+
+java_import {
+ name: "car-br-auto-value-jar",
+ host_supported: true,
+ sdk_version: "current",
+ jars: ["auto-value-1.5.2.jar"],
+}
+
+java_plugin {
+ name: "car-br-auto-value",
+ static_libs: [
+ "car-br-auto-value-jar",
+ "guava",
+ ],
+ processor_class: "com.google.auto.value.processor.AutoValueProcessor",
+}
+
+java_import {
+ name: "car-br-google-api-java-client-jar",
+ jars: ["google-api-client-1.30.2.jar"],
+ sdk_version: "current",
+}
+
+java_import {
+ name: "car-br-google-api-client-android-jar",
+ jars: ["google-api-client-android-1.30.2.jar"],
+ sdk_version: "current",
+}
+
+java_import {
+ name: "car-br-google-storage-services-jar",
+ jars: ["google-api-services-storage-v1-rev158-1.25.0.jar"],
+ sdk_version: "current",
+}
+
+java_import {
+ name: "car-br-google-oauth-client-jar",
+ jars: ["google-oauth-client-1.30.1.jar"],
+ sdk_version: "current",
+}
+
+java_import {
+ name: "car-br-google-http-client-jar",
+ jars: ["google-http-client-1.30.1.jar"],
+ sdk_version: "current",
+}
+
+java_import {
+ name: "car-br-google-http-client-android-jar",
+ jars: ["google-http-client-android-1.30.1.jar"],
+ sdk_version: "current",
+}
+
+java_import {
+ name: "car-br-google-http-client-jackson2-jar",
+ jars: ["google-http-client-jackson2-1.30.1.jar"],
+ sdk_version: "current",
+}
+
+java_import {
+ name: "car-br-grpc-context-jar",
+ jars: ["grpc-context-1.19.0.jar"],
+ sdk_version: "current",
+}
+
+java_import {
+ name: "car-br-jackson-core-jar",
+ jars: ["jackson-core-2.9.9.jar"],
+ sdk_version: "current",
+}
+
+java_import {
+ name: "car-br-opencensus-api-jar",
+ jars: ["opencensus-api-0.21.0.jar"],
+ sdk_version: "current",
+}
+
+java_import {
+ name: "car-br-opencensus-contrib-http-util-jar",
+ jars: ["opencensus-contrib-http-util-0.21.0.jar"],
+ sdk_version: "current",
+}
diff --git a/tests/BugReportApp/libs/auto-value-1.5.2.jar b/tests/BugReportApp/libs/auto-value-1.5.2.jar
new file mode 100644
index 0000000..8ac0567
--- /dev/null
+++ b/tests/BugReportApp/libs/auto-value-1.5.2.jar
Binary files differ
diff --git a/tests/BugReportApp/libs/google-api-client-1.25.0.jar b/tests/BugReportApp/libs/google-api-client-1.25.0.jar
deleted file mode 100644
index f1e65b2..0000000
--- a/tests/BugReportApp/libs/google-api-client-1.25.0.jar
+++ /dev/null
Binary files differ
diff --git a/tests/BugReportApp/libs/google-api-client-1.30.2.jar b/tests/BugReportApp/libs/google-api-client-1.30.2.jar
new file mode 100644
index 0000000..b2330d8
--- /dev/null
+++ b/tests/BugReportApp/libs/google-api-client-1.30.2.jar
Binary files differ
diff --git a/tests/BugReportApp/libs/google-api-client-android-1.25.0.jar b/tests/BugReportApp/libs/google-api-client-android-1.25.0.jar
deleted file mode 100644
index 2e62e7a..0000000
--- a/tests/BugReportApp/libs/google-api-client-android-1.25.0.jar
+++ /dev/null
Binary files differ
diff --git a/tests/BugReportApp/libs/google-api-client-android-1.30.2.jar b/tests/BugReportApp/libs/google-api-client-android-1.30.2.jar
new file mode 100644
index 0000000..fb04d53
--- /dev/null
+++ b/tests/BugReportApp/libs/google-api-client-android-1.30.2.jar
Binary files differ
diff --git a/tests/BugReportApp/libs/google-api-client-gson-1.25.0.jar b/tests/BugReportApp/libs/google-api-client-gson-1.25.0.jar
deleted file mode 100644
index 734491d..0000000
--- a/tests/BugReportApp/libs/google-api-client-gson-1.25.0.jar
+++ /dev/null
Binary files differ
diff --git a/tests/BugReportApp/libs/google-api-client-jackson2-1.25.0.jar b/tests/BugReportApp/libs/google-api-client-jackson2-1.25.0.jar
deleted file mode 100644
index da08ebe..0000000
--- a/tests/BugReportApp/libs/google-api-client-jackson2-1.25.0.jar
+++ /dev/null
Binary files differ
diff --git a/tests/BugReportApp/libs/google-api-services-storage-v1-rev136-1.25.0.jar b/tests/BugReportApp/libs/google-api-services-storage-v1-rev136-1.25.0.jar
deleted file mode 100644
index 2f265eb..0000000
--- a/tests/BugReportApp/libs/google-api-services-storage-v1-rev136-1.25.0.jar
+++ /dev/null
Binary files differ
diff --git a/tests/BugReportApp/libs/google-api-services-storage-v1-rev158-1.25.0.jar b/tests/BugReportApp/libs/google-api-services-storage-v1-rev158-1.25.0.jar
new file mode 100644
index 0000000..a8e58a6
--- /dev/null
+++ b/tests/BugReportApp/libs/google-api-services-storage-v1-rev158-1.25.0.jar
Binary files differ
diff --git a/tests/BugReportApp/libs/google-http-client-1.25.0.jar b/tests/BugReportApp/libs/google-http-client-1.25.0.jar
deleted file mode 100644
index 84c8ce3..0000000
--- a/tests/BugReportApp/libs/google-http-client-1.25.0.jar
+++ /dev/null
Binary files differ
diff --git a/tests/BugReportApp/libs/google-http-client-1.30.1.jar b/tests/BugReportApp/libs/google-http-client-1.30.1.jar
new file mode 100644
index 0000000..aa2ea71
--- /dev/null
+++ b/tests/BugReportApp/libs/google-http-client-1.30.1.jar
Binary files differ
diff --git a/tests/BugReportApp/libs/google-http-client-android-1.25.0.jar b/tests/BugReportApp/libs/google-http-client-android-1.25.0.jar
deleted file mode 100644
index f2bb0d4..0000000
--- a/tests/BugReportApp/libs/google-http-client-android-1.25.0.jar
+++ /dev/null
Binary files differ
diff --git a/tests/BugReportApp/libs/google-http-client-android-1.30.1.jar b/tests/BugReportApp/libs/google-http-client-android-1.30.1.jar
new file mode 100644
index 0000000..31c88a8
--- /dev/null
+++ b/tests/BugReportApp/libs/google-http-client-android-1.30.1.jar
Binary files differ
diff --git a/tests/BugReportApp/libs/google-http-client-gson-1.25.0.jar b/tests/BugReportApp/libs/google-http-client-gson-1.25.0.jar
deleted file mode 100644
index 158c0c8..0000000
--- a/tests/BugReportApp/libs/google-http-client-gson-1.25.0.jar
+++ /dev/null
Binary files differ
diff --git a/tests/BugReportApp/libs/google-http-client-jackson2-1.25.0.jar b/tests/BugReportApp/libs/google-http-client-jackson2-1.25.0.jar
deleted file mode 100644
index 34f5646..0000000
--- a/tests/BugReportApp/libs/google-http-client-jackson2-1.25.0.jar
+++ /dev/null
Binary files differ
diff --git a/tests/BugReportApp/libs/google-http-client-jackson2-1.30.1.jar b/tests/BugReportApp/libs/google-http-client-jackson2-1.30.1.jar
new file mode 100644
index 0000000..021b6b7
--- /dev/null
+++ b/tests/BugReportApp/libs/google-http-client-jackson2-1.30.1.jar
Binary files differ
diff --git a/tests/BugReportApp/libs/google-http-client-jdo-1.25.0.jar b/tests/BugReportApp/libs/google-http-client-jdo-1.25.0.jar
deleted file mode 100644
index dcb7461..0000000
--- a/tests/BugReportApp/libs/google-http-client-jdo-1.25.0.jar
+++ /dev/null
Binary files differ
diff --git a/tests/BugReportApp/libs/google-oauth-client-1.25.0.jar b/tests/BugReportApp/libs/google-oauth-client-1.25.0.jar
deleted file mode 100644
index 1304c30..0000000
--- a/tests/BugReportApp/libs/google-oauth-client-1.25.0.jar
+++ /dev/null
Binary files differ
diff --git a/tests/BugReportApp/libs/google-oauth-client-1.30.1.jar b/tests/BugReportApp/libs/google-oauth-client-1.30.1.jar
new file mode 100644
index 0000000..2489729
--- /dev/null
+++ b/tests/BugReportApp/libs/google-oauth-client-1.30.1.jar
Binary files differ
diff --git a/tests/BugReportApp/libs/grpc-context-1.19.0.jar b/tests/BugReportApp/libs/grpc-context-1.19.0.jar
new file mode 100644
index 0000000..94b2e38
--- /dev/null
+++ b/tests/BugReportApp/libs/grpc-context-1.19.0.jar
Binary files differ
diff --git a/tests/BugReportApp/libs/gson-2.1.jar b/tests/BugReportApp/libs/gson-2.1.jar
deleted file mode 100644
index 83c5c99..0000000
--- a/tests/BugReportApp/libs/gson-2.1.jar
+++ /dev/null
Binary files differ
diff --git a/tests/BugReportApp/libs/httpclient-4.5.5.jar b/tests/BugReportApp/libs/httpclient-4.5.5.jar
deleted file mode 100644
index 7796b0e..0000000
--- a/tests/BugReportApp/libs/httpclient-4.5.5.jar
+++ /dev/null
Binary files differ
diff --git a/tests/BugReportApp/libs/jackson-core-2.9.6.jar b/tests/BugReportApp/libs/jackson-core-2.9.6.jar
deleted file mode 100644
index 09e7dd2..0000000
--- a/tests/BugReportApp/libs/jackson-core-2.9.6.jar
+++ /dev/null
Binary files differ
diff --git a/tests/BugReportApp/libs/jackson-core-2.9.9.jar b/tests/BugReportApp/libs/jackson-core-2.9.9.jar
new file mode 100644
index 0000000..02bd446
--- /dev/null
+++ b/tests/BugReportApp/libs/jackson-core-2.9.9.jar
Binary files differ
diff --git a/tests/BugReportApp/libs/jdo2-api-2.3-eb.jar b/tests/BugReportApp/libs/jdo2-api-2.3-eb.jar
deleted file mode 100644
index a039ae7..0000000
--- a/tests/BugReportApp/libs/jdo2-api-2.3-eb.jar
+++ /dev/null
Binary files differ
diff --git a/tests/BugReportApp/libs/opencensus-api-0.21.0.jar b/tests/BugReportApp/libs/opencensus-api-0.21.0.jar
new file mode 100644
index 0000000..ad0646e
--- /dev/null
+++ b/tests/BugReportApp/libs/opencensus-api-0.21.0.jar
Binary files differ
diff --git a/tests/BugReportApp/libs/opencensus-contrib-http-util-0.21.0.jar b/tests/BugReportApp/libs/opencensus-contrib-http-util-0.21.0.jar
new file mode 100644
index 0000000..32f0e51
--- /dev/null
+++ b/tests/BugReportApp/libs/opencensus-contrib-http-util-0.21.0.jar
Binary files differ
diff --git a/tests/BugReportApp/res/layout/bug_info_view.xml b/tests/BugReportApp/res/layout/bug_info_view.xml
index 3736c00..199b368 100644
--- a/tests/BugReportApp/res/layout/bug_info_view.xml
+++ b/tests/BugReportApp/res/layout/bug_info_view.xml
@@ -26,99 +26,68 @@
android:orientation="vertical">
<TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="TITLE"
- android:textColor="@android:color/holo_green_light"
- android:textSize="28sp" />
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="USER"
- android:textColor="@android:color/holo_red_dark"
- android:textSize="28sp" />
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="BUG TIME"
- android:textColor="@android:color/holo_red_light"
- android:textSize="28sp" />
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="STATUS"
- android:textColor="@android:color/holo_orange_light"
- android:textSize="28sp" />
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="OTHER"
- android:textColor="@android:color/holo_blue_dark"
- android:textSize="28sp" />
-
- <Button
- android:id="@+id/bug_info_upload_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/bug_report_user_action_button_padding"
- android:textSize="@dimen/bug_report_button_text_size"
- android:text="@string/bugreport_upload_button_text" />
-
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingLeft="10dp"
- android:orientation="vertical">
-
- <TextView
android:id="@+id/bug_info_row_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
- android:textSize="28sp" />
+ android:textColor="@*android:color/car_yellow_500"
+ android:textSize="@dimen/bug_report_default_text_size" />
-
- <TextView
- android:id="@+id/bug_info_row_user"
+ <LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:textSize="28sp" />
-
-
- <TextView
- android:id="@+id/bug_info_row_timestamp"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textSize="28sp" />
-
-
- <TextView
- android:id="@+id/bug_info_row_status"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textSize="28sp" />
-
+ android:orientation="horizontal">
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginRight="@dimen/bug_report_horizontal_layout_children_margin"
+ android:text="@string/bugreport_info_status"
+ android:textSize="@dimen/bug_report_default_text_size" />
+ <TextView
+ android:id="@+id/bug_info_row_status"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="@dimen/bug_report_default_text_size" />
+ </LinearLayout>
<TextView
android:id="@+id/bug_info_row_message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:textSize="28sp" />
+ android:visibility="gone"
+ android:textSize="@dimen/bug_report_default_text_size" />
- <Button
- android:id="@+id/bug_info_move_button"
+ <LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/bug_report_user_action_button_padding"
- android:textSize="@dimen/bug_report_button_text_size"
- android:text="@string/bugreport_move_button_text" />
-
+ android:orientation="horizontal">
+ <Button
+ android:id="@+id/bug_info_add_audio_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/bug_report_user_action_button_padding"
+ android:layout_marginRight="@dimen/bug_report_horizontal_layout_children_margin"
+ android:visibility="gone"
+ android:textSize="@dimen/bug_report_button_text_size"
+ android:text="@string/bugreport_add_audio_button_text" />
+ <Button
+ android:id="@+id/bug_info_upload_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/bug_report_user_action_button_padding"
+ android:layout_marginRight="@dimen/bug_report_horizontal_layout_children_margin"
+ android:visibility="gone"
+ android:textSize="@dimen/bug_report_button_text_size"
+ android:text="@string/bugreport_upload_button_text" />
+ <Button
+ android:id="@+id/bug_info_move_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/bug_report_user_action_button_padding"
+ android:visibility="gone"
+ android:textSize="@dimen/bug_report_button_text_size"
+ android:text="@string/bugreport_move_button_text" />
+ </LinearLayout>
</LinearLayout>
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
diff --git a/tests/BugReportApp/res/layout/bug_report_activity.xml b/tests/BugReportApp/res/layout/bug_report_activity.xml
index ccb4d28..1b1907d 100644
--- a/tests/BugReportApp/res/layout/bug_report_activity.xml
+++ b/tests/BugReportApp/res/layout/bug_report_activity.xml
@@ -16,15 +16,16 @@
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:background="@color/bugreport_background"
+ android:padding="@dimen/bug_report_padding"
+ android:orientation="vertical">
<LinearLayout
android:id="@+id/submit_bug_report_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:padding="@dimen/bug_report_padding"
- android:background="@color/bugreport_background"
android:visibility="gone"
android:orientation="vertical">
<TextView
@@ -34,6 +35,16 @@
android:textColor="@color/bugreport_text"
android:gravity="center"
android:text="@string/bugreport_dialog_title"/>
+ <TextView
+ android:id="@+id/bug_report_add_audio_to_existing"
+ android:layout_marginTop="@dimen/bug_report_voice_recording_margin_top"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="@color/bugreport_text"
+ android:gravity="center"
+ android:visibility="gone"
+ android:text="@string/bugreport_dialog_add_audio_to_existing"/>
<com.android.car.bugreport.VoiceRecordingView
android:id="@+id/voice_recording_view"
android:layout_marginTop="@dimen/bug_report_voice_recording_margin_top"
@@ -65,23 +76,12 @@
android:layout_marginTop="@dimen/bug_report_button_margin_top"
android:padding="@dimen/bug_report_secondary_button_padding"
android:text="@string/bugreport_dialog_cancel"/>
- <Button
- android:id="@+id/button_show_bugreports"
- style="@style/standard_button"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/bug_report_button_margin_top"
- android:padding="@dimen/bug_report_small_button_padding"
- android:visibility="gone"
- android:text="@string/bugreport_dialog_show_bugreports"/>
</LinearLayout>
<LinearLayout
android:id="@+id/in_progress_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:background="@color/bugreport_background"
- android:padding="@dimen/bug_report_padding"
android:visibility="gone"
android:orientation="vertical">
<TextView
@@ -115,4 +115,14 @@
android:padding="@dimen/bug_report_secondary_button_padding"
android:text="@string/bugreport_dialog_close"/>
</LinearLayout>
+
+ <Button
+ android:id="@+id/button_show_bugreports"
+ style="@style/standard_button"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/bug_report_button_margin_top"
+ android:padding="@dimen/bug_report_small_button_padding"
+ android:visibility="gone"
+ android:text="@string/bugreport_dialog_show_bugreports"/>
</LinearLayout>
diff --git a/tests/BugReportApp/res/values/dimens.xml b/tests/BugReportApp/res/values/dimens.xml
index 4a5f270..7f7967f 100644
--- a/tests/BugReportApp/res/values/dimens.xml
+++ b/tests/BugReportApp/res/values/dimens.xml
@@ -19,6 +19,8 @@
<!-- Margin between edge of BugReportActivity dialog and content -->
<dimen name="bug_report_padding">30dp</dimen>
+ <dimen name="bug_report_default_text_size">28dp</dimen>
+
<!-- VoiceRecordingView dimensions -->
<dimen name="bug_report_voice_recording_margin_top">20dp</dimen>
<dimen name="bug_report_voice_recording_height">40dp</dimen>
@@ -34,4 +36,6 @@
<!-- ProgressBar dimensions -->
<dimen name="bug_report_progress_bar_margin_top">32dp</dimen>
+ <!-- Horizontal layout children margins. -->
+ <dimen name="bug_report_horizontal_layout_children_margin">12dp</dimen>
</resources>
diff --git a/tests/BugReportApp/res/values/strings.xml b/tests/BugReportApp/res/values/strings.xml
index bca00fa..b3b125a 100644
--- a/tests/BugReportApp/res/values/strings.xml
+++ b/tests/BugReportApp/res/values/strings.xml
@@ -15,35 +15,43 @@
limitations under the License.
-->
<resources>
- <string name="app_name" translatable="false">Bug Report</string>
+ <string name="app_name">Bug Report</string>
- <string name="bugreport_info_quit" translatable="false">Close</string>
- <string name="bugreport_info_start" translatable="false">Start Bug Report</string>
+ <string name="bugreport_info_quit">Close</string>
+ <string name="bugreport_info_start">Start Bug Report</string>
+ <string name="bugreport_info_status">Status:</string>
- <string name="bugreport_dialog_submit" translatable="false">Submit</string>
- <string name="bugreport_dialog_cancel" translatable="false">Cancel</string>
- <string name="bugreport_dialog_show_bugreports" translatable="false">Show Bug Reports</string>
- <string name="bugreport_dialog_close" translatable="false">Close</string>
- <string name="bugreport_dialog_title" translatable="false">Speak & Describe The Issue</string>
- <string name="bugreport_dialog_recording_finished" translatable="false">Recording finished</string>
- <string name="bugreport_dialog_in_progress_title" translatable="false">A bug report is already being collected</string>
- <string name="bugreport_dialog_in_progress_title_finished" translatable="false">A bug report has been collected</string>
- <string name="bugreport_move_button_text" translatable="false">Move</string>
- <string name="bugreport_upload_button_text" translatable="false">Upload</string>
+ <string name="bugreport_dialog_submit">Submit</string>
+ <string name="bugreport_dialog_cancel">Cancel</string>
+ <!-- A button: uploads bugreport with recorded audio message. -->
+ <string name="bugreport_dialog_upload">Upload</string>
+ <!-- A button: saves recorded audio message. -->
+ <string name="bugreport_dialog_save">Save</string>
+ <string name="bugreport_dialog_show_bugreports">Show Bug Reports</string>
+ <string name="bugreport_dialog_close">Close</string>
+ <string name="bugreport_dialog_title">Speak & Describe The Issue</string>
+ <!-- %s is the timestamp of a bugreport. -->
+ <string name="bugreport_dialog_add_audio_to_existing">Audio message for bug report at %s</string>
+ <string name="bugreport_dialog_recording_finished">Recording finished</string>
+ <string name="bugreport_dialog_in_progress_title">A bug report is already being collected</string>
+ <string name="bugreport_dialog_in_progress_title_finished">A bug report has been collected</string>
+ <!-- A button to add audio message to the bugreport. It will show Save button on the dialog. -->
+ <string name="bugreport_add_audio_button_text">Add Audio</string>
+ <!-- A button to add audio message to the bugreport; it will show Upload button on the dialog. -->
+ <string name="bugreport_add_audio_upload_button_text">Add Audio & Upload</string>
+ <string name="bugreport_move_button_text">Move to USB</string>
+ <string name="bugreport_upload_button_text">Upload</string>
+ <string name="bugreport_upload_gcs_button_text">Upload to GCS</string>
- <string name="toast_permissions_denied" translatable="false">Please grant permissions</string>
- <string name="toast_bug_report_in_progress" translatable="false">Bug report already being collected</string>
- <string name="toast_timed_out" translatable="false">Timed out, cancelling</string>
- <string name="toast_status_failed" translatable="false">Bug report failed</string>
- <string name="toast_status_finished" translatable="false">Bug report finished</string>
- <string name="toast_status_pending_upload" translatable="false">Bug report ready for upload</string>
- <string name="toast_status_screencap_failed" translatable="false">Screen capture failed</string>
- <string name="toast_status_dump_state_failed" translatable="false">Dump state failed</string>
+ <string name="toast_permissions_denied">Please grant permissions</string>
+ <string name="toast_bug_report_in_progress">Bug report already being collected</string>
+ <string name="toast_bug_report_started">Bug reporting is started</string>
+ <string name="toast_status_failed">Bug report failed</string>
+ <string name="toast_status_screencap_failed">Screen capture failed</string>
+ <string name="toast_status_dump_state_failed">Dump state failed</string>
<!-- Notification strings -->
- <string name="notification_bugreport_in_progress" translatable="false">Bug report is in progress</string>
- <string name="notification_bugreport_finished_title" translatable="false">Bug report is collected</string>
- <string name="notification_bugreport_manual_upload_finished_text" translatable="false">Please upload it when the car is parked</string>
- <string name="notification_bugreport_auto_upload_finished_text" translatable="false">The report will be upload automatically</string>
- <string name="notification_bugreport_channel_name" translatable="false">Bug report status channel</string>
+ <string name="notification_bugreport_in_progress">Bug report is in progress</string>
+ <string name="notification_bugreport_finished_title">Bug report is collected</string>
+ <string name="notification_bugreport_channel_name">Bug report status channel</string>
</resources>
diff --git a/tests/BugReportApp/src/com/android/car/bugreport/BugInfoAdapter.java b/tests/BugReportApp/src/com/android/car/bugreport/BugInfoAdapter.java
index cdc9388..4a7f1d7 100644
--- a/tests/BugReportApp/src/com/android/car/bugreport/BugInfoAdapter.java
+++ b/tests/BugReportApp/src/com/android/car/bugreport/BugInfoAdapter.java
@@ -23,63 +23,77 @@
import androidx.recyclerview.widget.RecyclerView;
+import java.util.ArrayList;
import java.util.List;
+/**
+ * Shows bugreport title, status, status message and user action buttons. "Upload to Google" button
+ * is enabled when the status is {@link Status#STATUS_PENDING_USER_ACTION}, "Move to USB" button is
+ * enabled only when status is {@link Status#STATUS_PENDING_USER_ACTION} and USB device is plugged
+ * in.
+ */
public class BugInfoAdapter extends RecyclerView.Adapter<BugInfoAdapter.BugInfoViewHolder> {
-
static final int BUTTON_TYPE_UPLOAD = 0;
static final int BUTTON_TYPE_MOVE = 1;
+ static final int BUTTON_TYPE_ADD_AUDIO = 2;
/** Provides a handler for click events*/
interface ItemClickedListener {
- /** onItemClicked handles click events differently depending on provided buttonType and
- * uses additional information provided in metaBugReport. */
- void onItemClicked(int buttonType, MetaBugReport metaBugReport);
+ /**
+ * Handles click events differently depending on provided buttonType and
+ * uses additional information provided in metaBugReport.
+ *
+ * @param buttonType One of {@link #BUTTON_TYPE_UPLOAD}, {@link #BUTTON_TYPE_MOVE} or
+ * {@link #BUTTON_TYPE_ADD_AUDIO}.
+ * @param metaBugReport Selected bugreport.
+ * @param holder ViewHolder of the clicked item.
+ */
+ void onItemClicked(int buttonType, MetaBugReport metaBugReport, BugInfoViewHolder holder);
}
/**
* Reference to each bug report info views.
*/
- public static class BugInfoViewHolder extends RecyclerView.ViewHolder {
+ static class BugInfoViewHolder extends RecyclerView.ViewHolder {
/** Title view */
- public TextView titleView;
-
- /** User view */
- public TextView userView;
-
- /** TimeStamp View */
- public TextView timestampView;
+ TextView mTitleView;
/** Status View */
- public TextView statusView;
+ TextView mStatusView;
/** Message View */
- public TextView messageView;
+ TextView mMessageView;
/** Move Button */
- public Button moveButton;
+ Button mMoveButton;
/** Upload Button */
- public Button uploadButton;
+ Button mUploadButton;
+
+ /** Add Audio Button */
+ Button mAddAudioButton;
BugInfoViewHolder(View v) {
super(v);
- titleView = itemView.findViewById(R.id.bug_info_row_title);
- userView = itemView.findViewById(R.id.bug_info_row_user);
- timestampView = itemView.findViewById(R.id.bug_info_row_timestamp);
- statusView = itemView.findViewById(R.id.bug_info_row_status);
- messageView = itemView.findViewById(R.id.bug_info_row_message);
- moveButton = itemView.findViewById(R.id.bug_info_move_button);
- uploadButton = itemView.findViewById(R.id.bug_info_upload_button);
+ mTitleView = itemView.findViewById(R.id.bug_info_row_title);
+ mStatusView = itemView.findViewById(R.id.bug_info_row_status);
+ mMessageView = itemView.findViewById(R.id.bug_info_row_message);
+ mMoveButton = itemView.findViewById(R.id.bug_info_move_button);
+ mUploadButton = itemView.findViewById(R.id.bug_info_upload_button);
+ mAddAudioButton = itemView.findViewById(R.id.bug_info_add_audio_button);
}
}
- private final List<MetaBugReport> mDataset;
+ private List<MetaBugReport> mDataset;
private final ItemClickedListener mItemClickedListener;
+ private final Config mConfig;
- BugInfoAdapter(List<MetaBugReport> dataSet, ItemClickedListener itemClickedListener) {
- mDataset = dataSet;
+ BugInfoAdapter(ItemClickedListener itemClickedListener, Config config) {
mItemClickedListener = itemClickedListener;
+ mDataset = new ArrayList<>();
+ mConfig = config;
+ // Allow RecyclerView to efficiently update UI; getItemId() is implemented below.
+ setHasStableIds(true);
}
@Override
@@ -93,22 +107,74 @@
@Override
public void onBindViewHolder(BugInfoViewHolder holder, int position) {
MetaBugReport bugreport = mDataset.get(position);
- holder.titleView.setText(mDataset.get(position).getTitle());
- holder.userView.setText(mDataset.get(position).getUsername());
- holder.timestampView.setText(mDataset.get(position).getTimestamp());
- holder.statusView.setText(Status.toString(mDataset.get(position).getStatus()));
- holder.messageView.setText(mDataset.get(position).getStatusMessage());
- if (bugreport.getStatus() == Status.STATUS_PENDING_USER_ACTION.getValue()
- || bugreport.getStatus() == Status.STATUS_MOVE_FAILED.getValue()
- || bugreport.getStatus() == Status.STATUS_UPLOAD_FAILED.getValue()) {
- holder.moveButton.setOnClickListener(
- view -> mItemClickedListener.onItemClicked(BUTTON_TYPE_MOVE, bugreport));
- holder.uploadButton.setOnClickListener(
- view -> mItemClickedListener.onItemClicked(BUTTON_TYPE_UPLOAD, bugreport));
+ holder.mTitleView.setText(bugreport.getTitle());
+ holder.mStatusView.setText(Status.toString(bugreport.getStatus()));
+ holder.mMessageView.setText(bugreport.getStatusMessage());
+ if (bugreport.getStatusMessage().isEmpty()) {
+ holder.mMessageView.setVisibility(View.GONE);
} else {
- holder.moveButton.setEnabled(false);
- holder.uploadButton.setEnabled(false);
+ holder.mMessageView.setVisibility(View.VISIBLE);
}
+ boolean enableUserActionButtons =
+ bugreport.getStatus() == Status.STATUS_PENDING_USER_ACTION.getValue()
+ || bugreport.getStatus() == Status.STATUS_MOVE_FAILED.getValue()
+ || bugreport.getStatus() == Status.STATUS_UPLOAD_FAILED.getValue();
+ if (enableUserActionButtons) {
+ holder.mMoveButton.setEnabled(true);
+ holder.mMoveButton.setVisibility(View.VISIBLE);
+ holder.mMoveButton.setOnClickListener(
+ view -> mItemClickedListener.onItemClicked(BUTTON_TYPE_MOVE, bugreport,
+ holder));
+ } else {
+ holder.mMoveButton.setEnabled(false);
+ holder.mMoveButton.setVisibility(View.GONE);
+ }
+ // Always enable upload to GCS button, because the app is enabled only for userdebug,
+ // and sometimes Config might not be properly set.
+ if (enableUserActionButtons) {
+ holder.mUploadButton.setText(R.string.bugreport_upload_gcs_button_text);
+ holder.mUploadButton.setEnabled(true);
+ holder.mUploadButton.setVisibility(View.VISIBLE);
+ holder.mUploadButton.setOnClickListener(
+ view -> mItemClickedListener.onItemClicked(BUTTON_TYPE_UPLOAD, bugreport,
+ holder));
+ } else {
+ holder.mUploadButton.setVisibility(View.GONE);
+ holder.mUploadButton.setEnabled(false);
+ }
+ if (bugreport.getStatus() == Status.STATUS_AUDIO_PENDING.getValue()) {
+ if (mConfig.getAutoUpload()) {
+ holder.mAddAudioButton.setText(R.string.bugreport_add_audio_upload_button_text);
+ } else {
+ holder.mAddAudioButton.setText(R.string.bugreport_add_audio_button_text);
+ }
+ holder.mAddAudioButton.setEnabled(true);
+ holder.mAddAudioButton.setVisibility(View.VISIBLE);
+ holder.mAddAudioButton.setOnClickListener(view ->
+ mItemClickedListener.onItemClicked(BUTTON_TYPE_ADD_AUDIO, bugreport, holder));
+ } else {
+ holder.mAddAudioButton.setEnabled(false);
+ holder.mAddAudioButton.setVisibility(View.GONE);
+ }
+ }
+
+ /** Sets dataSet; it copies the list, because it modifies it in this adapter. */
+ void setDataset(List<MetaBugReport> bugReports) {
+ mDataset = new ArrayList<>(bugReports);
+ notifyDataSetChanged();
+ }
+
+ /** Update a bug report in the data set. */
+ void updateBugReportInDataSet(MetaBugReport bugReport, int position) {
+ if (position != RecyclerView.NO_POSITION) {
+ mDataset.set(position, bugReport);
+ notifyItemChanged(position);
+ }
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return mDataset.get(position).getId();
}
@Override
diff --git a/tests/BugReportApp/src/com/android/car/bugreport/BugReportActivity.java b/tests/BugReportApp/src/com/android/car/bugreport/BugReportActivity.java
index 9c41277..5f9a231 100644
--- a/tests/BugReportApp/src/com/android/car/bugreport/BugReportActivity.java
+++ b/tests/BugReportApp/src/com/android/car/bugreport/BugReportActivity.java
@@ -15,7 +15,6 @@
*/
package com.android.car.bugreport;
-import static com.android.car.bugreport.BugReportService.EXTRA_META_BUG_REPORT;
import static com.android.car.bugreport.BugReportService.MAX_PROGRESS_VALUE;
import android.Manifest;
@@ -25,6 +24,7 @@
import android.car.drivingstate.CarDrivingStateEvent;
import android.car.drivingstate.CarDrivingStateManager;
import android.content.ComponentName;
+import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
@@ -41,14 +41,19 @@
import android.util.Log;
import android.view.View;
import android.view.Window;
+import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
+import com.google.common.base.Preconditions;
+import com.google.common.io.ByteStreams;
+
import java.io.File;
+import java.io.FileInputStream;
import java.io.IOException;
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
+import java.io.InputStream;
+import java.io.OutputStream;
import java.util.Arrays;
import java.util.Date;
import java.util.Random;
@@ -65,33 +70,52 @@
public class BugReportActivity extends Activity {
private static final String TAG = BugReportActivity.class.getSimpleName();
+ /** Starts silent (no audio message recording) bugreporting. */
+ private static final String ACTION_START_SILENT =
+ "com.android.car.bugreport.action.START_SILENT";
+
+ /** This is deprecated action. Please start SILENT bugreport using {@link BugReportService}. */
+ private static final String ACTION_ADD_AUDIO =
+ "com.android.car.bugreport.action.ADD_AUDIO";
+
private static final int VOICE_MESSAGE_MAX_DURATION_MILLIS = 60 * 1000;
private static final int AUDIO_PERMISSIONS_REQUEST_ID = 1;
- private static final DateFormat BUG_REPORT_TIMESTAMP_DATE_FORMAT =
- new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss");
+ private static final String EXTRA_BUGREPORT_ID = "bugreport-id";
+ /**
+ * NOTE: mRecorder related messages are cleared when the activity finishes.
+ */
private final Handler mHandler = new Handler(Looper.getMainLooper());
+ /** Look up string length, e.g. [ABCDEF]. */
+ static final int LOOKUP_STRING_LENGTH = 6;
+
private TextView mInProgressTitleText;
private ProgressBar mProgressBar;
private TextView mProgressText;
+ private TextView mAddAudioText;
private VoiceRecordingView mVoiceRecordingView;
private View mVoiceRecordingFinishedView;
private View mSubmitBugReportLayout;
private View mInProgressLayout;
private View mShowBugReportsButton;
+ private Button mSubmitButton;
private boolean mBound;
private boolean mAudioRecordingStarted;
- private boolean mBugReportServiceStarted;
+ private boolean mIsNewBugReport;
+ private boolean mIsOnActivityStartedWithBugReportServiceBoundCalled;
+ private boolean mIsSubmitButtonClicked;
private BugReportService mService;
private MediaRecorder mRecorder;
private MetaBugReport mMetaBugReport;
+ private File mAudioFile;
private Car mCar;
private CarDrivingStateManager mDrivingStateManager;
private AudioManager mAudioManager;
private AudioFocusRequest mLastAudioFocusRequest;
+ private Config mConfig;
/** Defines callbacks for service binding, passed to bindService() */
private ServiceConnection mConnection = new ServiceConnection() {
@@ -100,7 +124,7 @@
BugReportService.ServiceBinder binder = (BugReportService.ServiceBinder) service;
mService = binder.getService();
mBound = true;
- startAudioMessageRecording();
+ onActivityStartedWithBugReportServiceBound();
}
@Override
@@ -110,7 +134,7 @@
}
};
- private final ServiceConnection mServiceConnection = new ServiceConnection() {
+ private final ServiceConnection mCarServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
try {
@@ -118,6 +142,8 @@
Car.CAR_DRIVING_STATE_SERVICE);
mDrivingStateManager.registerListener(
BugReportActivity.this::onCarDrivingStateChanged);
+ // Call onCarDrivingStateChanged(), because it's not called when Car is connected.
+ onCarDrivingStateChanged(mDrivingStateManager.getCurrentCarDrivingState());
} catch (CarNotConnectedException e) {
Log.w(TAG, "Failed to get CarDrivingStateManager.", e);
}
@@ -128,30 +154,24 @@
}
};
+ /**
+ * Builds an intent that starts {@link BugReportActivity} to add audio message to the existing
+ * bug report.
+ */
+ static Intent buildAddAudioIntent(Context context, MetaBugReport bug) {
+ Intent addAudioIntent = new Intent(context, BugReportActivity.class);
+ addAudioIntent.setAction(ACTION_ADD_AUDIO);
+ addAudioIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ addAudioIntent.putExtra(EXTRA_BUGREPORT_ID, bug.getId());
+ return addAudioIntent;
+ }
+
@Override
public void onCreate(Bundle savedInstanceState) {
+ Preconditions.checkState(Config.isBugReportEnabled(), "BugReport is disabled.");
+
super.onCreate(savedInstanceState);
-
requestWindowFeature(Window.FEATURE_NO_TITLE);
- setContentView(R.layout.bug_report_activity);
-
- mInProgressTitleText = findViewById(R.id.in_progress_title_text);
- mProgressBar = findViewById(R.id.progress_bar);
- mProgressText = findViewById(R.id.progress_text);
- mVoiceRecordingView = findViewById(R.id.voice_recording_view);
- mVoiceRecordingFinishedView = findViewById(R.id.voice_recording_finished_text_view);
- mSubmitBugReportLayout = findViewById(R.id.submit_bug_report_layout);
- mInProgressLayout = findViewById(R.id.in_progress_layout);
- mShowBugReportsButton = findViewById(R.id.button_show_bugreports);
-
- mShowBugReportsButton.setOnClickListener(this::buttonShowBugReportsClick);
- findViewById(R.id.button_submit).setOnClickListener(this::buttonSubmitClick);
- findViewById(R.id.button_cancel).setOnClickListener(this::buttonCancelClick);
- findViewById(R.id.button_close).setOnClickListener(this::buttonCancelClick);
-
- mCar = Car.createCar(this, mServiceConnection);
- mCar.connect();
- mAudioManager = getSystemService(AudioManager.class);
// Bind to BugReportService.
Intent intent = new Intent(this, BugReportService.class);
@@ -163,26 +183,35 @@
super.onStart();
if (mBound) {
- startAudioMessageRecording();
+ onActivityStartedWithBugReportServiceBound();
}
}
@Override
protected void onStop() {
super.onStop();
- if (!mBugReportServiceStarted && mAudioRecordingStarted) {
+ // If SUBMIT button is clicked, cancelling audio has been taken care of.
+ if (!mIsSubmitButtonClicked) {
cancelAudioMessageRecording();
}
if (mBound) {
mService.removeBugReportProgressListener();
}
+ // Reset variables for the next onStart().
+ mAudioRecordingStarted = false;
+ mIsSubmitButtonClicked = false;
+ mIsOnActivityStartedWithBugReportServiceBoundCalled = false;
+ mMetaBugReport = null;
+ mAudioFile = null;
}
@Override
public void onDestroy() {
super.onDestroy();
- mHandler.removeCallbacksAndMessages(null);
+ if (mRecorder != null) {
+ mHandler.removeCallbacksAndMessages(/* token= */ mRecorder);
+ }
if (mBound) {
unbindService(mConnection);
mBound = false;
@@ -194,7 +223,14 @@
}
private void onCarDrivingStateChanged(CarDrivingStateEvent event) {
- if (event.eventValue == CarDrivingStateEvent.DRIVING_STATE_PARKED) {
+ // When adding audio message to the existing bugreport, do not show "Show Bug Reports"
+ // button, users either should explicitly Submit or Cancel.
+ if (mAudioRecordingStarted && !mIsNewBugReport) {
+ mShowBugReportsButton.setVisibility(View.GONE);
+ return;
+ }
+ if (event.eventValue == CarDrivingStateEvent.DRIVING_STATE_PARKED
+ || event.eventValue == CarDrivingStateEvent.DRIVING_STATE_IDLING) {
mShowBugReportsButton.setVisibility(View.VISIBLE);
} else {
mShowBugReportsButton.setVisibility(View.GONE);
@@ -210,6 +246,43 @@
}
}
+ private void prepareUi() {
+ if (mSubmitBugReportLayout != null) {
+ return;
+ }
+ setContentView(R.layout.bug_report_activity);
+
+ // Connect to the services here, because they are used only when showing the dialog.
+ // We need to minimize system state change when performing SILENT bug report.
+ mConfig = new Config();
+ mConfig.start();
+ mCar = Car.createCar(this, mCarServiceConnection);
+ mCar.connect();
+
+ mInProgressTitleText = findViewById(R.id.in_progress_title_text);
+ mProgressBar = findViewById(R.id.progress_bar);
+ mProgressText = findViewById(R.id.progress_text);
+ mAddAudioText = findViewById(R.id.bug_report_add_audio_to_existing);
+ mVoiceRecordingView = findViewById(R.id.voice_recording_view);
+ mVoiceRecordingFinishedView = findViewById(R.id.voice_recording_finished_text_view);
+ mSubmitBugReportLayout = findViewById(R.id.submit_bug_report_layout);
+ mInProgressLayout = findViewById(R.id.in_progress_layout);
+ mShowBugReportsButton = findViewById(R.id.button_show_bugreports);
+ mSubmitButton = findViewById(R.id.button_submit);
+
+ mShowBugReportsButton.setOnClickListener(this::buttonShowBugReportsClick);
+ mSubmitButton.setOnClickListener(this::buttonSubmitClick);
+ findViewById(R.id.button_cancel).setOnClickListener(this::buttonCancelClick);
+ findViewById(R.id.button_close).setOnClickListener(this::buttonCancelClick);
+
+ if (mIsNewBugReport) {
+ mSubmitButton.setText(R.string.bugreport_dialog_submit);
+ } else {
+ mSubmitButton.setText(mConfig.getAutoUpload()
+ ? R.string.bugreport_dialog_upload : R.string.bugreport_dialog_save);
+ }
+ }
+
private void showInProgressUi() {
mSubmitBugReportLayout.setVisibility(View.GONE);
mInProgressLayout.setVisibility(View.VISIBLE);
@@ -231,7 +304,6 @@
mShowBugReportsButton.setVisibility(View.GONE);
if (mDrivingStateManager != null) {
try {
- // Call onCarDrivingStateChanged(), because it's not called when Car is connected.
onCarDrivingStateChanged(mDrivingStateManager.getCurrentCarDrivingState());
} catch (CarNotConnectedException e) {
Log.e(TAG, "Failed to get current driving state.", e);
@@ -244,28 +316,89 @@
*
* <p>This method expected to be called when the activity is started and bound to the service.
*/
- private void startAudioMessageRecording() {
- mService.setBugReportProgressListener(this::onProgressChanged);
+ private void onActivityStartedWithBugReportServiceBound() {
+ if (mIsOnActivityStartedWithBugReportServiceBoundCalled) {
+ return;
+ }
+ mIsOnActivityStartedWithBugReportServiceBoundCalled = true;
if (mService.isCollectingBugReport()) {
Log.i(TAG, "Bug report is already being collected.");
+ mService.setBugReportProgressListener(this::onProgressChanged);
+ prepareUi();
showInProgressUi();
return;
}
+ if (ACTION_START_SILENT.equals(getIntent().getAction())) {
+ Log.i(TAG, "Starting a silent bugreport.");
+ MetaBugReport bugReport = createBugReport(this, MetaBugReport.TYPE_SILENT);
+ startBugReportCollection(bugReport);
+ finish();
+ return;
+ }
+
+ // Close the notification shade and other dialogs when showing BugReportActivity dialog.
+ sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
+
+ if (ACTION_ADD_AUDIO.equals(getIntent().getAction())) {
+ addAudioToExistingBugReport(
+ getIntent().getIntExtra(EXTRA_BUGREPORT_ID, /* defaultValue= */ -1));
+ return;
+ }
+
+ Log.i(TAG, "Starting an interactive bugreport.");
+ createNewBugReportWithAudioMessage();
+ }
+
+ private void addAudioToExistingBugReport(int bugreportId) {
+ MetaBugReport bug = BugStorageUtils.findBugReport(this, bugreportId).orElseThrow(
+ () -> new RuntimeException("Failed to find bug report with id " + bugreportId));
+ Log.i(TAG, "Adding audio to the existing bugreport " + bug.getTimestamp());
+ if (bug.getStatus() != Status.STATUS_AUDIO_PENDING.getValue()) {
+ Log.e(TAG, "Failed to add audio, bad status, expected "
+ + Status.STATUS_AUDIO_PENDING.getValue() + ", got " + bug.getStatus());
+ finish();
+ }
+ File audioFile;
+ try {
+ audioFile = File.createTempFile("audio", "mp3", getCacheDir());
+ } catch (IOException e) {
+ throw new RuntimeException("failed to create temp audio file");
+ }
+ startAudioMessageRecording(/* isNewBugReport= */ false, bug, audioFile);
+ }
+
+ private void createNewBugReportWithAudioMessage() {
+ MetaBugReport bug = createBugReport(this, MetaBugReport.TYPE_INTERACTIVE);
+ startAudioMessageRecording(
+ /* isNewBugReport= */ true,
+ bug,
+ FileUtils.getFileWithSuffix(this, bug.getTimestamp(), "-message.3gp"));
+ }
+
+ /** Shows a dialog UI and starts recording audio message. */
+ private void startAudioMessageRecording(
+ boolean isNewBugReport, MetaBugReport bug, File audioFile) {
if (mAudioRecordingStarted) {
Log.i(TAG, "Audio message recording is already started.");
return;
}
-
mAudioRecordingStarted = true;
+ mAudioManager = getSystemService(AudioManager.class);
+ mIsNewBugReport = isNewBugReport;
+ mMetaBugReport = bug;
+ mAudioFile = audioFile;
+ prepareUi();
showSubmitBugReportUi(/* isRecording= */ true);
-
- Date initiatedAt = new Date();
- String timestamp = BUG_REPORT_TIMESTAMP_DATE_FORMAT.format(initiatedAt);
- String username = getCurrentUserName();
- String title = BugReportTitleGenerator.generateBugReportTitle(initiatedAt, username);
- mMetaBugReport = BugStorageUtils.createBugReport(this, title, timestamp, username);
+ if (isNewBugReport) {
+ mAddAudioText.setVisibility(View.GONE);
+ } else {
+ mAddAudioText.setVisibility(View.VISIBLE);
+ mAddAudioText.setText(String.format(
+ getString(R.string.bugreport_dialog_add_audio_to_existing),
+ mMetaBugReport.getTimestamp()));
+ }
if (!hasRecordPermissions()) {
requestRecordPermissions();
@@ -282,10 +415,17 @@
return;
}
stopAudioRecording();
- File tempDir = FileUtils.getTempDir(this, mMetaBugReport.getTimestamp());
- new DeleteDirectoryAsyncTask().execute(tempDir);
- BugStorageUtils.setBugReportStatus(this, mMetaBugReport, Status.STATUS_USER_CANCELLED, "");
- Log.i(TAG, "Bug report is cancelled");
+ if (mIsNewBugReport) {
+ // The app creates a temp dir only for new INTERACTIVE bugreports.
+ File tempDir = FileUtils.getTempDir(this, mMetaBugReport.getTimestamp());
+ new DeleteFilesAndDirectoriesAsyncTask().execute(tempDir);
+ } else {
+ BugStorageUtils.deleteBugReportFiles(this, mMetaBugReport.getId());
+ new DeleteFilesAndDirectoriesAsyncTask().execute(mAudioFile);
+ }
+ BugStorageUtils.setBugReportStatus(
+ this, mMetaBugReport, Status.STATUS_USER_CANCELLED, "");
+ Log.i(TAG, "Bug report " + mMetaBugReport.getTimestamp() + " is cancelled");
mAudioRecordingStarted = false;
}
@@ -294,36 +434,46 @@
}
private void buttonSubmitClick(View view) {
- startBugReportingInService();
+ stopAudioRecording();
+ mIsSubmitButtonClicked = true;
+ if (mIsNewBugReport) {
+ Log.i(TAG, "Starting bugreport service.");
+ startBugReportCollection(mMetaBugReport);
+ } else {
+ Log.i(TAG, "Adding audio file to the bugreport " + mMetaBugReport.getTimestamp());
+ new AddAudioToBugReportAsyncTask(this, mConfig, mMetaBugReport, mAudioFile).execute();
+ }
+ setResult(Activity.RESULT_OK);
finish();
}
+ /** Starts the {@link BugReportService} to collect bug report. */
+ private void startBugReportCollection(MetaBugReport bug) {
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(BugReportService.EXTRA_META_BUG_REPORT, bug);
+ Intent intent = new Intent(this, BugReportService.class);
+ intent.putExtras(bundle);
+ startForegroundService(intent);
+ }
+
/**
* Starts {@link BugReportInfoActivity} and finishes current activity, so it won't be running
- * in the background and closing {@link BugReportInfoActivity} will not open it again.
+ * in the background and closing {@link BugReportInfoActivity} will not open the current
+ * activity again.
*/
private void buttonShowBugReportsClick(View view) {
+ // First cancel the audio recording, then delete the bug report from database.
cancelAudioMessageRecording();
// Delete the bugreport from database, otherwise pressing "Show Bugreports" button will
// create unnecessary cancelled bugreports.
if (mMetaBugReport != null) {
- BugStorageUtils.deleteBugReport(this, mMetaBugReport.getId());
+ BugStorageUtils.completeDeleteBugReport(this, mMetaBugReport.getId());
}
Intent intent = new Intent(this, BugReportInfoActivity.class);
startActivity(intent);
finish();
}
- private void startBugReportingInService() {
- stopAudioRecording();
- Bundle bundle = new Bundle();
- bundle.putParcelable(EXTRA_META_BUG_REPORT, mMetaBugReport);
- Intent intent = new Intent(this, BugReportService.class);
- intent.putExtras(bundle);
- startService(intent);
- mBugReportServiceStarted = true;
- }
-
private void requestRecordPermissions() {
requestPermissions(
new String[]{Manifest.permission.RECORD_AUDIO}, AUDIO_PERMISSIONS_REQUEST_ID);
@@ -343,7 +493,9 @@
for (int i = 0; i < grantResults.length; i++) {
if (Manifest.permission.RECORD_AUDIO.equals(permissions[i])
&& grantResults[i] == PackageManager.PERMISSION_GRANTED) {
- startRecordingWithPermission();
+ // Start recording from UI thread, otherwise when MediaRecord#start() fails,
+ // stack trace gets confusing.
+ mHandler.post(this::startRecordingWithPermission);
return;
}
}
@@ -361,9 +513,7 @@
}
private void startRecordingWithPermission() {
- File recordingFile = FileUtils.getFileWithSuffix(this, mMetaBugReport.getTimestamp(),
- "-message.3gp");
- Log.i(TAG, "Started voice recording, and saving audio to " + recordingFile);
+ Log.i(TAG, "Started voice recording, and saving audio to " + mAudioFile);
mLastAudioFocusRequest = new AudioFocusRequest.Builder(
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE)
@@ -388,12 +538,12 @@
Log.i(TAG, "OnMediaRecorderInfo: what=" + what + ", extra=" + extra));
mRecorder.setOnErrorListener((MediaRecorder recorder, int what, int extra) ->
Log.i(TAG, "OnMediaRecorderError: what=" + what + ", extra=" + extra));
- mRecorder.setOutputFile(recordingFile);
+ mRecorder.setOutputFile(mAudioFile);
try {
mRecorder.prepare();
} catch (IOException e) {
- Log.e(TAG, "Failed on MediaRecorder#prepare(), filename: " + recordingFile, e);
+ Log.e(TAG, "Failed on MediaRecorder#prepare(), filename: " + mAudioFile, e);
finish();
return;
}
@@ -401,19 +551,21 @@
mRecorder.start();
mVoiceRecordingView.setRecorder(mRecorder);
+ // Messages with token mRecorder are cleared when the activity finishes or recording stops.
mHandler.postDelayed(() -> {
Log.i(TAG, "Timed out while recording voice message, cancelling.");
stopAudioRecording();
showSubmitBugReportUi(/* isRecording= */ false);
- }, VOICE_MESSAGE_MAX_DURATION_MILLIS);
+ }, /* token= */ mRecorder, VOICE_MESSAGE_MAX_DURATION_MILLIS);
}
private void stopAudioRecording() {
if (mRecorder != null) {
Log.i(TAG, "Recording ended, stopping the MediaRecorder.");
+ mHandler.removeCallbacksAndMessages(/* token= */ mRecorder);
try {
mRecorder.stop();
- } catch (IllegalStateException e) {
+ } catch (RuntimeException e) {
// Sometimes MediaRecorder doesn't start and stopping it throws an error.
// We just log these cases, no need to crash the app.
Log.w(TAG, "Couldn't stop media recorder", e);
@@ -430,11 +582,24 @@
mVoiceRecordingView.setRecorder(null);
}
- private String getCurrentUserName() {
- UserManager um = UserManager.get(this);
+ private static String getCurrentUserName(Context context) {
+ UserManager um = UserManager.get(context);
return um.getUserName();
}
+ /**
+ * Creates a {@link MetaBugReport} and saves it in a local sqlite database.
+ *
+ * @param context an Android context.
+ * @param type bug report type, {@link MetaBugReport.BugReportType}.
+ */
+ static MetaBugReport createBugReport(Context context, int type) {
+ String timestamp = MetaBugReport.toBugReportTimestamp(new Date());
+ String username = getCurrentUserName(context);
+ String title = BugReportTitleGenerator.generateBugReportTitle(timestamp, username);
+ return BugStorageUtils.createBugReport(context, title, timestamp, username, type);
+ }
+
/** A helper class to generate bugreport title. */
private static final class BugReportTitleGenerator {
/** Contains easily readable characters. */
@@ -442,17 +607,14 @@
new char[]{'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P',
'R', 'S', 'T', 'U', 'W', 'X', 'Y', 'Z'};
- private static final int LOOKUP_STRING_LENGTH = 6;
-
/**
* Generates a bugreport title from given timestamp and username.
*
* <p>Example: "[A45E8] Feedback from user Driver at 2019-09-21_12:00:00"
*/
- static String generateBugReportTitle(Date initiatedAt, String username) {
+ static String generateBugReportTitle(String timestamp, String username) {
// Lookup string is used to search a bug in Buganizer (see b/130915969).
String lookupString = generateRandomString(LOOKUP_STRING_LENGTH);
- String timestamp = BUG_REPORT_TIMESTAMP_DATE_FORMAT.format(initiatedAt);
return "[" + lookupString + "] Feedback from user " + username + " at " + timestamp;
}
@@ -467,15 +629,66 @@
}
}
- /** AsyncTask that recursively deletes directories. */
- private static class DeleteDirectoryAsyncTask extends AsyncTask<File, Void, Void> {
+ /** AsyncTask that recursively deletes files and directories. */
+ private static class DeleteFilesAndDirectoriesAsyncTask extends AsyncTask<File, Void, Void> {
@Override
protected Void doInBackground(File... files) {
for (File file : files) {
Log.i(TAG, "Deleting " + file.getAbsolutePath());
- FileUtils.deleteDirectory(file);
+ if (file.isFile()) {
+ file.delete();
+ } else {
+ FileUtils.deleteDirectory(file);
+ }
}
return null;
}
}
+
+ /**
+ * AsyncTask that moves audio file to the system user's {@link FileUtils#getPendingDir} and
+ * sets status to either STATUS_UPLOAD_PENDING or STATUS_PENDING_USER_ACTION.
+ */
+ private static class AddAudioToBugReportAsyncTask extends AsyncTask<Void, Void, Void> {
+ private final Context mContext;
+ private final Config mConfig;
+ private final File mAudioFile;
+ private final MetaBugReport mOriginalBug;
+
+ AddAudioToBugReportAsyncTask(
+ Context context, Config config, MetaBugReport bug, File audioFile) {
+ mContext = context;
+ mConfig = config;
+ mOriginalBug = bug;
+ mAudioFile = audioFile;
+ }
+
+ @Override
+ protected Void doInBackground(Void... voids) {
+ String audioFileName = FileUtils.getAudioFileName(
+ MetaBugReport.toBugReportTimestamp(new Date()), mOriginalBug);
+ MetaBugReport bug = BugStorageUtils.update(mContext,
+ mOriginalBug.toBuilder().setAudioFileName(audioFileName).build());
+ try (OutputStream out = BugStorageUtils.openAudioMessageFileToWrite(mContext, bug);
+ InputStream input = new FileInputStream(mAudioFile)) {
+ ByteStreams.copy(input, out);
+ } catch (IOException e) {
+ BugStorageUtils.setBugReportStatus(mContext, bug,
+ com.android.car.bugreport.Status.STATUS_WRITE_FAILED,
+ "Failed to write audio to bug report");
+ Log.e(TAG, "Failed to write audio to bug report", e);
+ return null;
+ }
+ if (mConfig.getAutoUpload()) {
+ BugStorageUtils.setBugReportStatus(mContext, bug,
+ com.android.car.bugreport.Status.STATUS_UPLOAD_PENDING, "");
+ } else {
+ BugStorageUtils.setBugReportStatus(mContext, bug,
+ com.android.car.bugreport.Status.STATUS_PENDING_USER_ACTION, "");
+ BugReportService.showBugReportFinishedNotification(mContext, bug);
+ }
+ mAudioFile.delete();
+ return null;
+ }
+ }
}
diff --git a/tests/BugReportApp/src/com/android/car/bugreport/BugReportInfoActivity.java b/tests/BugReportApp/src/com/android/car/bugreport/BugReportInfoActivity.java
index 8071f99..017052a 100644
--- a/tests/BugReportApp/src/com/android/car/bugreport/BugReportInfoActivity.java
+++ b/tests/BugReportApp/src/com/android/car/bugreport/BugReportInfoActivity.java
@@ -21,9 +21,13 @@
import android.app.NotificationManager;
import android.content.ContentResolver;
import android.content.Intent;
+import android.content.res.AssetFileDescriptor;
+import android.database.ContentObserver;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.UserHandle;
import android.provider.DocumentsContract;
import android.util.Log;
import android.view.View;
@@ -33,10 +37,16 @@
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Strings;
+import com.google.common.io.ByteStreams;
+
import java.io.File;
+import java.io.FileDescriptor;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
@@ -47,105 +57,26 @@
public class BugReportInfoActivity extends Activity {
public static final String TAG = BugReportInfoActivity.class.getSimpleName();
+ /** Used for moving bug reports to a new location (e.g. USB drive). */
private static final int SELECT_DIRECTORY_REQUEST_CODE = 1;
+ /** Used to start {@link BugReportActivity} to add audio message. */
+ private static final int ADD_AUDIO_MESSAGE_REQUEST_CODE = 2;
+
private RecyclerView mRecyclerView;
- private RecyclerView.Adapter mAdapter;
+ private BugInfoAdapter mBugInfoAdapter;
private RecyclerView.LayoutManager mLayoutManager;
private NotificationManager mNotificationManager;
private MetaBugReport mLastSelectedBugReport;
-
- private static final class AsyncMoveFilesTask extends AsyncTask<Void, Void, Boolean> {
- private final BugReportInfoActivity mActivity;
- private final MetaBugReport mBugReport;
- private final Uri mDestinationDirUri;
-
- AsyncMoveFilesTask(BugReportInfoActivity activity, MetaBugReport bugReport,
- Uri destinationDir) {
- mActivity = activity;
- mBugReport = bugReport;
- mDestinationDirUri = destinationDir;
- }
-
- @Override
- protected Boolean doInBackground(Void... params) {
- Uri sourceUri = BugStorageProvider.buildUriWithBugId(mBugReport.getId());
- ContentResolver resolver = mActivity.getContentResolver();
- String documentId = DocumentsContract.getTreeDocumentId(mDestinationDirUri);
- Uri parentDocumentUri =
- DocumentsContract.buildDocumentUriUsingTree(mDestinationDirUri, documentId);
- String mimeType = resolver.getType(sourceUri);
- try {
- Uri newFileUri = DocumentsContract.createDocument(resolver, parentDocumentUri,
- mimeType,
- new File(mBugReport.getFilePath()).toPath().getFileName().toString());
- if (newFileUri == null) {
- Log.e(TAG, "Unable to create a new file.");
- return false;
- }
- try (InputStream input = resolver.openInputStream(sourceUri);
- OutputStream output = resolver.openOutputStream(newFileUri)) {
- byte[] buffer = new byte[4096];
- int len;
- while ((len = input.read(buffer)) > 0) {
- output.write(buffer, 0, len);
- }
- }
- BugStorageUtils.setBugReportStatus(
- mActivity, mBugReport,
- com.android.car.bugreport.Status.STATUS_MOVE_SUCCESSFUL, "");
- } catch (IOException e) {
- Log.e(TAG, "Failed to create the bug report in the location.", e);
- return false;
- }
- return true;
- }
-
- @Override
- protected void onPostExecute(Boolean moveSuccessful) {
- if (!moveSuccessful) {
- BugStorageUtils.setBugReportStatus(
- mActivity, mBugReport,
- com.android.car.bugreport.Status.STATUS_MOVE_FAILED, "");
- }
- // Refresh the UI to reflect the new status.
- new BugReportInfoTask(mActivity).execute();
- }
- }
-
- private static final class BugReportInfoTask extends
- AsyncTask<Void, Void, List<MetaBugReport>> {
- private final WeakReference<BugReportInfoActivity> mBugReportInfoActivityWeakReference;
-
- BugReportInfoTask(BugReportInfoActivity activity) {
- mBugReportInfoActivityWeakReference = new WeakReference<>(activity);
- }
-
- @Override
- protected List<MetaBugReport> doInBackground(Void... voids) {
- BugReportInfoActivity activity = mBugReportInfoActivityWeakReference.get();
- if (activity == null) {
- Log.w(TAG, "Activity is gone, cancelling BugReportInfoTask.");
- return new ArrayList<>();
- }
- return BugStorageUtils.getAllBugReportsDescending(activity);
- }
-
- @Override
- protected void onPostExecute(List<MetaBugReport> result) {
- BugReportInfoActivity activity = mBugReportInfoActivityWeakReference.get();
- if (activity == null) {
- Log.w(TAG, "Activity is gone, cancelling onPostExecute.");
- return;
- }
- activity.mAdapter = new BugInfoAdapter(result, activity::onBugReportItemClicked);
- activity.mRecyclerView.setAdapter(activity.mAdapter);
- activity.mRecyclerView.getAdapter().notifyDataSetChanged();
- }
- }
+ private BugInfoAdapter.BugInfoViewHolder mLastSelectedBugInfoViewHolder;
+ private BugStorageObserver mBugStorageObserver;
+ private Config mConfig;
+ private boolean mAudioRecordingStarted;
@Override
protected void onCreate(Bundle savedInstanceState) {
+ Preconditions.checkState(Config.isBugReportEnabled(), "BugReport is disabled.");
+
super.onCreate(savedInstanceState);
setContentView(R.layout.bug_report_info_activity);
@@ -159,9 +90,13 @@
mRecyclerView.addItemDecoration(new DividerItemDecoration(mRecyclerView.getContext(),
DividerItemDecoration.VERTICAL));
- // specify an adapter (see also next example)
- mAdapter = new BugInfoAdapter(new ArrayList<>(), this::onBugReportItemClicked);
- mRecyclerView.setAdapter(mAdapter);
+ mConfig = new Config();
+ mConfig.start();
+
+ mBugInfoAdapter = new BugInfoAdapter(this::onBugReportItemClicked, mConfig);
+ mRecyclerView.setAdapter(mBugInfoAdapter);
+
+ mBugStorageObserver = new BugStorageObserver(this, new Handler());
findViewById(R.id.quit_button).setOnClickListener(this::onQuitButtonClick);
findViewById(R.id.start_bug_report_button).setOnClickListener(
@@ -175,7 +110,16 @@
@Override
protected void onStart() {
super.onStart();
- new BugReportInfoTask(this).execute();
+ new BugReportsLoaderAsyncTask(this).execute();
+ // As BugStorageProvider is running under user0, we register using USER_ALL.
+ getContentResolver().registerContentObserver(BugStorageProvider.BUGREPORT_CONTENT_URI, true,
+ mBugStorageObserver, UserHandle.USER_ALL);
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ getContentResolver().unregisterContentObserver(mBugStorageObserver);
}
/**
@@ -186,17 +130,26 @@
mNotificationManager.cancel(BugReportService.BUGREPORT_FINISHED_NOTIF_ID);
}
- private void onBugReportItemClicked(int buttonType, MetaBugReport bugReport) {
+ private void onBugReportItemClicked(
+ int buttonType, MetaBugReport bugReport, BugInfoAdapter.BugInfoViewHolder holder) {
if (buttonType == BugInfoAdapter.BUTTON_TYPE_UPLOAD) {
- Log.i(TAG, "Uploading " + bugReport.getFilePath());
+ Log.i(TAG, "Uploading " + bugReport.getTimestamp());
BugStorageUtils.setBugReportStatus(this, bugReport, Status.STATUS_UPLOAD_PENDING, "");
// Refresh the UI to reflect the new status.
- new BugReportInfoTask(this).execute();
+ new BugReportsLoaderAsyncTask(this).execute();
} else if (buttonType == BugInfoAdapter.BUTTON_TYPE_MOVE) {
- Log.i(TAG, "Moving " + bugReport.getFilePath());
+ Log.i(TAG, "Moving " + bugReport.getTimestamp());
mLastSelectedBugReport = bugReport;
+ mLastSelectedBugInfoViewHolder = holder;
startActivityForResult(new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE),
SELECT_DIRECTORY_REQUEST_CODE);
+ } else if (buttonType == BugInfoAdapter.BUTTON_TYPE_ADD_AUDIO) {
+ // Check mAudioRecordingStarted to prevent double click to BUTTON_TYPE_ADD_AUDIO.
+ if (!mAudioRecordingStarted) {
+ mAudioRecordingStarted = true;
+ startActivityForResult(BugReportActivity.buildAddAudioIntent(this, bugReport),
+ ADD_AUDIO_MESSAGE_REQUEST_CODE);
+ }
} else {
throw new IllegalStateException("unreachable");
}
@@ -211,11 +164,20 @@
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
Uri destDirUri = data.getData();
getContentResolver().takePersistableUriPermission(destDirUri, takeFlags);
- if (mLastSelectedBugReport == null) {
+ if (mLastSelectedBugReport == null || mLastSelectedBugInfoViewHolder == null) {
Log.w(TAG, "No bug report is selected.");
return;
}
- new AsyncMoveFilesTask(this, mLastSelectedBugReport, destDirUri).execute();
+ MetaBugReport updatedBugReport = BugStorageUtils.setBugReportStatus(this,
+ mLastSelectedBugReport, Status.STATUS_MOVE_IN_PROGRESS, "");
+ mBugInfoAdapter.updateBugReportInDataSet(
+ updatedBugReport, mLastSelectedBugInfoViewHolder.getAdapterPosition());
+ new AsyncMoveFilesTask(
+ this,
+ mBugInfoAdapter,
+ updatedBugReport,
+ mLastSelectedBugInfoViewHolder,
+ destDirUri).execute();
}
}
@@ -230,4 +192,161 @@
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
}
+
+ /**
+ * Print the Provider's state into the given stream. This gets invoked if
+ * you run "adb shell dumpsys activity BugReportInfoActivity".
+ *
+ * @param prefix Desired prefix to prepend at each line of output.
+ * @param fd The raw file descriptor that the dump is being sent to.
+ * @param writer The PrintWriter to which you should dump your state. This will be
+ * closed for you after you return.
+ * @param args additional arguments to the dump request.
+ */
+ public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
+ super.dump(prefix, fd, writer, args);
+ mConfig.dump(prefix, writer);
+ }
+
+ /**
+ * Moves bugreport zip to USB drive and updates RecyclerView.
+ *
+ * <p>It merges bugreport zip file and audio file into one final zip file and moves it.
+ */
+ private static final class AsyncMoveFilesTask extends AsyncTask<Void, Void, MetaBugReport> {
+ private final BugReportInfoActivity mActivity;
+ private final MetaBugReport mBugReport;
+ private final Uri mDestinationDirUri;
+ /** RecyclerView.Adapter that contains all the bug reports. */
+ private final BugInfoAdapter mBugInfoAdapter;
+ /** ViewHolder for {@link #mBugReport}. */
+ private final BugInfoAdapter.BugInfoViewHolder mBugViewHolder;
+ private final ContentResolver mResolver;
+
+ AsyncMoveFilesTask(BugReportInfoActivity activity, BugInfoAdapter bugInfoAdapter,
+ MetaBugReport bugReport, BugInfoAdapter.BugInfoViewHolder holder,
+ Uri destinationDir) {
+ mActivity = activity;
+ mBugInfoAdapter = bugInfoAdapter;
+ mBugReport = bugReport;
+ mBugViewHolder = holder;
+ mDestinationDirUri = destinationDir;
+ mResolver = mActivity.getContentResolver();
+ }
+
+ /** Moves the bugreport to the USB drive and returns the updated {@link MetaBugReport}. */
+ @Override
+ protected MetaBugReport doInBackground(Void... params) {
+ try {
+ return copyFilesToUsb();
+ } catch (IOException e) {
+ Log.e(TAG, "Failed to copy bugreport "
+ + mBugReport.getTimestamp() + " to USB", e);
+ return BugStorageUtils.setBugReportStatus(
+ mActivity, mBugReport,
+ com.android.car.bugreport.Status.STATUS_MOVE_FAILED, e);
+ }
+ }
+
+ private MetaBugReport copyFilesToUsb() throws IOException {
+ String documentId = DocumentsContract.getTreeDocumentId(mDestinationDirUri);
+ Uri parentDocumentUri =
+ DocumentsContract.buildDocumentUriUsingTree(mDestinationDirUri, documentId);
+ if (!Strings.isNullOrEmpty(mBugReport.getFilePath())) {
+ // There are still old bugreports with deprecated filePath.
+ Uri sourceUri = BugStorageProvider.buildUriWithSegment(
+ mBugReport.getId(), BugStorageProvider.URL_SEGMENT_OPEN_FILE);
+ copyFileToUsb(
+ new File(mBugReport.getFilePath()).getName(), sourceUri, parentDocumentUri);
+ } else {
+ Uri sourceBugReport = BugStorageProvider.buildUriWithSegment(
+ mBugReport.getId(), BugStorageProvider.URL_SEGMENT_OPEN_BUGREPORT_FILE);
+ copyFileToUsb(
+ mBugReport.getBugReportFileName(), sourceBugReport, parentDocumentUri);
+ Uri sourceAudio = BugStorageProvider.buildUriWithSegment(
+ mBugReport.getId(), BugStorageProvider.URL_SEGMENT_OPEN_AUDIO_FILE);
+ copyFileToUsb(mBugReport.getAudioFileName(), sourceAudio, parentDocumentUri);
+ }
+ Log.d(TAG, "Deleting local bug report files.");
+ BugStorageUtils.deleteBugReportFiles(mActivity, mBugReport.getId());
+ return BugStorageUtils.setBugReportStatus(mActivity, mBugReport,
+ com.android.car.bugreport.Status.STATUS_MOVE_SUCCESSFUL,
+ "Moved to: " + mDestinationDirUri.getPath());
+ }
+
+ private void copyFileToUsb(String filename, Uri sourceUri, Uri parentDocumentUri)
+ throws IOException {
+ String mimeType = mResolver.getType(sourceUri);
+ Uri newFileUri = DocumentsContract.createDocument(
+ mResolver, parentDocumentUri, mimeType, filename);
+ if (newFileUri == null) {
+ throw new IOException("Unable to create a file " + filename + " in USB");
+ }
+ try (InputStream input = mResolver.openInputStream(sourceUri);
+ AssetFileDescriptor fd = mResolver.openAssetFileDescriptor(newFileUri, "w")) {
+ OutputStream output = fd.createOutputStream();
+ ByteStreams.copy(input, output);
+ // Force sync the written data from memory to the disk.
+ fd.getFileDescriptor().sync();
+ }
+ }
+
+ @Override
+ protected void onPostExecute(MetaBugReport updatedBugReport) {
+ // Refresh the UI to reflect the new status.
+ mBugInfoAdapter.updateBugReportInDataSet(
+ updatedBugReport, mBugViewHolder.getAdapterPosition());
+ }
+ }
+
+ /** Asynchronously loads bugreports from {@link BugStorageProvider}. */
+ private static final class BugReportsLoaderAsyncTask extends
+ AsyncTask<Void, Void, List<MetaBugReport>> {
+ private final WeakReference<BugReportInfoActivity> mBugReportInfoActivityWeakReference;
+
+ BugReportsLoaderAsyncTask(BugReportInfoActivity activity) {
+ mBugReportInfoActivityWeakReference = new WeakReference<>(activity);
+ }
+
+ @Override
+ protected List<MetaBugReport> doInBackground(Void... voids) {
+ BugReportInfoActivity activity = mBugReportInfoActivityWeakReference.get();
+ if (activity == null) {
+ Log.w(TAG, "Activity is gone, cancelling BugReportsLoaderAsyncTask.");
+ return new ArrayList<>();
+ }
+ return BugStorageUtils.getAllBugReportsDescending(activity);
+ }
+
+ @Override
+ protected void onPostExecute(List<MetaBugReport> result) {
+ BugReportInfoActivity activity = mBugReportInfoActivityWeakReference.get();
+ if (activity == null) {
+ Log.w(TAG, "Activity is gone, cancelling onPostExecute.");
+ return;
+ }
+ activity.mBugInfoAdapter.setDataset(result);
+ }
+ }
+
+ /** Observer for {@link BugStorageProvider}. */
+ private static class BugStorageObserver extends ContentObserver {
+ private final BugReportInfoActivity mInfoActivity;
+
+ /**
+ * Creates a content observer.
+ *
+ * @param activity A {@link BugReportInfoActivity} instance.
+ * @param handler The handler to run {@link #onChange} on, or null if none.
+ */
+ BugStorageObserver(BugReportInfoActivity activity, Handler handler) {
+ super(handler);
+ mInfoActivity = activity;
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ new BugReportsLoaderAsyncTask(mInfoActivity).execute();
+ }
+ }
}
diff --git a/tests/BugReportApp/src/com/android/car/bugreport/BugReportService.java b/tests/BugReportApp/src/com/android/car/bugreport/BugReportService.java
index 378c883..dcfeb2b 100644
--- a/tests/BugReportApp/src/com/android/car/bugreport/BugReportService.java
+++ b/tests/BugReportApp/src/com/android/car/bugreport/BugReportService.java
@@ -27,7 +27,12 @@
import android.car.Car;
import android.car.CarBugreportManager;
import android.car.CarNotConnectedException;
+import android.content.Context;
import android.content.Intent;
+import android.media.AudioManager;
+import android.media.Ringtone;
+import android.media.RingtoneManager;
+import android.net.Uri;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
@@ -38,33 +43,32 @@
import android.util.Log;
import android.widget.Toast;
+import com.google.common.base.Preconditions;
+import com.google.common.io.ByteStreams;
import com.google.common.util.concurrent.AtomicDouble;
-import libcore.io.IoUtils;
-
import java.io.BufferedOutputStream;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
-import java.io.InputStream;
import java.io.OutputStream;
-import java.util.Enumeration;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;
/**
* Service that captures screenshot and bug report using dumpstate and bluetooth snoop logs.
*
- * <p>After collecting all the logs it updates the {@link MetaBugReport} using {@link
- * BugStorageProvider}, which in turn schedules bug report to upload.
+ * <p>After collecting all the logs it sets the {@link MetaBugReport} status to
+ * {@link Status#STATUS_AUDIO_PENDING} or {@link Status#STATUS_PENDING_USER_ACTION} depending
+ * on {@link MetaBugReport#getType}.
+ *
+ * <p>If the service is started with action {@link #ACTION_START_SILENT}, it will start
+ * bugreporting without showing dialog and recording audio message, see
+ * {@link MetaBugReport#TYPE_SILENT}.
*/
public class BugReportService extends Service {
private static final String TAG = BugReportService.class.getSimpleName();
@@ -74,6 +78,10 @@
*/
static final String EXTRA_META_BUG_REPORT = "meta_bug_report";
+ /** Starts silent (no audio message recording) bugreporting. */
+ private static final String ACTION_START_SILENT =
+ "com.android.car.bugreport.action.START_SILENT";
+
// Wait a short time before starting to capture the bugreport and the screen, so that
// bugreport activity can detach from the view tree.
// It is ugly to have a timeout, but it is ok here because such a delay should not really
@@ -81,6 +89,12 @@
// this, the best option is probably to wait for onDetach events from view tree.
private static final int ACTIVITY_FINISH_DELAY_MILLIS = 1000;
+ /**
+ * Wait a short time before showing "bugreport started" toast message, because the service
+ * will take a screenshot of the screen.
+ */
+ private static final int BUGREPORT_STARTED_TOAST_DELAY_MILLIS = 2000;
+
private static final String BT_SNOOP_LOG_LOCATION = "/data/misc/bluetooth/logs/btsnoop_hci.log";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -90,9 +104,10 @@
/** Notifications on this channel will pop-up. */
private static final String STATUS_CHANNEL_ID = "BUGREPORT_STATUS_CHANNEL";
+ /** Persistent notification is shown when bugreport is in progress or waiting for audio. */
private static final int BUGREPORT_IN_PROGRESS_NOTIF_ID = 1;
- /** The notification is shown when bugreport is collected. */
+ /** Dismissible notification is shown when bugreport is collected. */
static final int BUGREPORT_FINISHED_NOTIF_ID = 2;
private static final String OUTPUT_ZIP_FILE = "output_file.zip";
@@ -119,9 +134,16 @@
private Car mCar;
private CarBugreportManager mBugreportManager;
private CarBugreportManager.CarBugreportManagerCallback mCallback;
+ private Config mConfig;
/** A handler on the main thread. */
private Handler mHandler;
+ /**
+ * A handler to the main thread to show toast messages, it will be cleared when the service
+ * finishes. We need to clear it otherwise when bugreport fails, it will show "bugreport start"
+ * toast, which will confuse users.
+ */
+ private Handler mHandlerToast;
/** A listener that's notified when bugreport progress changes. */
interface BugReportProgressListener {
@@ -141,7 +163,7 @@
}
}
- /** A handler on a main thread. */
+ /** A handler on the main thread. */
private class BugReportHandler extends Handler {
@Override
public void handleMessage(Message message) {
@@ -161,6 +183,8 @@
@Override
public void onCreate() {
+ Preconditions.checkState(Config.isBugReportEnabled(), "BugReport is disabled.");
+
mNotificationManager = getSystemService(NotificationManager.class);
mNotificationManager.createNotificationChannel(new NotificationChannel(
PROGRESS_CHANNEL_ID,
@@ -172,34 +196,58 @@
NotificationManager.IMPORTANCE_HIGH));
mSingleThreadExecutor = Executors.newSingleThreadScheduledExecutor();
mHandler = new BugReportHandler();
+ mHandlerToast = new Handler();
+ mConfig = new Config();
+ mConfig.start();
+ // Synchronously connect to the car service.
mCar = Car.createCar(this);
try {
mBugreportManager = (CarBugreportManager) mCar.getCarManager(Car.CAR_BUGREPORT_SERVICE);
} catch (CarNotConnectedException | NoClassDefFoundError e) {
- Log.w(TAG, "Couldn't get CarBugreportManager", e);
+ throw new IllegalStateException("Failed to get CarBugreportManager.", e);
}
}
@Override
+ public void onDestroy() {
+ if (DEBUG) {
+ Log.d(TAG, "Service destroyed");
+ }
+ mCar.disconnect();
+ }
+
+ @Override
public int onStartCommand(final Intent intent, int flags, int startId) {
- if (mIsCollectingBugReport.get()) {
+ if (mIsCollectingBugReport.getAndSet(true)) {
Log.w(TAG, "bug report is already being collected, ignoring");
Toast.makeText(this, R.string.toast_bug_report_in_progress, Toast.LENGTH_SHORT).show();
return START_NOT_STICKY;
}
+
Log.i(TAG, String.format("Will start collecting bug report, version=%s",
getPackageVersion(this)));
- mIsCollectingBugReport.set(true);
+
+ if (ACTION_START_SILENT.equals(intent.getAction())) {
+ Log.i(TAG, "Starting a silent bugreport.");
+ mMetaBugReport = BugReportActivity.createBugReport(this, MetaBugReport.TYPE_SILENT);
+ } else {
+ Bundle extras = intent.getExtras();
+ mMetaBugReport = extras.getParcelable(EXTRA_META_BUG_REPORT);
+ }
+
mBugReportProgress.set(0);
startForeground(BUGREPORT_IN_PROGRESS_NOTIF_ID, buildProgressNotification());
showProgressNotification();
- Bundle extras = intent.getExtras();
- mMetaBugReport = extras.getParcelable(EXTRA_META_BUG_REPORT);
-
collectBugReport();
+ // Show a short lived "bugreport started" toast message after a short delay.
+ mHandlerToast.postDelayed(() -> {
+ Toast.makeText(this,
+ getText(R.string.toast_bug_report_started), Toast.LENGTH_LONG).show();
+ }, BUGREPORT_STARTED_TOAST_DELAY_MILLIS);
+
// If the service process gets killed due to heavy memory pressure, do not restart.
return START_NOT_STICKY;
}
@@ -213,6 +261,9 @@
}
private Notification buildProgressNotification() {
+ Intent intent = new Intent(getApplicationContext(), BugReportInfoActivity.class);
+ PendingIntent startBugReportInfoActivity =
+ PendingIntent.getActivity(getApplicationContext(), 0, intent, 0);
return new Notification.Builder(this, PROGRESS_CHANNEL_ID)
.setContentTitle(getText(R.string.notification_bugreport_in_progress))
.setSubText(String.format("%.1f%%", mBugReportProgress.get()))
@@ -220,6 +271,7 @@
.setCategory(Notification.CATEGORY_STATUS)
.setOngoing(true)
.setProgress((int) MAX_PROGRESS_VALUE, (int) mBugReportProgress.get(), false)
+ .setContentIntent(startBugReportInfoActivity)
.build();
}
@@ -266,9 +318,14 @@
Log.i(TAG, "Grabbing bt snoop log");
File result = FileUtils.getFileWithSuffix(this, mMetaBugReport.getTimestamp(),
"-btsnoop.bin.log");
- try {
- copyBinaryStream(new FileInputStream(new File(BT_SNOOP_LOG_LOCATION)),
- new FileOutputStream(result));
+ File snoopFile = new File(BT_SNOOP_LOG_LOCATION);
+ if (!snoopFile.exists()) {
+ Log.w(TAG, BT_SNOOP_LOG_LOCATION + " not found, skipping");
+ return;
+ }
+ try (FileInputStream input = new FileInputStream(snoopFile);
+ FileOutputStream output = new FileOutputStream(result)) {
+ ByteStreams.copy(input, output);
} catch (IOException e) {
// this regularly happens when snooplog is not enabled so do not log as an error
Log.i(TAG, "Failed to grab bt snooplog, continuing to take bug report.", e);
@@ -307,14 +364,21 @@
mCallback = new CarBugreportManager.CarBugreportManagerCallback() {
@Override
public void onError(int errorCode) {
- Log.e(TAG, "Bugreport failed " + errorCode);
- showToast(R.string.toast_status_failed);
- // TODO(b/133520419): show this error on Info page or add to zip file.
- scheduleZipTask();
+ Log.e(TAG, "CarBugreportManager failed: " + errorCode);
// We let the UI know that bug reporting is finished, because the next step is to
// zip everything and upload.
mBugReportProgress.set(MAX_PROGRESS_VALUE);
sendProgressEventToHandler(MAX_PROGRESS_VALUE);
+ showToast(R.string.toast_status_failed);
+ BugStorageUtils.setBugReportStatus(
+ BugReportService.this, mMetaBugReport,
+ Status.STATUS_WRITE_FAILED, "CarBugreportManager failed: " + errorCode);
+ mIsCollectingBugReport.set(false);
+ mHandler.post(() -> {
+ mNotificationManager.cancel(BUGREPORT_IN_PROGRESS_NOTIF_ID);
+ stopForeground(true);
+ });
+ mHandlerToast.removeCallbacksAndMessages(null);
}
@Override
@@ -325,86 +389,102 @@
@Override
public void onFinished() {
- Log.i(TAG, "Bugreport finished");
- scheduleZipTask();
+ Log.d(TAG, "CarBugreportManager finished");
mBugReportProgress.set(MAX_PROGRESS_VALUE);
sendProgressEventToHandler(MAX_PROGRESS_VALUE);
+ mSingleThreadExecutor.submit(BugReportService.this::zipDirectoryAndUpdateStatus);
}
};
mBugreportManager.requestBugreport(outFd, extraOutFd, mCallback);
}
- private void scheduleZipTask() {
- mSingleThreadExecutor.submit(this::zipDirectoryAndScheduleForUpload);
- }
-
/**
* Shows a clickable bugreport finished notification. When clicked it opens
* {@link BugReportInfoActivity}.
*/
- private void showBugReportFinishedNotification() {
- Intent intent = new Intent(getApplicationContext(), BugReportInfoActivity.class);
+ static void showBugReportFinishedNotification(Context context, MetaBugReport bug) {
+ Intent intent = new Intent(context, BugReportInfoActivity.class);
PendingIntent startBugReportInfoActivity =
- PendingIntent.getActivity(getApplicationContext(), 0, intent, 0);
+ PendingIntent.getActivity(context, 0, intent, 0);
Notification notification = new Notification
- .Builder(getApplicationContext(), STATUS_CHANNEL_ID)
- .setContentTitle(getText(R.string.notification_bugreport_finished_title))
- .setContentText(getText(JobSchedulingUtils.uploadByDefault()
- ? R.string.notification_bugreport_auto_upload_finished_text
- : R.string.notification_bugreport_manual_upload_finished_text))
+ .Builder(context, STATUS_CHANNEL_ID)
+ .setContentTitle(context.getText(R.string.notification_bugreport_finished_title))
+ .setContentText(bug.getTitle())
.setCategory(Notification.CATEGORY_STATUS)
.setSmallIcon(R.drawable.ic_upload)
.setContentIntent(startBugReportInfoActivity)
.build();
- mNotificationManager.notify(BUGREPORT_FINISHED_NOTIF_ID, notification);
+ context.getSystemService(NotificationManager.class)
+ .notify(BUGREPORT_FINISHED_NOTIF_ID, notification);
}
- private void zipDirectoryAndScheduleForUpload() {
+ /**
+ * Zips the temp directory, writes to the system user's {@link FileUtils#getPendingDir} and
+ * updates the bug report status.
+ *
+ * <p>For {@link MetaBugReport#TYPE_INTERACTIVE}: Sets status to either STATUS_UPLOAD_PENDING or
+ * STATUS_PENDING_USER_ACTION and shows a regular notification.
+ *
+ * <p>For {@link MetaBugReport#TYPE_SILENT}: Sets status to STATUS_AUDIO_PENDING and shows
+ * a dialog to record audio message.
+ */
+ private void zipDirectoryAndUpdateStatus() {
try {
- // When OutputStream from openBugReportFile is closed, BugStorageProvider automatically
- // schedules an upload job.
- zipDirectoryToOutputStream(
- FileUtils.createTempDir(this, mMetaBugReport.getTimestamp()),
- BugStorageUtils.openBugReportFile(this, mMetaBugReport));
- showBugReportFinishedNotification();
+ // All the generated zip files, images and audio messages are located in this dir.
+ // This is located under the current user.
+ String bugreportFileName = FileUtils.getZipFileName(mMetaBugReport);
+ Log.d(TAG, "Zipping bugreport into " + bugreportFileName);
+ mMetaBugReport = BugStorageUtils.update(this,
+ mMetaBugReport.toBuilder().setBugReportFileName(bugreportFileName).build());
+ File bugReportTempDir = FileUtils.createTempDir(this, mMetaBugReport.getTimestamp());
+ zipDirectoryToOutputStream(bugReportTempDir,
+ BugStorageUtils.openBugReportFileToWrite(this, mMetaBugReport));
+ mIsCollectingBugReport.set(false);
} catch (IOException e) {
Log.e(TAG, "Failed to zip files", e);
BugStorageUtils.setBugReportStatus(this, mMetaBugReport, Status.STATUS_WRITE_FAILED,
MESSAGE_FAILURE_ZIP);
showToast(R.string.toast_status_failed);
+ return;
}
- mIsCollectingBugReport.set(false);
- showToast(R.string.toast_status_finished);
- mHandler.post(() -> stopForeground(true));
+ if (mMetaBugReport.getType() == MetaBugReport.TYPE_SILENT) {
+ BugStorageUtils.setBugReportStatus(BugReportService.this,
+ mMetaBugReport, Status.STATUS_AUDIO_PENDING, /* message= */ "");
+ playNotificationSound();
+ startActivity(BugReportActivity.buildAddAudioIntent(this, mMetaBugReport));
+ } else {
+ // NOTE: If bugreport type is INTERACTIVE, it will already contain an audio message.
+ Status status = mConfig.getAutoUpload()
+ ? Status.STATUS_UPLOAD_PENDING : Status.STATUS_PENDING_USER_ACTION;
+ BugStorageUtils.setBugReportStatus(BugReportService.this,
+ mMetaBugReport, status, /* message= */ "");
+ showBugReportFinishedNotification(this, mMetaBugReport);
+ }
+ mHandler.post(() -> {
+ mNotificationManager.cancel(BUGREPORT_IN_PROGRESS_NOTIF_ID);
+ stopForeground(true);
+ });
+ mHandlerToast.removeCallbacksAndMessages(null);
}
- @Override
- public void onDestroy() {
- if (DEBUG) {
- Log.d(TAG, "Service destroyed");
+ private void playNotificationSound() {
+ Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
+ Ringtone ringtone = RingtoneManager.getRingtone(getApplicationContext(), notification);
+ if (ringtone == null) {
+ Log.w(TAG, "No notification ringtone found.");
+ return;
}
- }
-
- private static void copyBinaryStream(InputStream in, OutputStream out) throws IOException {
- OutputStream writer = null;
- InputStream reader = null;
- try {
- writer = new DataOutputStream(out);
- reader = new DataInputStream(in);
- rawCopyStream(writer, reader);
- } finally {
- IoUtils.closeQuietly(reader);
- IoUtils.closeQuietly(writer);
+ float volume = ringtone.getVolume();
+ // Use volume from audio manager, otherwise default ringtone volume can be too loud.
+ AudioManager audioManager = getSystemService(AudioManager.class);
+ if (audioManager != null) {
+ int currentVolume = audioManager.getStreamVolume(AudioManager.STREAM_NOTIFICATION);
+ int maxVolume = audioManager.getStreamMaxVolume(AudioManager.STREAM_NOTIFICATION);
+ volume = (currentVolume + 0.0f) / maxVolume;
}
- }
-
- // does not close the reader or writer.
- private static void rawCopyStream(OutputStream writer, InputStream reader) throws IOException {
- int read;
- byte[] buf = new byte[8192];
- while ((read = reader.read(buf, 0, buf.length)) > 0) {
- writer.write(buf, 0, read);
- }
+ Log.v(TAG, "Using volume " + volume);
+ ringtone.setVolume(volume);
+ ringtone.play();
}
/**
@@ -425,59 +505,23 @@
Log.v(TAG, "zipping directory " + dirToZip.getAbsolutePath());
File[] listFiles = dirToZip.listFiles();
- ZipOutputStream zipStream = new ZipOutputStream(new BufferedOutputStream(outStream));
- try {
+ try (ZipOutputStream zipStream = new ZipOutputStream(new BufferedOutputStream(outStream))) {
for (File file : listFiles) {
if (file.isDirectory()) {
continue;
}
- if (file.length() == 0) {
- // If there were issues with reading from dumpstate socket, the dumpstate zip
- // file still might be available in
- // /data/user_de/0/com.android.shell/files/bugreports/.
- Log.w(TAG, "File " + file.getName() + " is empty, skipping.");
- return;
- }
String filename = file.getName();
-
// only for the zipped output file, we add individual entries to zip file.
if (filename.equals(OUTPUT_ZIP_FILE) || filename.equals(EXTRA_OUTPUT_ZIP_FILE)) {
- extractZippedFileToOutputStream(file, zipStream);
+ ZipUtils.extractZippedFileToZipStream(file, zipStream);
} else {
- try (FileInputStream reader = new FileInputStream(file)) {
- addFileToOutputStream(filename, reader, zipStream);
- }
+ ZipUtils.addFileToZipStream(file, zipStream);
}
}
} finally {
- zipStream.close();
outStream.close();
}
// Zipping successful, now cleanup the temp dir.
FileUtils.deleteDirectory(dirToZip);
}
-
- private void extractZippedFileToOutputStream(File file, ZipOutputStream zipStream)
- throws IOException {
- ZipFile zipFile = new ZipFile(file);
- Enumeration<? extends ZipEntry> entries = zipFile.entries();
- while (entries.hasMoreElements()) {
- ZipEntry entry = entries.nextElement();
- try (InputStream stream = zipFile.getInputStream(entry)) {
- addFileToOutputStream(entry.getName(), stream, zipStream);
- }
- }
- }
-
- private void addFileToOutputStream(
- String filename, InputStream reader, ZipOutputStream zipStream) {
- ZipEntry entry = new ZipEntry(filename);
- try {
- zipStream.putNextEntry(entry);
- rawCopyStream(zipStream, reader);
- zipStream.closeEntry();
- } catch (IOException e) {
- Log.w(TAG, "Failed to add file " + filename + " to the zip.", e);
- }
- }
}
diff --git a/tests/BugReportApp/src/com/android/car/bugreport/BugStorageProvider.java b/tests/BugReportApp/src/com/android/car/bugreport/BugStorageProvider.java
index 095a668..1abbdb2 100644
--- a/tests/BugReportApp/src/com/android/car/bugreport/BugStorageProvider.java
+++ b/tests/BugReportApp/src/com/android/car/bugreport/BugStorageProvider.java
@@ -17,6 +17,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.StringDef;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.Context;
@@ -26,13 +27,19 @@
import android.database.sqlite.SQLiteOpenHelper;
import android.net.Uri;
import android.os.CancellationSignal;
-import android.os.Handler;
import android.os.ParcelFileDescriptor;
import android.util.Log;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Strings;
+
import java.io.File;
+import java.io.FileDescriptor;
import java.io.FileNotFoundException;
-import java.io.IOException;
+import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.function.Function;
/**
@@ -40,32 +47,76 @@
* In Android Automotive user 0 runs as the system and all the time, while other users won't once
* their session ends. This content provider enables bug reports to be uploaded even after
* user session ends.
+ *
+ * <p>A bugreport constists of two files: bugreport zip file and audio file. Audio file is added
+ * later through notification. {@link SimpleUploaderAsyncTask} merges two files into one zip file
+ * before uploading.
+ *
+ * <p>All files are stored under system user's {@link FileUtils#getPendingDir}.
*/
public class BugStorageProvider extends ContentProvider {
private static final String TAG = BugStorageProvider.class.getSimpleName();
private static final String AUTHORITY = "com.android.car.bugreport";
private static final String BUG_REPORTS_TABLE = "bugreports";
- static final Uri BUGREPORT_CONTENT_URI =
- Uri.parse("content://" + AUTHORITY + "/" + BUG_REPORTS_TABLE);
- static final String COLUMN_ID = "_ID";
- static final String COLUMN_USERNAME = "username";
- static final String COLUMN_TITLE = "title";
- static final String COLUMN_TIMESTAMP = "timestamp";
- static final String COLUMN_DESCRIPTION = "description";
- static final String COLUMN_FILEPATH = "filepath";
- static final String COLUMN_STATUS = "status";
- static final String COLUMN_STATUS_MESSAGE = "message";
+ /** Deletes files associated with a bug report. */
+ static final String URL_SEGMENT_DELETE_FILES = "deleteZipFile";
+ /** Destructively deletes a bug report. */
+ static final String URL_SEGMENT_COMPLETE_DELETE = "completeDelete";
+ /** Opens bugreport file of a bug report, uses column {@link #COLUMN_BUGREPORT_FILENAME}. */
+ static final String URL_SEGMENT_OPEN_BUGREPORT_FILE = "openBugReportFile";
+ /** Opens audio file of a bug report, uses column {@link #URL_MATCHED_OPEN_AUDIO_FILE}. */
+ static final String URL_SEGMENT_OPEN_AUDIO_FILE = "openAudioFile";
+ /**
+ * Opens final bugreport zip file, uses column {@link #COLUMN_FILEPATH}.
+ *
+ * <p>NOTE: This is the old way of storing final zipped bugreport. In
+ * {@code BugStorageProvider#AUDIO_VERSION} {@link #COLUMN_FILEPATH} is dropped. But there are
+ * still some devices with this field set.
+ */
+ static final String URL_SEGMENT_OPEN_FILE = "openFile";
// URL Matcher IDs.
private static final int URL_MATCHED_BUG_REPORTS_URI = 1;
private static final int URL_MATCHED_BUG_REPORT_ID_URI = 2;
+ private static final int URL_MATCHED_DELETE_FILES = 3;
+ private static final int URL_MATCHED_COMPLETE_DELETE = 4;
+ private static final int URL_MATCHED_OPEN_BUGREPORT_FILE = 5;
+ private static final int URL_MATCHED_OPEN_AUDIO_FILE = 6;
+ private static final int URL_MATCHED_OPEN_FILE = 7;
- private Handler mHandler;
+ @StringDef({
+ URL_SEGMENT_DELETE_FILES,
+ URL_SEGMENT_COMPLETE_DELETE,
+ URL_SEGMENT_OPEN_BUGREPORT_FILE,
+ URL_SEGMENT_OPEN_AUDIO_FILE,
+ URL_SEGMENT_OPEN_FILE,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface UriActionSegments {}
+
+ static final Uri BUGREPORT_CONTENT_URI =
+ Uri.parse("content://" + AUTHORITY + "/" + BUG_REPORTS_TABLE);
+
+ /** See {@link MetaBugReport} for column descriptions. */
+ static final String COLUMN_ID = "_ID";
+ static final String COLUMN_USERNAME = "username";
+ static final String COLUMN_TITLE = "title";
+ static final String COLUMN_TIMESTAMP = "timestamp";
+ /** not used anymore */
+ static final String COLUMN_DESCRIPTION = "description";
+ /** not used anymore, but some devices still might have bugreports with this field set. */
+ static final String COLUMN_FILEPATH = "filepath";
+ static final String COLUMN_STATUS = "status";
+ static final String COLUMN_STATUS_MESSAGE = "message";
+ static final String COLUMN_TYPE = "type";
+ static final String COLUMN_BUGREPORT_FILENAME = "bugreport_filename";
+ static final String COLUMN_AUDIO_FILENAME = "audio_filename";
private DatabaseHelper mDatabaseHelper;
private final UriMatcher mUriMatcher;
+ private Config mConfig;
/**
* A helper class to work with sqlite database.
@@ -78,9 +129,13 @@
/**
* All changes in database versions should be recorded here.
* 1: Initial version.
+ * 2: Add integer column details_needed.
+ * 3: Add string column audio_filename and bugreport_filename.
*/
private static final int INITIAL_VERSION = 1;
- private static final int DATABASE_VERSION = INITIAL_VERSION;
+ private static final int TYPE_VERSION = 2;
+ private static final int AUDIO_VERSION = 3;
+ private static final int DATABASE_VERSION = AUDIO_VERSION;
private static final String CREATE_TABLE = "CREATE TABLE " + BUG_REPORTS_TABLE + " ("
+ COLUMN_ID + " INTEGER PRIMARY KEY,"
@@ -90,7 +145,10 @@
+ COLUMN_DESCRIPTION + " TEXT NULL,"
+ COLUMN_FILEPATH + " TEXT DEFAULT NULL,"
+ COLUMN_STATUS + " INTEGER DEFAULT " + Status.STATUS_WRITE_PENDING.getValue() + ","
- + COLUMN_STATUS_MESSAGE + " TEXT NULL"
+ + COLUMN_STATUS_MESSAGE + " TEXT NULL,"
+ + COLUMN_TYPE + " INTEGER DEFAULT " + MetaBugReport.TYPE_INTERACTIVE + ","
+ + COLUMN_BUGREPORT_FILENAME + " TEXT DEFAULT NULL,"
+ + COLUMN_AUDIO_FILENAME + " TEXT DEFAULT NULL"
+ ");";
DatabaseHelper(Context context) {
@@ -105,24 +163,56 @@
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.w(TAG, "Upgrading from " + oldVersion + " to " + newVersion);
+ if (oldVersion < TYPE_VERSION) {
+ db.execSQL("ALTER TABLE " + BUG_REPORTS_TABLE + " ADD COLUMN "
+ + COLUMN_TYPE + " INTEGER DEFAULT " + MetaBugReport.TYPE_INTERACTIVE);
+ }
+ if (oldVersion < AUDIO_VERSION) {
+ db.execSQL("ALTER TABLE " + BUG_REPORTS_TABLE + " ADD COLUMN "
+ + COLUMN_BUGREPORT_FILENAME + " TEXT DEFAULT NULL");
+ db.execSQL("ALTER TABLE " + BUG_REPORTS_TABLE + " ADD COLUMN "
+ + COLUMN_AUDIO_FILENAME + " TEXT DEFAULT NULL");
+ }
}
}
- /** Builds {@link Uri} that points to a bugreport entry with provided bugreport id. */
- static Uri buildUriWithBugId(int bugReportId) {
- return Uri.parse("content://" + AUTHORITY + "/" + BUG_REPORTS_TABLE + "/" + bugReportId);
+ /**
+ * Builds an {@link Uri} that points to the single bug report and performs an action
+ * defined by given URI segment.
+ */
+ static Uri buildUriWithSegment(int bugReportId, @UriActionSegments String segment) {
+ return Uri.parse("content://" + AUTHORITY + "/" + BUG_REPORTS_TABLE + "/"
+ + segment + "/" + bugReportId);
}
public BugStorageProvider() {
mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
mUriMatcher.addURI(AUTHORITY, BUG_REPORTS_TABLE, URL_MATCHED_BUG_REPORTS_URI);
mUriMatcher.addURI(AUTHORITY, BUG_REPORTS_TABLE + "/#", URL_MATCHED_BUG_REPORT_ID_URI);
+ mUriMatcher.addURI(
+ AUTHORITY, BUG_REPORTS_TABLE + "/" + URL_SEGMENT_DELETE_FILES + "/#",
+ URL_MATCHED_DELETE_FILES);
+ mUriMatcher.addURI(
+ AUTHORITY, BUG_REPORTS_TABLE + "/" + URL_SEGMENT_COMPLETE_DELETE + "/#",
+ URL_MATCHED_COMPLETE_DELETE);
+ mUriMatcher.addURI(
+ AUTHORITY, BUG_REPORTS_TABLE + "/" + URL_SEGMENT_OPEN_BUGREPORT_FILE + "/#",
+ URL_MATCHED_OPEN_BUGREPORT_FILE);
+ mUriMatcher.addURI(
+ AUTHORITY, BUG_REPORTS_TABLE + "/" + URL_SEGMENT_OPEN_AUDIO_FILE + "/#",
+ URL_MATCHED_OPEN_AUDIO_FILE);
+ mUriMatcher.addURI(
+ AUTHORITY, BUG_REPORTS_TABLE + "/" + URL_SEGMENT_OPEN_FILE + "/#",
+ URL_MATCHED_OPEN_FILE);
}
@Override
public boolean onCreate() {
+ Preconditions.checkState(Config.isBugReportEnabled(), "BugReport is disabled.");
+
mDatabaseHelper = new DatabaseHelper(getContext());
- mHandler = new Handler();
+ mConfig = new Config();
+ mConfig.start();
return true;
}
@@ -181,10 +271,6 @@
switch (mUriMatcher.match(uri)) {
case URL_MATCHED_BUG_REPORTS_URI:
table = BUG_REPORTS_TABLE;
- String filepath = FileUtils.getZipFile(getContext(),
- (String) values.get(COLUMN_TIMESTAMP),
- (String) values.get(COLUMN_USERNAME)).getPath();
- values.put(COLUMN_FILEPATH, filepath);
break;
default:
throw new IllegalArgumentException("unknown uri" + uri);
@@ -203,31 +289,46 @@
@Nullable
@Override
public String getType(@NonNull Uri uri) {
- if (mUriMatcher.match(uri) != URL_MATCHED_BUG_REPORT_ID_URI) {
- throw new IllegalArgumentException("unknown uri:" + uri);
+ switch (mUriMatcher.match(uri)) {
+ case URL_MATCHED_OPEN_BUGREPORT_FILE:
+ case URL_MATCHED_OPEN_FILE:
+ return "application/zip";
+ case URL_MATCHED_OPEN_AUDIO_FILE:
+ return "audio/3gpp";
+ default:
+ throw new IllegalArgumentException("unknown uri:" + uri);
}
- // We only store zip files in this provider.
- return "application/zip";
}
@Override
public int delete(
@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
+ SQLiteDatabase db = mDatabaseHelper.getReadableDatabase();
switch (mUriMatcher.match(uri)) {
- // returns the bugreport that match the id.
- case URL_MATCHED_BUG_REPORT_ID_URI:
+ case URL_MATCHED_DELETE_FILES:
if (selection != null || selectionArgs != null) {
throw new IllegalArgumentException("selection is not allowed for "
- + URL_MATCHED_BUG_REPORT_ID_URI);
+ + URL_MATCHED_DELETE_FILES);
+ }
+ if (deleteFilesFor(getBugReportFromUri(uri))) {
+ getContext().getContentResolver().notifyChange(uri, null);
+ return 1;
+ }
+ return 0;
+ case URL_MATCHED_COMPLETE_DELETE:
+ if (selection != null || selectionArgs != null) {
+ throw new IllegalArgumentException("selection is not allowed for "
+ + URL_MATCHED_COMPLETE_DELETE);
}
selection = COLUMN_ID + " = ?";
selectionArgs = new String[]{uri.getLastPathSegment()};
- break;
+ // Ignore the results of zip file deletion, possibly it wasn't even created.
+ deleteFilesFor(getBugReportFromUri(uri));
+ getContext().getContentResolver().notifyChange(uri, null);
+ return db.delete(BUG_REPORTS_TABLE, selection, selectionArgs);
default:
throw new IllegalArgumentException("Unknown URL " + uri);
}
- SQLiteDatabase db = mDatabaseHelper.getReadableDatabase();
- return db.delete(BUG_REPORTS_TABLE, selection, selectionArgs);
}
@Override
@@ -263,77 +364,72 @@
}
/**
- * This is called when the OutputStream is requested by
- * {@link BugStorageUtils#openBugReportFile}.
+ * This is called when a file is opened.
*
- * It expects the file to be a zip file and schedules an upload under the primary user.
+ * <p>See {@link BugStorageUtils#openBugReportFileToWrite},
+ * {@link BugStorageUtils#openAudioMessageFileToWrite}.
*/
@Nullable
@Override
public ParcelFileDescriptor openFile(@NonNull Uri uri, @NonNull String mode)
throws FileNotFoundException {
- if (mUriMatcher.match(uri) != URL_MATCHED_BUG_REPORT_ID_URI) {
- throw new IllegalArgumentException("unknown uri:" + uri);
+ Function<MetaBugReport, String> fileNameExtractor;
+ switch (mUriMatcher.match(uri)) {
+ case URL_MATCHED_OPEN_BUGREPORT_FILE:
+ fileNameExtractor = MetaBugReport::getBugReportFileName;
+ break;
+ case URL_MATCHED_OPEN_AUDIO_FILE:
+ fileNameExtractor = MetaBugReport::getAudioFileName;
+ break;
+ case URL_MATCHED_OPEN_FILE:
+ File file = new File(getBugReportFromUri(uri).getFilePath());
+ Log.v(TAG, "Opening file " + file + " with mode " + mode);
+ return ParcelFileDescriptor.open(file, ParcelFileDescriptor.parseMode(mode));
+ default:
+ throw new IllegalArgumentException("unknown uri:" + uri);
}
-
- Cursor c = query(uri, new String[]{COLUMN_FILEPATH}, null, null, null);
- int count = (c != null) ? c.getCount() : 0;
- if (count != 1) {
- // If there is not exactly one result, throw an appropriate
- // exception.
- if (c != null) {
- c.close();
- }
- if (count == 0) {
- throw new FileNotFoundException("No entry for " + uri);
- }
- throw new FileNotFoundException("Multiple items at " + uri);
- }
-
- c.moveToFirst();
- int i = c.getColumnIndex(COLUMN_FILEPATH);
- String path = (i >= 0 ? c.getString(i) : null);
- c.close();
- if (path == null) {
- throw new FileNotFoundException("Column for path not found.");
- }
-
+ // URI contains bugreport ID as the last segment, see the matched urls.
+ MetaBugReport bugReport = getBugReportFromUri(uri);
+ File file = new File(
+ FileUtils.getPendingDir(getContext()), fileNameExtractor.apply(bugReport));
+ Log.v(TAG, "Opening file " + file + " with mode " + mode);
int modeBits = ParcelFileDescriptor.parseMode(mode);
- try {
- return ParcelFileDescriptor.open(new File(path), modeBits, mHandler, e -> {
- if (mode.equals("r")) {
- Log.i(TAG, "File " + path + " opened in read-only mode.");
- return;
- } else if (!mode.equals("w")) {
- Log.e(TAG, "Only read-only or write-only mode supported; mode=" + mode);
- return;
- }
- Log.i(TAG, "File " + path + " opened in write-only mode.");
- Status status;
- if (e == null) {
- // success writing the file. Update the field to indicate bugreport
- // is ready for upload
- status = JobSchedulingUtils.uploadByDefault() ? Status.STATUS_UPLOAD_PENDING
- : Status.STATUS_PENDING_USER_ACTION;
- } else {
- // We log it and ignore it
- Log.e(TAG, "Bug report file write failed ", e);
- status = Status.STATUS_WRITE_FAILED;
- }
- SQLiteDatabase db = mDatabaseHelper.getWritableDatabase();
- ContentValues values = new ContentValues();
- values.put(COLUMN_STATUS, status.getValue());
- db.update(BUG_REPORTS_TABLE, values, COLUMN_ID + "=?",
- new String[]{ uri.getLastPathSegment() });
- if (status == Status.STATUS_UPLOAD_PENDING) {
- JobSchedulingUtils.scheduleUploadJob(BugStorageProvider.this.getContext());
- }
- Log.i(TAG, "Finished adding bugreport " + path + " " + uri);
- });
- } catch (IOException e) {
- // An IOException (for example not being able to open the file, will crash us.
- // That is ok.
- throw new RuntimeException(e);
+ return ParcelFileDescriptor.open(file, modeBits);
+ }
+
+ private MetaBugReport getBugReportFromUri(@NonNull Uri uri) {
+ int bugreportId = Integer.parseInt(uri.getLastPathSegment());
+ return BugStorageUtils.findBugReport(getContext(), bugreportId)
+ .orElseThrow(() -> new IllegalArgumentException("No record found for " + uri));
+ }
+
+ /**
+ * Print the Provider's state into the given stream. This gets invoked if
+ * you run "dumpsys activity provider com.android.car.bugreport/.BugStorageProvider".
+ *
+ * @param fd The raw file descriptor that the dump is being sent to.
+ * @param writer The PrintWriter to which you should dump your state. This will be
+ * closed for you after you return.
+ * @param args additional arguments to the dump request.
+ */
+ public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+ writer.println("BugStorageProvider:");
+ mConfig.dump(/* prefix= */ " ", writer);
+ }
+
+ private boolean deleteFilesFor(MetaBugReport bugReport) {
+ if (!Strings.isNullOrEmpty(bugReport.getFilePath())) {
+ // Old bugreports have only filePath.
+ return new File(bugReport.getFilePath()).delete();
}
+ File pendingDir = FileUtils.getPendingDir(getContext());
+ boolean result = true;
+ if (!Strings.isNullOrEmpty(bugReport.getAudioFileName())) {
+ result = new File(pendingDir, bugReport.getAudioFileName()).delete();
+ }
+ if (!Strings.isNullOrEmpty(bugReport.getBugReportFileName())) {
+ result = result && new File(pendingDir, bugReport.getBugReportFileName()).delete();
+ }
+ return result;
}
}
diff --git a/tests/BugReportApp/src/com/android/car/bugreport/BugStorageUtils.java b/tests/BugReportApp/src/com/android/car/bugreport/BugStorageUtils.java
index 34fd3dd..cd0a12e 100644
--- a/tests/BugReportApp/src/com/android/car/bugreport/BugStorageUtils.java
+++ b/tests/BugReportApp/src/com/android/car/bugreport/BugStorageUtils.java
@@ -15,12 +15,15 @@
*/
package com.android.car.bugreport;
+import static com.android.car.bugreport.BugStorageProvider.COLUMN_AUDIO_FILENAME;
+import static com.android.car.bugreport.BugStorageProvider.COLUMN_BUGREPORT_FILENAME;
import static com.android.car.bugreport.BugStorageProvider.COLUMN_FILEPATH;
import static com.android.car.bugreport.BugStorageProvider.COLUMN_ID;
import static com.android.car.bugreport.BugStorageProvider.COLUMN_STATUS;
import static com.android.car.bugreport.BugStorageProvider.COLUMN_STATUS_MESSAGE;
import static com.android.car.bugreport.BugStorageProvider.COLUMN_TIMESTAMP;
import static com.android.car.bugreport.BugStorageProvider.COLUMN_TITLE;
+import static com.android.car.bugreport.BugStorageProvider.COLUMN_TYPE;
import static com.android.car.bugreport.BugStorageProvider.COLUMN_USERNAME;
import android.annotation.NonNull;
@@ -30,18 +33,21 @@
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
-import android.text.TextUtils;
import android.util.Log;
import com.google.api.client.auth.oauth2.TokenResponseException;
+import com.google.common.base.Strings;
import java.io.FileNotFoundException;
+import java.io.InputStream;
import java.io.OutputStream;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
+import java.time.Instant;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
+import java.util.Optional;
/**
* A class that hides details when communicating with the bug storage provider.
@@ -68,6 +74,7 @@
* @param title - title of the bug report.
* @param timestamp - timestamp when the bug report was initiated.
* @param username - current user name. Note, it's a user name, not an account name.
+ * @param type - bug report type, {@link MetaBugReport.BugReportType}.
* @return an instance of {@link MetaBugReport} that was created in a database.
*/
@NonNull
@@ -75,68 +82,95 @@
@NonNull Context context,
@NonNull String title,
@NonNull String timestamp,
- @NonNull String username) {
+ @NonNull String username,
+ @MetaBugReport.BugReportType int type) {
// insert bug report username and title
ContentValues values = new ContentValues();
values.put(COLUMN_TITLE, title);
values.put(COLUMN_TIMESTAMP, timestamp);
values.put(COLUMN_USERNAME, username);
+ values.put(COLUMN_TYPE, type);
ContentResolver r = context.getContentResolver();
Uri uri = r.insert(BugStorageProvider.BUGREPORT_CONTENT_URI, values);
-
- Cursor c = r.query(uri, new String[]{COLUMN_ID}, null, null, null);
- int count = (c == null) ? 0 : c.getCount();
- if (count != 1) {
- throw new RuntimeException("Could not create a bug report entry.");
- }
- c.moveToFirst();
- int id = getInt(c, COLUMN_ID);
- c.close();
- return new MetaBugReport.Builder(id, timestamp)
- .setTitle(title)
- .setUserName(username)
- .build();
+ return findBugReport(context, Integer.parseInt(uri.getLastPathSegment())).get();
}
- /**
- * Returns a file stream to write the zipped file to. The content provider listens for file
- * descriptor to be closed, and as soon as it is closed, {@link BugStorageProvider} schedules
- * it for upload.
- *
- * @param context - an application context.
- * @param metaBugReport - a bug report.
- * @return a file descriptor where a zip content should be written.
- */
+ /** Returns an output stream to write the zipped file to. */
@NonNull
- static OutputStream openBugReportFile(
+ static OutputStream openBugReportFileToWrite(
@NonNull Context context, @NonNull MetaBugReport metaBugReport)
throws FileNotFoundException {
ContentResolver r = context.getContentResolver();
+ return r.openOutputStream(BugStorageProvider.buildUriWithSegment(
+ metaBugReport.getId(), BugStorageProvider.URL_SEGMENT_OPEN_BUGREPORT_FILE));
+ }
- // Write the file. When file is closed, bug report record status
- // will automatically be made ready for uploading.
- return r.openOutputStream(BugStorageProvider.buildUriWithBugId(metaBugReport.getId()));
+ /** Returns an output stream to write the audio message file to. */
+ static OutputStream openAudioMessageFileToWrite(
+ @NonNull Context context, @NonNull MetaBugReport metaBugReport)
+ throws FileNotFoundException {
+ ContentResolver r = context.getContentResolver();
+ return r.openOutputStream(BugStorageProvider.buildUriWithSegment(
+ metaBugReport.getId(), BugStorageProvider.URL_SEGMENT_OPEN_AUDIO_FILE));
}
/**
- * Deletes {@link MetaBugReport} record from a local database. Returns true if the record was
- * deleted.
+ * Returns an input stream to read the final zip file from.
+ *
+ * <p>NOTE: This is the old way of storing final zipped bugreport. See
+ * {@link BugStorageProvider#URL_SEGMENT_OPEN_FILE} for more info.
+ */
+ static InputStream openFileToRead(Context context, MetaBugReport bug)
+ throws FileNotFoundException {
+ return context.getContentResolver().openInputStream(
+ BugStorageProvider.buildUriWithSegment(
+ bug.getId(), BugStorageProvider.URL_SEGMENT_OPEN_FILE));
+ }
+
+ /** Returns an input stream to read the bug report zip file from. */
+ static InputStream openBugReportFileToRead(Context context, MetaBugReport bug)
+ throws FileNotFoundException {
+ return context.getContentResolver().openInputStream(
+ BugStorageProvider.buildUriWithSegment(
+ bug.getId(), BugStorageProvider.URL_SEGMENT_OPEN_BUGREPORT_FILE));
+ }
+
+ /** Returns an input stream to read the audio file from. */
+ static InputStream openAudioFileToRead(Context context, MetaBugReport bug)
+ throws FileNotFoundException {
+ return context.getContentResolver().openInputStream(
+ BugStorageProvider.buildUriWithSegment(
+ bug.getId(), BugStorageProvider.URL_SEGMENT_OPEN_AUDIO_FILE));
+ }
+
+ /**
+ * Deletes {@link MetaBugReport} record from a local database and deletes the associated file.
+ *
+ * <p>WARNING: destructive operation.
*
* @param context - an application context.
* @param bugReportId - a bug report id.
* @return true if the record was deleted.
*/
- static boolean deleteBugReport(@NonNull Context context, int bugReportId) {
+ static boolean completeDeleteBugReport(@NonNull Context context, int bugReportId) {
ContentResolver r = context.getContentResolver();
- return r.delete(BugStorageProvider.buildUriWithBugId(bugReportId), null, null) == 1;
+ return r.delete(BugStorageProvider.buildUriWithSegment(
+ bugReportId, BugStorageProvider.URL_SEGMENT_COMPLETE_DELETE), null, null) == 1;
+ }
+
+ /** Deletes all files for given bugreport id; doesn't delete sqlite3 record. */
+ static boolean deleteBugReportFiles(@NonNull Context context, int bugReportId) {
+ ContentResolver r = context.getContentResolver();
+ return r.delete(BugStorageProvider.buildUriWithSegment(
+ bugReportId, BugStorageProvider.URL_SEGMENT_DELETE_FILES), null, null) == 1;
}
/**
- * Returns bugreports that are waiting to be uploaded.
+ * Returns all the bugreports that are waiting to be uploaded.
*/
@NonNull
- public static List<MetaBugReport> getPendingBugReports(@NonNull Context context) {
+ public static List<MetaBugReport> getUploadPendingBugReports(@NonNull Context context) {
String selection = COLUMN_STATUS + "=?";
String[] selectionArgs = new String[]{
Integer.toString(Status.STATUS_UPLOAD_PENDING.getValue())};
@@ -152,17 +186,32 @@
return getBugreports(context, null, null, COLUMN_ID + " DESC");
}
- private static List<MetaBugReport> getBugreports(Context context, String selection,
- String[] selectionArgs, String order) {
+ /** Returns {@link MetaBugReport} for given bugreport id. */
+ static Optional<MetaBugReport> findBugReport(Context context, int bugreportId) {
+ String selection = COLUMN_ID + " = ?";
+ String[] selectionArgs = new String[]{Integer.toString(bugreportId)};
+ List<MetaBugReport> bugs = BugStorageUtils.getBugreports(
+ context, selection, selectionArgs, null);
+ if (bugs.isEmpty()) {
+ return Optional.empty();
+ }
+ return Optional.of(bugs.get(0));
+ }
+
+ private static List<MetaBugReport> getBugreports(
+ Context context, String selection, String[] selectionArgs, String order) {
ArrayList<MetaBugReport> bugReports = new ArrayList<>();
String[] projection = {
COLUMN_ID,
COLUMN_USERNAME,
COLUMN_TITLE,
COLUMN_TIMESTAMP,
+ COLUMN_BUGREPORT_FILENAME,
+ COLUMN_AUDIO_FILENAME,
COLUMN_FILEPATH,
COLUMN_STATUS,
- COLUMN_STATUS_MESSAGE};
+ COLUMN_STATUS_MESSAGE,
+ COLUMN_TYPE};
ContentResolver r = context.getContentResolver();
Cursor c = r.query(BugStorageProvider.BUGREPORT_CONTENT_URI, projection,
selection, selectionArgs, order);
@@ -171,13 +220,17 @@
if (count > 0) c.moveToFirst();
for (int i = 0; i < count; i++) {
- MetaBugReport meta = new MetaBugReport.Builder(getInt(c, COLUMN_ID),
- getString(c, COLUMN_TIMESTAMP))
+ MetaBugReport meta = MetaBugReport.builder()
+ .setId(getInt(c, COLUMN_ID))
+ .setTimestamp(getString(c, COLUMN_TIMESTAMP))
.setUserName(getString(c, COLUMN_USERNAME))
.setTitle(getString(c, COLUMN_TITLE))
- .setFilepath(getString(c, COLUMN_FILEPATH))
+ .setBugReportFileName(getString(c, COLUMN_BUGREPORT_FILENAME))
+ .setAudioFileName(getString(c, COLUMN_AUDIO_FILENAME))
+ .setFilePath(getString(c, COLUMN_FILEPATH))
.setStatus(getInt(c, COLUMN_STATUS))
.setStatusMessage(getString(c, COLUMN_STATUS_MESSAGE))
+ .setType(getInt(c, COLUMN_TYPE))
.build();
bugReports.add(meta);
c.moveToNext();
@@ -207,7 +260,7 @@
Log.w(TAG, "Column " + colName + " not found.");
return "";
}
- return c.getString(colIndex);
+ return Strings.nullToEmpty(c.getString(colIndex));
}
/**
@@ -219,13 +272,6 @@
}
/**
- * Sets bugreport status to upload failed.
- */
- public static void setUploadFailed(Context context, MetaBugReport bugReport, Exception e) {
- setBugReportStatus(context, bugReport, Status.STATUS_UPLOAD_FAILED, getRootCauseMessage(e));
- }
-
- /**
* Sets bugreport status pending, and update the message to last exception message.
*
* <p>Used when a transient error has occurred.
@@ -244,6 +290,22 @@
setBugReportStatus(context, bugReport, Status.STATUS_UPLOAD_PENDING, msg);
}
+ /**
+ * Sets {@link MetaBugReport} status {@link Status#STATUS_EXPIRED}.
+ * Deletes the associated zip file from disk.
+ *
+ * @return true if succeeded.
+ */
+ static boolean expireBugReport(@NonNull Context context,
+ @NonNull MetaBugReport metaBugReport, @NonNull Instant expiredAt) {
+ metaBugReport = setBugReportStatus(
+ context, metaBugReport, Status.STATUS_EXPIRED, "Expired on " + expiredAt);
+ if (metaBugReport.getStatus() != Status.STATUS_EXPIRED.getValue()) {
+ return false;
+ }
+ return deleteBugReportFiles(context, metaBugReport.getId());
+ }
+
/** Gets the root cause of the error. */
@NonNull
private static String getRootCauseMessage(@Nullable Throwable t) {
@@ -260,18 +322,52 @@
return t.getMessage();
}
- /** Updates bug report record status. */
- static void setBugReportStatus(
+ /**
+ * Updates bug report record status.
+ *
+ * <p>NOTE: When status is set to STATUS_UPLOAD_PENDING, BugStorageProvider automatically
+ * schedules the bugreport to be uploaded.
+ *
+ * @return Updated {@link MetaBugReport}.
+ */
+ static MetaBugReport setBugReportStatus(
Context context, MetaBugReport bugReport, Status status, String message) {
- // update status
+ return update(context, bugReport.toBuilder()
+ .setStatus(status.getValue())
+ .setStatusMessage(message)
+ .build());
+ }
+
+ /**
+ * Updates bug report record status.
+ *
+ * <p>NOTE: When status is set to STATUS_UPLOAD_PENDING, BugStorageProvider automatically
+ * schedules the bugreport to be uploaded.
+ *
+ * @return Updated {@link MetaBugReport}.
+ */
+ static MetaBugReport setBugReportStatus(
+ Context context, MetaBugReport bugReport, Status status, Exception e) {
+ return setBugReportStatus(context, bugReport, status, getRootCauseMessage(e));
+ }
+
+ /**
+ * Updates the bugreport and returns the updated version.
+ *
+ * <p>NOTE: doesn't update all the fields.
+ */
+ static MetaBugReport update(Context context, MetaBugReport bugReport) {
+ // Update only necessary fields.
ContentValues values = new ContentValues();
- values.put(COLUMN_STATUS, status.getValue());
- if (!TextUtils.isEmpty(message)) {
- values.put(COLUMN_STATUS_MESSAGE, message);
- }
+ values.put(COLUMN_BUGREPORT_FILENAME, bugReport.getBugReportFileName());
+ values.put(COLUMN_AUDIO_FILENAME, bugReport.getAudioFileName());
+ values.put(COLUMN_STATUS, bugReport.getStatus());
+ values.put(COLUMN_STATUS_MESSAGE, bugReport.getStatusMessage());
String where = COLUMN_ID + "=" + bugReport.getId();
- context.getContentResolver().update(BugStorageProvider.BUGREPORT_CONTENT_URI, values,
- where, null);
+ context.getContentResolver().update(
+ BugStorageProvider.BUGREPORT_CONTENT_URI, values, where, null);
+ return findBugReport(context, bugReport.getId()).orElseThrow(
+ () -> new IllegalArgumentException("Bug " + bugReport.getId() + " not found"));
}
private static String currentTimestamp() {
diff --git a/tests/BugReportApp/src/com/android/car/bugreport/Config.java b/tests/BugReportApp/src/com/android/car/bugreport/Config.java
new file mode 100644
index 0000000..db1e03c
--- /dev/null
+++ b/tests/BugReportApp/src/com/android/car/bugreport/Config.java
@@ -0,0 +1,160 @@
+/*
+ * 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.bugreport;
+
+import android.app.ActivityThread;
+import android.os.Build;
+import android.os.SystemProperties;
+import android.provider.DeviceConfig;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.io.PrintWriter;
+
+/**
+ * Contains config for BugReport App.
+ *
+ * <p>The config is kept synchronized with {@code car} namespace. It's not defined in
+ * {@link DeviceConfig}.
+ *
+ * <ul>To get/set the flags via adb:
+ * <li>{@code adb shell device_config get car bugreport_upload_destination}
+ * <li>{@code adb shell device_config put car bugreport_upload_destination gcs}
+ * <li>{@code adb shell device_config delete car bugreport_upload_destination}
+ * </ul>
+ */
+final class Config {
+ private static final String TAG = Config.class.getSimpleName();
+
+ /**
+ * Namespace for all Android Automotive related features.
+ *
+ * <p>In the future it will move to {@code DeviceConfig#NAMESPACE_CAR}.
+ */
+ private static final String NAMESPACE_CAR = "car";
+
+ /**
+ * A string flag, can be one of {@code null} or {@link #UPLOAD_DESTINATION_GCS}.
+ */
+ private static final String KEY_BUGREPORT_UPLOAD_DESTINATION = "bugreport_upload_destination";
+
+ /**
+ * A value for {@link #KEY_BUGREPORT_UPLOAD_DESTINATION}.
+ *
+ * Upload bugreports to GCS. Only works in {@code userdebug} or {@code eng} builds.
+ */
+ private static final String UPLOAD_DESTINATION_GCS = "gcs";
+
+ /**
+ * A system property to force enable the app bypassing the {@code userdebug/eng} build check.
+ */
+ private static final String PROP_FORCE_ENABLE = "android.car.bugreport.force_enable";
+
+ /**
+ * Temporary flag to retain the old behavior.
+ *
+ * Default is {@code true}.
+ *
+ * TODO(b/143183993): Disable auto-upload to GCS after testing DeviceConfig.
+ */
+ private static final String ENABLE_AUTO_UPLOAD = "android.car.bugreport.enableautoupload";
+
+ private final Object mLock = new Object();
+
+ @GuardedBy("mLock")
+ private String mUploadDestination = null;
+
+ void start() {
+ DeviceConfig.addOnPropertiesChangedListener(NAMESPACE_CAR,
+ ActivityThread.currentApplication().getMainExecutor(), this::onPropertiesChanged);
+ updateConstants();
+ }
+
+ private void onPropertiesChanged(DeviceConfig.Properties properties) {
+ if (properties.getKeyset().contains(KEY_BUGREPORT_UPLOAD_DESTINATION)) {
+ updateConstants();
+ }
+ }
+
+ /** Returns true if bugreport app is enabled for this device. */
+ static boolean isBugReportEnabled() {
+ return Build.IS_DEBUGGABLE || SystemProperties.getBoolean(PROP_FORCE_ENABLE, false);
+ }
+
+ /** If new bugreports should be scheduled for uploading. */
+ boolean getAutoUpload() {
+ if (isTempForceAutoUploadGcsEnabled()) {
+ Log.d(TAG, "Enabling auto-upload because ENABLE_AUTO_UPLOAD is true");
+ return true;
+ }
+ // TODO(b/144851443): Enable auto-upload only if upload destination is Gcs until
+ // we create a way to allow implementing OEMs custom upload logic.
+ return isUploadDestinationGcs();
+ }
+
+ /**
+ * Returns {@link true} if bugreport upload destination is GCS.
+ */
+ boolean isUploadDestinationGcs() {
+ if (isTempForceAutoUploadGcsEnabled()) {
+ Log.d(TAG, "Setting upload dest to GCS ENABLE_AUTO_UPLOAD is true");
+ return true;
+ }
+ // NOTE: enable it only for userdebug builds, unless it's force enabled using a system
+ // property.
+ return UPLOAD_DESTINATION_GCS.equals(getUploadDestination()) && Build.IS_DEBUGGABLE;
+ }
+
+ private static boolean isTempForceAutoUploadGcsEnabled() {
+ return SystemProperties.getBoolean(ENABLE_AUTO_UPLOAD, /* def= */ true);
+ }
+
+ /**
+ * Returns value of a flag {@link #KEY_BUGREPORT_UPLOAD_DESTINATION}.
+ */
+ private String getUploadDestination() {
+ synchronized (mLock) {
+ return mUploadDestination;
+ }
+ }
+
+ private void updateConstants() {
+ synchronized (mLock) {
+ mUploadDestination = DeviceConfig.getString(NAMESPACE_CAR,
+ KEY_BUGREPORT_UPLOAD_DESTINATION, /* defaultValue= */ null);
+ }
+ }
+
+ void dump(String prefix, PrintWriter pw) {
+ pw.println(prefix + "car.bugreport.Config:");
+
+ pw.print(prefix + " ");
+ pw.print("getAutoUpload");
+ pw.print("=");
+ pw.println(getAutoUpload() ? "true" : "false");
+
+ pw.print(prefix + " ");
+ pw.print("getUploadDestination");
+ pw.print("=");
+ pw.println(getUploadDestination());
+
+ pw.print(prefix + " ");
+ pw.print("isUploadDestinationGcs");
+ pw.print("=");
+ pw.println(isUploadDestinationGcs());
+ }
+}
diff --git a/tests/BugReportApp/src/com/android/car/bugreport/FileUtils.java b/tests/BugReportApp/src/com/android/car/bugreport/FileUtils.java
index 0f36859..bf12aa7 100644
--- a/tests/BugReportApp/src/com/android/car/bugreport/FileUtils.java
+++ b/tests/BugReportApp/src/com/android/car/bugreport/FileUtils.java
@@ -17,6 +17,8 @@
import android.content.Context;
+import com.google.common.base.Preconditions;
+
import java.io.File;
/**
@@ -34,14 +36,16 @@
*/
public class FileUtils {
private static final String PREFIX = "bugreport-";
- // bug reports waiting to be uploaded
+ /** A directory under the system user; contains bugreport zip files and audio files. */
private static final String PENDING_DIR = "bug_reports_pending";
- // temporary directory, used for zipping files
+ // Temporary directory under the current user, used for zipping files.
private static final String TEMP_DIR = "bug_reports_temp";
private static final String FS = "@";
- private static File getPendingDir(Context context) {
+ static File getPendingDir(Context context) {
+ Preconditions.checkArgument(context.getUser().isSystem(),
+ "Must be called from the system user.");
File dir = new File(context.getDataDir(), PENDING_DIR);
dir.mkdirs();
return dir;
@@ -62,15 +66,38 @@
* single file.
*/
static File getTempDir(Context context, String timestamp) {
+ Preconditions.checkArgument(!context.getUser().isSystem(),
+ "Must be called from the current user.");
return new File(context.getDataDir(), TEMP_DIR + "/" + timestamp);
}
/**
- * Returns zip file directory with the given timestamp and ldap
+ * Constructs a bugreport zip file name.
+ *
+ * <p>Add lookup code to the filename to allow matching audio file and bugreport file in USB.
*/
- static File getZipFile(Context context, String timestamp, String ldap) {
- File zipdir = getPendingDir(context);
- return new File(zipdir, PREFIX + ldap + FS + timestamp + ".zip");
+ static String getZipFileName(MetaBugReport bug) {
+ String lookupCode = extractLookupCode(bug);
+ return PREFIX + bug.getUserName() + FS + bug.getTimestamp() + "-" + lookupCode + ".zip";
+ }
+
+ /**
+ * Constructs a audio message file name.
+ *
+ * <p>Add lookup code to the filename to allow matching audio file and bugreport file in USB.
+ *
+ * @param timestamp - current timestamp, when audio was created.
+ * @param bug - a bug report.
+ */
+ static String getAudioFileName(String timestamp, MetaBugReport bug) {
+ String lookupCode = extractLookupCode(bug);
+ return PREFIX + bug.getUserName() + FS + timestamp + "-" + lookupCode + "-message.3gp";
+ }
+
+ private static String extractLookupCode(MetaBugReport bug) {
+ Preconditions.checkArgument(bug.getTitle().startsWith("["),
+ "Invalid bugreport title, doesn't contain lookup code. ");
+ return bug.getTitle().substring(1, BugReportActivity.LOOKUP_STRING_LENGTH + 1);
}
/**
@@ -99,7 +126,6 @@
return new File(getTempDir(context, timestamp), name);
}
-
/**
* Deletes a directory and its contents recursively
*
diff --git a/tests/BugReportApp/src/com/android/car/bugreport/JobSchedulingUtils.java b/tests/BugReportApp/src/com/android/car/bugreport/JobSchedulingUtils.java
index 922c910..ec09b1f 100644
--- a/tests/BugReportApp/src/com/android/car/bugreport/JobSchedulingUtils.java
+++ b/tests/BugReportApp/src/com/android/car/bugreport/JobSchedulingUtils.java
@@ -19,7 +19,6 @@
import android.app.job.JobScheduler;
import android.content.ComponentName;
import android.content.Context;
-import android.os.SystemProperties;
import android.util.Log;
/**
@@ -32,15 +31,7 @@
private static final int RETRY_DELAY_IN_MS = 5_000;
/**
- * The system property to disable auto-upload when bug reports are collected. When auto-upload
- * is disabled, the app waits for user action on collected bug reports: user can either
- * upload to Google Cloud or copy to flash drive.
- */
- private static final String PROP_DISABLE_AUTO_UPLOAD =
- "android.car.bugreport.disableautoupload";
-
- /**
- * Schedules an upload job under the current user.
+ * Schedules {@link UploadJob} under the current user.
*
* <p>Make sure this method is called under the primary user.
*
@@ -72,15 +63,4 @@
.setBackoffCriteria(RETRY_DELAY_IN_MS, JobInfo.BACKOFF_POLICY_LINEAR)
.build());
}
-
- /**
- * Returns true if collected bugreports should be uploaded automatically.
- *
- * <p>If it returns false, the app maps to an alternative workflow that requires user action
- * after bugreport is successfully written. A user then has an option to choose whether to
- * upload the bugreport or copy it to an external drive.
- */
- static boolean uploadByDefault() {
- return !SystemProperties.getBoolean(PROP_DISABLE_AUTO_UPLOAD, false);
- }
}
diff --git a/tests/BugReportApp/src/com/android/car/bugreport/MetaBugReport.java b/tests/BugReportApp/src/com/android/car/bugreport/MetaBugReport.java
index eeb491f..e458e22 100644
--- a/tests/BugReportApp/src/com/android/car/bugreport/MetaBugReport.java
+++ b/tests/BugReportApp/src/com/android/car/bugreport/MetaBugReport.java
@@ -15,77 +15,95 @@
*/
package com.android.car.bugreport;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.annotation.IntDef;
import android.os.Parcel;
import android.os.Parcelable;
-/** Represents the information that a bugreport can contain. */
-public final class MetaBugReport implements Parcelable {
- private final int mId;
- private final String mTimestamp;
- private final String mTitle;
- private final String mUsername;
- private final String mFilePath;
- private final int mStatus;
- private final String mStatusMessage;
+import com.google.auto.value.AutoValue;
- private MetaBugReport(Builder builder) {
- mId = builder.mId;
- mTimestamp = builder.mTimestamp;
- mTitle = builder.mTitle;
- mUsername = builder.mUsername;
- mFilePath = builder.mFilePath;
- mStatus = builder.mStatus;
- mStatusMessage = builder.mStatusMessage;
- }
+import java.lang.annotation.Retention;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/** Represents the information that a bugreport can contain. */
+@AutoValue
+abstract class MetaBugReport implements Parcelable {
+
+ private static final DateFormat BUG_REPORT_TIMESTAMP_DATE_FORMAT =
+ new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss");
+
+ /** The app records audio message when initiated. Can change audio state. */
+ static final int TYPE_INTERACTIVE = 0;
+
+ /**
+ * The app doesn't show dialog and doesn't record audio when initiated. It allows user to
+ * add audio message when bugreport is collected.
+ */
+ static final int TYPE_SILENT = 1;
+
+ /** Annotation for bug report types. */
+ @Retention(SOURCE)
+ @IntDef({TYPE_INTERACTIVE, TYPE_SILENT})
+ @interface BugReportType {};
/**
* @return Id of the bug report. Bug report id monotonically increases and is unique.
*/
- public int getId() {
- return mId;
- }
+ public abstract int getId();
/**
* @return Username (LDAP) that created this bugreport
*/
- public String getUsername() {
- return mUsername == null ? "" : mUsername;
- }
+ public abstract String getUserName();
/**
* @return Title of the bug.
*/
- public String getTitle() {
- return mTitle == null ? "" : mTitle;
- }
+ public abstract String getTitle();
/**
* @return Timestamp when the bug report is initialized.
*/
- public String getTimestamp() {
- return mTimestamp == null ? "" : mTimestamp;
- }
+ public abstract String getTimestamp();
/**
- * @return path to the zip file
+ * @return path to the zip file stored under the system user.
+ *
+ * <p>NOTE: This is the old way of storing final zipped bugreport. See
+ * {@link BugStorageProvider#URL_SEGMENT_OPEN_FILE} for more info.
*/
- public String getFilePath() {
- return mFilePath == null ? "" : mFilePath;
- }
+ public abstract String getFilePath();
/**
- * @return Status of the bug upload.
+ * @return filename of the bug report zip file stored under the system user.
*/
- public int getStatus() {
- return mStatus;
- }
+ public abstract String getBugReportFileName();
+
+ /**
+ * @return filename of the audio message file stored under the system user.
+ */
+ public abstract String getAudioFileName();
+
+ /**
+ * @return {@link Status} of the bug upload.
+ */
+ public abstract int getStatus();
/**
* @return StatusMessage of the bug upload.
*/
- public String getStatusMessage() {
- return mStatusMessage == null ? "" : mStatusMessage;
- }
+ public abstract String getStatusMessage();
+
+ /**
+ * @return {@link BugReportType}.
+ */
+ public abstract int getType();
+
+ /** @return {@link Builder} from the meta bug report. */
+ public abstract Builder toBuilder();
@Override
public int describeContents() {
@@ -94,13 +112,33 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(mId);
- dest.writeString(mTimestamp);
- dest.writeString(mTitle);
- dest.writeString(mUsername);
- dest.writeString(mFilePath);
- dest.writeInt(mStatus);
- dest.writeString(mStatusMessage);
+ dest.writeInt(getId());
+ dest.writeString(getTimestamp());
+ dest.writeString(getTitle());
+ dest.writeString(getUserName());
+ dest.writeString(getFilePath());
+ dest.writeString(getBugReportFileName());
+ dest.writeString(getAudioFileName());
+ dest.writeInt(getStatus());
+ dest.writeString(getStatusMessage());
+ dest.writeInt(getType());
+ }
+
+ /** Converts {@link Date} to bugreport timestamp. */
+ static String toBugReportTimestamp(Date date) {
+ return BUG_REPORT_TIMESTAMP_DATE_FORMAT.format(date);
+ }
+
+ /** Creates a {@link Builder} with default, non-null values. */
+ static Builder builder() {
+ return new AutoValue_MetaBugReport.Builder()
+ .setTimestamp("")
+ .setFilePath("")
+ .setBugReportFileName("")
+ .setAudioFileName("")
+ .setStatusMessage("")
+ .setTitle("")
+ .setUserName("");
}
/** A creator that's used by Parcelable. */
@@ -112,14 +150,22 @@
String title = in.readString();
String username = in.readString();
String filePath = in.readString();
+ String bugReportFileName = in.readString();
+ String audioFileName = in.readString();
int status = in.readInt();
String statusMessage = in.readString();
- return new Builder(id, timestamp)
+ int type = in.readInt();
+ return MetaBugReport.builder()
+ .setId(id)
+ .setTimestamp(timestamp)
.setTitle(title)
.setUserName(username)
- .setFilepath(filePath)
+ .setFilePath(filePath)
+ .setBugReportFileName(bugReportFileName)
+ .setAudioFileName(audioFileName)
.setStatus(status)
.setStatusMessage(statusMessage)
+ .setType(type)
.build();
}
@@ -129,59 +175,38 @@
};
/** Builder for MetaBugReport. */
- public static class Builder {
- private final int mId;
- private final String mTimestamp;
- private String mTitle;
- private String mUsername;
- private String mFilePath;
- private int mStatus;
- private String mStatusMessage;
+ @AutoValue.Builder
+ abstract static class Builder {
+ /** Sets id. */
+ public abstract Builder setId(int id);
- /**
- * Initializes MetaBugReport.Builder.
- *
- * @param id - mandatory bugreport id
- * @param timestamp - mandatory timestamp when bugreport initialized.
- */
- public Builder(int id, String timestamp) {
- mId = id;
- mTimestamp = timestamp;
- }
+ /** Sets timestamp. */
+ public abstract Builder setTimestamp(String timestamp);
/** Sets title. */
- public Builder setTitle(String title) {
- mTitle = title;
- return this;
- }
+ public abstract Builder setTitle(String title);
/** Sets username. */
- public Builder setUserName(String username) {
- mUsername = username;
- return this;
- }
+ public abstract Builder setUserName(String username);
/** Sets filepath. */
- public Builder setFilepath(String filePath) {
- mFilePath = filePath;
- return this;
- }
+ public abstract Builder setFilePath(String filePath);
- /** Sets status. */
- public Builder setStatus(int status) {
- mStatus = status;
- return this;
- }
+ /** Sets bugReportFileName. */
+ public abstract Builder setBugReportFileName(String bugReportFileName);
+
+ /** Sets audioFileName. */
+ public abstract Builder setAudioFileName(String audioFileName);
+
+ /** Sets {@link Status}. */
+ public abstract Builder setStatus(int status);
/** Sets statusmessage. */
- public Builder setStatusMessage(String statusMessage) {
- mStatusMessage = statusMessage;
- return this;
- }
+ public abstract Builder setStatusMessage(String statusMessage);
- /** Returns a {@link MetaBugReport}. */
- public MetaBugReport build() {
- return new MetaBugReport(this);
- }
+ /** Sets the {@link BugReportType}. */
+ public abstract Builder setType(@BugReportType int type);
+
+ public abstract MetaBugReport build();
}
}
diff --git a/tests/BugReportApp/src/com/android/car/bugreport/SimpleUploaderAsyncTask.java b/tests/BugReportApp/src/com/android/car/bugreport/SimpleUploaderAsyncTask.java
index 7cca613..0cc5c1a 100644
--- a/tests/BugReportApp/src/com/android/car/bugreport/SimpleUploaderAsyncTask.java
+++ b/tests/BugReportApp/src/com/android/car/bugreport/SimpleUploaderAsyncTask.java
@@ -29,18 +29,24 @@
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.services.storage.Storage;
import com.google.api.services.storage.model.StorageObject;
+import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
+import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
import java.util.List;
import java.util.Map;
+import java.util.zip.ZipOutputStream;
/**
- * Uploads a file to GCS using a simple (no-multipart / no-resume) upload policy.
+ * Uploads a bugreport files to GCS using a simple (no-multipart / no-resume) upload policy.
+ *
+ * <p>It merges bugreport zip file and audio file into one final zip file and uploads it.
*
* <p>Please see {@code res/values/configs.xml} and {@code res/raw/gcs_credentials.json} for the
* configuration.
@@ -113,14 +119,51 @@
Storage storage = new Storage.Builder(httpTransport, jsonFactory, credential)
.setApplicationName("Bugreportupload/1.0").build();
- File bugReportFile = new File(bugReport.getFilePath());
- String fileName = bugReportFile.getName();
- try (FileInputStream inputStream = new FileInputStream(bugReportFile)) {
- StorageObject object = uploadSimple(storage, bugReport, fileName, inputStream);
- Log.v(TAG, "finished uploading object " + object.getName() + " file " + fileName);
+ File tmpBugReportFile = zipBugReportFiles(bugReport);
+ Log.d(TAG, "Uploading file " + tmpBugReportFile);
+ try {
+ // Upload filename is bugreport filename, although, now it contains the audio message.
+ String fileName = bugReport.getBugReportFileName();
+ try (FileInputStream inputStream = new FileInputStream(tmpBugReportFile)) {
+ StorageObject object = uploadSimple(storage, bugReport, fileName, inputStream);
+ Log.v(TAG, "finished uploading object " + object.getName() + " file " + fileName);
+ }
+ File pendingDir = FileUtils.getPendingDir(mContext);
+ // Delete only after successful upload; the files are needed for retry.
+ if (!Strings.isNullOrEmpty(bugReport.getAudioFileName())) {
+ Log.v(TAG, "Deleting file " + bugReport.getAudioFileName());
+ new File(pendingDir, bugReport.getAudioFileName()).delete();
+ }
+ if (!Strings.isNullOrEmpty(bugReport.getBugReportFileName())) {
+ Log.v(TAG, "Deleting file " + bugReport.getBugReportFileName());
+ new File(pendingDir, bugReport.getBugReportFileName()).delete();
+ }
+ } finally {
+ // Delete the temp file if it's not a MetaBugReport#getFilePath, because it's needed
+ // for retry.
+ if (Strings.isNullOrEmpty(bugReport.getFilePath())) {
+ Log.v(TAG, "Deleting file " + tmpBugReportFile);
+ tmpBugReportFile.delete();
+ }
}
- Log.v(TAG, "Deleting file " + fileName);
- bugReportFile.delete();
+ }
+
+ private File zipBugReportFiles(MetaBugReport bugReport) throws IOException {
+ if (!Strings.isNullOrEmpty(bugReport.getFilePath())) {
+ // Old bugreports still have this field.
+ return new File(bugReport.getFilePath());
+ }
+ File finalZipFile =
+ File.createTempFile("bugreport", ".zip", mContext.getCacheDir());
+ File pendingDir = FileUtils.getPendingDir(mContext);
+ try (ZipOutputStream zipStream = new ZipOutputStream(
+ new BufferedOutputStream(new FileOutputStream(finalZipFile)))) {
+ ZipUtils.extractZippedFileToZipStream(
+ new File(pendingDir, bugReport.getBugReportFileName()), zipStream);
+ ZipUtils.addFileToZipStream(
+ new File(pendingDir, bugReport.getAudioFileName()), zipStream);
+ }
+ return finalZipFile;
}
@Override
@@ -131,7 +174,7 @@
/** Returns true is there are more files to upload. */
@Override
protected Boolean doInBackground(Void... voids) {
- List<MetaBugReport> bugReports = BugStorageUtils.getPendingBugReports(mContext);
+ List<MetaBugReport> bugReports = BugStorageUtils.getUploadPendingBugReports(mContext);
for (MetaBugReport bugReport : bugReports) {
try {
diff --git a/tests/BugReportApp/src/com/android/car/bugreport/StartUpBootReceiver.java b/tests/BugReportApp/src/com/android/car/bugreport/StartUpBootReceiver.java
index 07b5843..7528c21 100644
--- a/tests/BugReportApp/src/com/android/car/bugreport/StartUpBootReceiver.java
+++ b/tests/BugReportApp/src/com/android/car/bugreport/StartUpBootReceiver.java
@@ -33,6 +33,9 @@
@Override
public void onReceive(Context context, Intent intent) {
+ if (!Config.isBugReportEnabled()) {
+ return;
+ }
// Run it only once for the system user (u0) and ignore for other users.
UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
if (!userManager.isSystemUser()) {
diff --git a/tests/BugReportApp/src/com/android/car/bugreport/Status.java b/tests/BugReportApp/src/com/android/car/bugreport/Status.java
index 2c1e6dc..84250bb 100644
--- a/tests/BugReportApp/src/com/android/car/bugreport/Status.java
+++ b/tests/BugReportApp/src/com/android/car/bugreport/Status.java
@@ -42,7 +42,16 @@
STATUS_MOVE_SUCCESSFUL(7),
// Bugreport move has failed.
- STATUS_MOVE_FAILED(8);
+ STATUS_MOVE_FAILED(8),
+
+ // Bugreport is moving to USB drive.
+ STATUS_MOVE_IN_PROGRESS(9),
+
+ // Bugreport is expired. Associated file is deleted from the disk.
+ STATUS_EXPIRED(10),
+
+ // Bugreport needs audio message.
+ STATUS_AUDIO_PENDING(11);
private final int mValue;
@@ -76,6 +85,12 @@
return "Move successful";
case 8:
return "Move failed";
+ case 9:
+ return "Move in progress";
+ case 10:
+ return "Expired";
+ case 11:
+ return "Audio message pending";
}
return "unknown";
}
diff --git a/tests/BugReportApp/src/com/android/car/bugreport/UploadJob.java b/tests/BugReportApp/src/com/android/car/bugreport/UploadJob.java
index c6d7ec8..a0b9cec 100644
--- a/tests/BugReportApp/src/com/android/car/bugreport/UploadJob.java
+++ b/tests/BugReportApp/src/com/android/car/bugreport/UploadJob.java
@@ -27,6 +27,9 @@
@Override
public boolean onStartJob(final JobParameters jobParameters) {
+ if (!Config.isBugReportEnabled()) {
+ return false;
+ }
Log.v(TAG, "Starting upload job");
mUploader = new SimpleUploaderAsyncTask(
this, reschedule -> jobFinished(jobParameters, reschedule));
diff --git a/tests/BugReportApp/src/com/android/car/bugreport/ZipUtils.java b/tests/BugReportApp/src/com/android/car/bugreport/ZipUtils.java
new file mode 100644
index 0000000..93dad40
--- /dev/null
+++ b/tests/BugReportApp/src/com/android/car/bugreport/ZipUtils.java
@@ -0,0 +1,87 @@
+/*
+ * 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.bugreport;
+
+import android.util.Log;
+
+import com.google.common.io.ByteStreams;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Enumeration;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipOutputStream;
+
+/** Zip utility functions. */
+final class ZipUtils {
+ private static final String TAG = ZipUtils.class.getSimpleName();
+
+ /** Extracts the contents of a zip file to the zip output stream. */
+ static void extractZippedFileToZipStream(File file, ZipOutputStream zipStream) {
+ if (!file.exists()) {
+ Log.w(TAG, "File " + file + " not found");
+ return;
+ }
+ if (file.length() == 0) {
+ // If there were issues with reading from dumpstate socket, the dumpstate zip
+ // file still might be available in
+ // /data/user_de/0/com.android.shell/files/bugreports/.
+ Log.w(TAG, "Zip file " + file.getName() + " is empty, skipping.");
+ return;
+ }
+ try (ZipFile zipFile = new ZipFile(file)) {
+ Enumeration<? extends ZipEntry> entries = zipFile.entries();
+ while (entries.hasMoreElements()) {
+ ZipEntry entry = entries.nextElement();
+ try (InputStream stream = zipFile.getInputStream(entry)) {
+ writeInputStreamToZipStream(entry.getName(), stream, zipStream);
+ }
+ }
+ } catch (IOException e) {
+ Log.w(TAG, "Failed to add " + file + " to zip", e);
+ }
+ }
+
+ /** Adds a file to the zip output stream. */
+ static void addFileToZipStream(File file, ZipOutputStream zipStream) {
+ if (!file.exists()) {
+ Log.w(TAG, "File " + file + " not found");
+ return;
+ }
+ if (file.length() == 0) {
+ Log.w(TAG, "File " + file.getName() + " is empty, skipping.");
+ return;
+ }
+ try (FileInputStream audioInput = new FileInputStream(file)) {
+ writeInputStreamToZipStream(file.getName(), audioInput, zipStream);
+ } catch (IOException e) {
+ Log.w(TAG, "Failed to add " + file + "to the final zip");
+ }
+ }
+
+ private static void writeInputStreamToZipStream(
+ String filename, InputStream input, ZipOutputStream zipStream) throws IOException {
+ ZipEntry entry = new ZipEntry(filename);
+ zipStream.putNextEntry(entry);
+ ByteStreams.copy(input, zipStream);
+ zipStream.closeEntry();
+ }
+
+ private ZipUtils() {}
+}
diff --git a/tests/BugReportApp/tests/Android.bp b/tests/BugReportApp/tests/Android.bp
new file mode 100644
index 0000000..9f54a75
--- /dev/null
+++ b/tests/BugReportApp/tests/Android.bp
@@ -0,0 +1,42 @@
+// 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: "BugReportAppTest",
+
+ srcs: ["src/**/*.java"],
+
+ instrumentation_for: "BugReportApp",
+
+ certificate: "platform",
+ optimize: {
+ enabled: false,
+ },
+ platform_apis: true,
+
+ libs: [
+ "android.test.base",
+ "android.test.mock",
+ "android.test.runner",
+ ],
+
+ static_libs: [
+ "android-support-test",
+ "truth-prebuilt",
+ ],
+
+ test_suites: [
+ "device-tests",
+ ],
+}
diff --git a/tests/BugReportApp/tests/AndroidManifest.xml b/tests/BugReportApp/tests/AndroidManifest.xml
new file mode 100644
index 0000000..26736c6
--- /dev/null
+++ b/tests/BugReportApp/tests/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?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.bugreport.tests" >
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation
+ android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:label="BugReportAppTest"
+ android:targetPackage="com.android.car.bugreport" />
+</manifest>
diff --git a/tests/BugReportApp/tests/src/com/google/android/car/bugreport/BugStorageUtilsTest.java b/tests/BugReportApp/tests/src/com/google/android/car/bugreport/BugStorageUtilsTest.java
new file mode 100644
index 0000000..29dcc19
--- /dev/null
+++ b/tests/BugReportApp/tests/src/com/google/android/car/bugreport/BugStorageUtilsTest.java
@@ -0,0 +1,131 @@
+/*
+ * 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.bugreport;
+
+import static com.android.car.bugreport.MetaBugReport.TYPE_INTERACTIVE;
+import static com.android.car.bugreport.Status.STATUS_PENDING_USER_ACTION;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.time.Instant;
+import java.util.Date;
+
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+public class BugStorageUtilsTest {
+ private static final String TIMESTAMP_TODAY = MetaBugReport.toBugReportTimestamp(new Date());
+ private static final String BUGREPORT_ZIP_FILE_NAME = "bugreport@ASD.zip";
+ private static final int BUGREPORT_ZIP_FILE_CONTENT = 1;
+
+ private Context mContext;
+
+ @Before
+ public void setUp() {
+ mContext = InstrumentationRegistry.getContext();
+ }
+
+ @Test
+ public void test_createBugReport_createsAndReturnsMetaBugReport() throws Exception {
+ MetaBugReport bug = createBugReportWithStatus(TIMESTAMP_TODAY,
+ STATUS_PENDING_USER_ACTION, TYPE_INTERACTIVE, /* createBugReportFile= */ true);
+
+ assertThat(BugStorageUtils.findBugReport(mContext, bug.getId()).get()).isEqualTo(bug);
+ }
+
+ @Test
+ public void test_expireBugReport_marksBugReportDeletedAndDeletesZip() throws Exception {
+ MetaBugReport bug = createBugReportWithStatus(TIMESTAMP_TODAY,
+ STATUS_PENDING_USER_ACTION, TYPE_INTERACTIVE, /* createBugReportFile= */ true);
+ try (InputStream in = BugStorageUtils.openBugReportFileToRead(mContext, bug)) {
+ assertThat(in).isNotNull();
+ }
+ Instant now = Instant.now();
+
+ boolean deleteResult = BugStorageUtils.expireBugReport(mContext, bug, now);
+
+ assertThat(deleteResult).isTrue();
+ assertThat(BugStorageUtils.findBugReport(mContext, bug.getId()).get())
+ .isEqualTo(bug.toBuilder()
+ .setStatus(Status.STATUS_EXPIRED.getValue())
+ .setStatusMessage("Expired on " + now).build());
+ assertThrows(FileNotFoundException.class, () ->
+ BugStorageUtils.openBugReportFileToRead(mContext, bug));
+ }
+
+ @Test
+ public void test_completeDeleteBugReport_removesBugReportRecordFromDb() throws Exception {
+ MetaBugReport bug = createBugReportWithStatus(TIMESTAMP_TODAY,
+ STATUS_PENDING_USER_ACTION, TYPE_INTERACTIVE, /* createBugReportFile= */ true);
+ try (InputStream in = BugStorageUtils.openBugReportFileToRead(mContext, bug)) {
+ assertThat(in).isNotNull();
+ }
+
+ boolean deleteResult = BugStorageUtils.completeDeleteBugReport(mContext, bug.getId());
+
+ assertThat(deleteResult).isTrue();
+ assertThat(BugStorageUtils.findBugReport(mContext, bug.getId()).isPresent()).isFalse();
+ assertThrows(IllegalArgumentException.class, () ->
+ BugStorageUtils.openBugReportFileToRead(mContext, bug));
+ }
+
+ private MetaBugReport createBugReportWithStatus(
+ String timestamp, Status status, int type, boolean createBugReportFile)
+ throws IOException {
+ MetaBugReport bugReport = BugStorageUtils.createBugReport(
+ mContext, "sample title", timestamp, "driver", type);
+ if (createBugReportFile) {
+ bugReport = BugStorageUtils.update(mContext,
+ bugReport.toBuilder().setBugReportFileName(BUGREPORT_ZIP_FILE_NAME).build());
+ try (OutputStream out = BugStorageUtils.openBugReportFileToWrite(mContext, bugReport)) {
+ out.write(BUGREPORT_ZIP_FILE_CONTENT);
+ }
+ }
+ return BugStorageUtils.setBugReportStatus(mContext, bugReport, status, "");
+ }
+
+ private static void assertThrows(Class<? extends Throwable> exceptionClass,
+ ExceptionRunnable r) {
+ try {
+ r.run();
+ } catch (Throwable e) {
+ assertTrue("Expected exception type " + exceptionClass.getName() + " but got "
+ + e.getClass().getName(), exceptionClass.isAssignableFrom(e.getClass()));
+ return;
+ }
+ fail("Expected exception type " + exceptionClass.getName()
+ + ", but no exception was thrown");
+ }
+
+ private interface ExceptionRunnable {
+ void run() throws Exception;
+ }
+}
diff --git a/tests/BugReportApp/utils/bugreport_app_tester.py b/tests/BugReportApp/utils/bugreport_app_tester.py
index 0fb7e53..f095a53 100755
--- a/tests/BugReportApp/utils/bugreport_app_tester.py
+++ b/tests/BugReportApp/utils/bugreport_app_tester.py
@@ -56,13 +56,17 @@
SQLITE_DB_DIR = '/data/user/0/%s/databases' % BUGREPORT_PACKAGE
SQLITE_DB_PATH = SQLITE_DB_DIR + '/bugreport.db'
-# The statuses are from `src/com/android/car/bugreport/Status.java.
+# The statuses are from `src/com.android.car.bugreport/Status.java.
STATUS_WRITE_PENDING = 0
STATUS_WRITE_FAILED = 1
STATUS_UPLOAD_PENDING = 2
STATUS_UPLOAD_SUCCESS = 3
STATUS_UPLOAD_FAILED = 4
STATUS_USER_CANCELLED = 5
+STATUS_PENDING_USER_ACTION = 6
+STATUS_MOVE_SUCCESSFUL = 7
+STATUS_MOVE_FAILED = 8
+STATUS_MOVE_IN_PROGRESS = 9
DUMPSTATE_DEADLINE_SEC = 300 # 10 minutes.
UPLOAD_DEADLINE_SEC = 180 # 3 minutes.
@@ -120,6 +124,14 @@
return 'UPLOAD_FAILED'
elif status == STATUS_USER_CANCELLED:
return 'USER_CANCELLED'
+ elif status == STATUS_PENDING_USER_ACTION:
+ return 'PENDING_USER_ACTION'
+ elif status == STATUS_MOVE_SUCCESSFUL:
+ return 'MOVE_SUCCESSFUL'
+ elif status == STATUS_MOVE_FAILED:
+ return 'MOVE_FAILED'
+ elif status == STATUS_MOVE_IN_PROGRESS:
+ return 'MOVE_IN_PROGRESS'
return 'UNKNOWN_STATUS'
@@ -337,7 +349,7 @@
_bugreport_status_to_str(meta_bugreport.status))
def _wait_for_bugreport_to_complete(self, bugreport_id):
- """Waits until status changes to UPLOAD_PENDING.
+ """Waits until status changes to WRITE_PENDING.
It means dumpstate (bugreport) is completed (or failed).
@@ -356,13 +368,17 @@
print('\nDumpstate (bugreport) completed (or failed).')
def _wait_for_bugreport_to_upload(self, bugreport_id):
- """Waits bugreport to be uploaded and returns None if succeeds."""
+ """Waits bugreport to be uploaded and returns None if succeeds.
+
+ NOTE: If "android.car.bugreport.disableautoupload" system property is set,
+ the App will not upload.
+ """
print('\nWaiting for the bug report to be uploaded.')
err_msg = self._wait_for_bugreport_status_to_change_to(
STATUS_UPLOAD_SUCCESS,
UPLOAD_DEADLINE_SEC,
bugreport_id,
- allowed_statuses=[STATUS_UPLOAD_PENDING])
+ allowed_statuses=[STATUS_UPLOAD_PENDING, STATUS_PENDING_USER_ACTION])
if err_msg:
print('Failed to upload: %s' % err_msg)
return err_msg
diff --git a/tests/CarDeveloperOptions/res/values-ar/strings.xml b/tests/CarDeveloperOptions/res/values-ar/strings.xml
index bdcb7d0..ce6bb1c 100644
--- a/tests/CarDeveloperOptions/res/values-ar/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-ar/strings.xml
@@ -2347,7 +2347,7 @@
<string name="power_usage_level_and_status" msgid="8873534076894160727">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATUS">%2$s</xliff:g>"</string>
<string name="power_discharge_remaining" msgid="3461915627093471868">"الوقت المتبقي: <xliff:g id="REMAIN">%1$s</xliff:g>"</string>
<string name="power_charge_remaining" msgid="2730510256218879651">"<xliff:g id="UNTIL_CHARGED">%1$s</xliff:g> للشحن"</string>
- <string name="background_activity_title" msgid="7207836362312111483">"تقييد الخلفية"</string>
+ <string name="background_activity_title" msgid="7207836362312111483">"حظر العمل في الخلفية"</string>
<string name="background_activity_summary" msgid="582372194738538145">"السماح بتشغيل التطبيق في الخلفية"</string>
<string name="background_activity_summary_disabled" msgid="457944930942085876">"غير مسموح بتشغيل التطبيق في الخلفية"</string>
<string name="background_activity_summary_whitelisted" msgid="4713321059375873828">"يتعذر تقييد استخدام الخلفية."</string>
@@ -2446,7 +2446,7 @@
<string name="battery_tip_restrict_app_dialog_message" msgid="6905822297507947381">"لتوفير شحن البطارية، أوقف <xliff:g id="APP">%1$s</xliff:g> عن استخدام البطارية في الخلفية علمًا بأن هذا التطبيق قد لا يعمل على نحو صحيح وقد تتأخر الإشعارات."</string>
<string name="battery_tip_restrict_apps_less_than_5_dialog_message" msgid="4225881888543582456">"لتوفير شحن البطارية، أوقف هذه التطبيقات عن استخدام البطارية في الخلفية علمًا بأن التطبيقات المقيدة قد لا تعمل على نحو صحيح وقد تتأخر الإشعارات.\n\nالتطبيقات:"</string>
<string name="battery_tip_restrict_apps_more_than_5_dialog_message" msgid="1748375562539446634">"لتوفير شحن البطارية، أوقف هذه التطبيقات عن استخدام البطارية في الخلفية علمًا بأن التطبيقات المقيدة قد لا تعمل على نحو صحيح وقد تتأخر الإشعارات.\n\nالتطبيقات:\n<xliff:g id="APP_LIST">%1$s</xliff:g>."</string>
- <string name="battery_tip_restrict_app_dialog_ok" msgid="2573410775701913487">"تقييد"</string>
+ <string name="battery_tip_restrict_app_dialog_ok" msgid="2573410775701913487">"حظر التشغيل"</string>
<string name="battery_tip_unrestrict_app_dialog_title" msgid="812458516399125710">"هل تريد إزالة التقييد؟"</string>
<string name="battery_tip_unrestrict_app_dialog_message" msgid="8120081438825031335">"سيتمكّن هذا التطبيق من استخدام البطارية في الخلفية، وقد يؤدي ذلك إلى نفاد شحنها قبل الوقت المتوقع."</string>
<string name="battery_tip_unrestrict_app_dialog_ok" msgid="9154938931448151479">"إزالة"</string>
diff --git a/tests/CarDeveloperOptions/res/values-bn/strings.xml b/tests/CarDeveloperOptions/res/values-bn/strings.xml
index e2c8d76..fcb6999 100644
--- a/tests/CarDeveloperOptions/res/values-bn/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-bn/strings.xml
@@ -1183,7 +1183,7 @@
<string name="brightness" msgid="7309120144111305275">"উজ্জ্বলতার স্তর"</string>
<string name="brightness_title" msgid="5660190946911149690">"উজ্জ্বলতা"</string>
<string name="brightness_summary" msgid="8687101964451818730">"স্ক্রীনের উজ্জ্বলতা সামঞ্জস্য করুন"</string>
- <string name="auto_brightness_title" msgid="908511534369820426">"অ্যাডাপ্টিভ উজ্জ্বলতা"</string>
+ <string name="auto_brightness_title" msgid="908511534369820426">"অভিযোজিত উজ্জ্বলতা"</string>
<string name="auto_brightness_summary_on" msgid="121488862610275737">"চালু আছে"</string>
<string name="auto_brightness_summary_off" msgid="8569141123211510256">"বন্ধ আছে"</string>
<string name="auto_brightness_summary_very_low" msgid="7625647285740629347">"পছন্দের উজ্জ্বলতার মান খুব কম"</string>
@@ -3128,7 +3128,7 @@
<string name="keywords_battery_saver_sticky" msgid="8733804259716284872">"ব্যাটারি সেভার, স্টিকি, লেগে থাকা, পাওয়ার সেভার, ব্যাটারি"</string>
<string name="default_sound" msgid="6675629744816442953">"ডিফল্ট সাউন্ড"</string>
<string name="sound_settings_summary" msgid="8467549670633195109">"রিং ভলিউম <xliff:g id="PERCENTAGE">%1$s</xliff:g> তে রয়েছে"</string>
- <string name="sound_dashboard_summary" msgid="5187301919242823508">"ভলিউম, কম্পন, বিরক্ত করবে না"</string>
+ <string name="sound_dashboard_summary" msgid="5187301919242823508">"ভলিউম, ভাইব্রেশন, বিরক্ত করবে না"</string>
<string name="sound_settings_summary_vibrate" msgid="2194491116884798590">"রিঙ্গারকে ভাইব্রেট অবস্থায় সেট করা হয়েছে"</string>
<string name="sound_settings_summary_silent" msgid="899823817462768876">"রিঙ্গারকে নীরব অবস্থায় সেট করা হয়েছে"</string>
<string name="sound_settings_example_summary" msgid="2091822107298841827">"রিং ভলিউম ৮০% তে রয়েছে"</string>
diff --git a/tests/CarDeveloperOptions/res/values-bs/strings.xml b/tests/CarDeveloperOptions/res/values-bs/strings.xml
index ce5a987..5504da2 100644
--- a/tests/CarDeveloperOptions/res/values-bs/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-bs/strings.xml
@@ -3736,7 +3736,7 @@
<string name="usage_access" msgid="2023443456361489516">"Pristup korištenju"</string>
<string name="permit_usage_access" msgid="3321727608629752758">"Dopusti pristup korištenju"</string>
<string name="app_usage_preference" msgid="5691545073101551727">"Postavke upotrebe aplikacija"</string>
- <string name="time_spent_in_app_pref_title" msgid="2803186835902798451">"Vrijeme upotrebe"</string>
+ <string name="time_spent_in_app_pref_title" msgid="2803186835902798451">"Vrijeme korištenja uređaja"</string>
<string name="usage_access_description" msgid="2178083292760305207">"Pristup korištenju omogućava aplikaciji da prati koje druge aplikacije koristite i koliko često, kao i da vidi vašeg mobilnog operatera, postavke jezika i druge detalje."</string>
<string name="memory_settings_title" msgid="7867148522014070721">"Memorija"</string>
<string name="memory_details_title" msgid="6364825184513396865">"Detalji o memoriji"</string>
diff --git a/tests/CarDeveloperOptions/res/values-ca/strings.xml b/tests/CarDeveloperOptions/res/values-ca/strings.xml
index 9789a8a..fe126af 100644
--- a/tests/CarDeveloperOptions/res/values-ca/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-ca/strings.xml
@@ -1221,11 +1221,11 @@
<string name="night_display_summary_off" msgid="8850539785332228069">"Desactivada / <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="night_display_summary_off_auto_mode_never" msgid="8618824386434992487">"No s\'activarà mai automàticament"</string>
<string name="night_display_summary_off_auto_mode_custom" msgid="596847003171394411">"S\'activarà automàticament a les <xliff:g id="ID_1">%1$s</xliff:g>"</string>
- <string name="night_display_summary_off_auto_mode_twilight" msgid="4071750976585359952">"S\'activarà automàticament quan es pongui el sol"</string>
+ <string name="night_display_summary_off_auto_mode_twilight" msgid="4071750976585359952">"S\'activarà automàticament al vespre"</string>
<string name="night_display_summary_on" msgid="6580571388791426596">"Activat / <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="night_display_summary_on_auto_mode_never" msgid="5461580863060506687">"No es desactivarà mai automàticament"</string>
<string name="night_display_summary_on_auto_mode_custom" msgid="2200631112239399233">"Es desactivarà automàticament a les <xliff:g id="ID_1">%1$s</xliff:g>"</string>
- <string name="night_display_summary_on_auto_mode_twilight" msgid="8386769601369289561">"Es desactivarà automàticament quan surti el sol"</string>
+ <string name="night_display_summary_on_auto_mode_twilight" msgid="8386769601369289561">"Es desactivarà automàticament a l\'alba"</string>
<string name="night_display_activation_on_manual" msgid="8379477527072027346">"Activa ara"</string>
<string name="night_display_activation_off_manual" msgid="7776082151269794201">"Desactiva ara"</string>
<string name="night_display_activation_on_twilight" msgid="5610294051700287249">"Activa fins a l\'alba"</string>
@@ -3294,7 +3294,7 @@
<string name="other_sound_category_preference_title" msgid="2045757472469840859">"Vibracions i altres sons"</string>
<string name="configure_notification_settings" msgid="291914315140851270">"Notificacions"</string>
<string name="recent_notifications" msgid="8125865995065032049">"Enviades fa poc"</string>
- <string name="recent_notifications_see_all_title" msgid="4089007770442871469">"Mostra-les totes des de fa 7 dies"</string>
+ <string name="recent_notifications_see_all_title" msgid="4089007770442871469">"Mostra totes les dels 7 darrers dies"</string>
<string name="advanced_section_header" msgid="984680389373090015">"Configuració avançada"</string>
<string name="profile_section_header" msgid="5471479005472037417">"Notificacions de la feina"</string>
<string name="asst_capability_prioritizer_title" msgid="3488284760645922160">"Prioritat de les notificacions automàtiques"</string>
diff --git a/tests/CarDeveloperOptions/res/values-da/strings.xml b/tests/CarDeveloperOptions/res/values-da/strings.xml
index 6e5e892..6883803 100644
--- a/tests/CarDeveloperOptions/res/values-da/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-da/strings.xml
@@ -1213,7 +1213,7 @@
<string name="night_display_auto_mode_title" msgid="8493573087102481588">"Tidsplan"</string>
<string name="night_display_auto_mode_never" msgid="2897444637217807088">"Ingen"</string>
<string name="night_display_auto_mode_custom" msgid="1400891076453963151">"Aktiveres på valgt tidspunkt"</string>
- <string name="night_display_auto_mode_twilight" msgid="4000162110017520674">"Aktiveres fra sol ned til sol op"</string>
+ <string name="night_display_auto_mode_twilight" msgid="4000162110017520674">"Aktiveres fra solnedgang til solopgang"</string>
<string name="night_display_start_time_title" msgid="1069255169673371077">"Starttidspunkt"</string>
<string name="night_display_end_time_title" msgid="2760793157124245911">"Sluttidspunkt"</string>
<string name="night_display_status_title" msgid="1727020934735770319">"Status"</string>
diff --git a/tests/CarDeveloperOptions/res/values-fa/strings.xml b/tests/CarDeveloperOptions/res/values-fa/strings.xml
index ef79cc5..ade25b4 100644
--- a/tests/CarDeveloperOptions/res/values-fa/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-fa/strings.xml
@@ -1849,7 +1849,7 @@
<string name="filter_dlg_title" msgid="115313222190512670">"انتخاب گزینههای فیلتر"</string>
<string name="filter_apps_all" msgid="3938077534861382701">"همه برنامهها"</string>
<string name="filter_apps_disabled" msgid="5394488790555678117">"برنامههای غیرفعالشده"</string>
- <string name="filter_apps_third_party" msgid="3985794876813232322">"دانلودشده"</string>
+ <string name="filter_apps_third_party" msgid="3985794876813232322">"بارگیریشده"</string>
<string name="filter_apps_running" msgid="6852975378502426359">"در حال اجرا"</string>
<string name="filter_apps_onsdcard" product="nosdcard" msgid="3501701148760911442">"حافظهٔ USB"</string>
<string name="filter_apps_onsdcard" product="default" msgid="135989136394672864">"در کارت SD"</string>
diff --git a/tests/CarDeveloperOptions/res/values-fr/strings.xml b/tests/CarDeveloperOptions/res/values-fr/strings.xml
index 2a2e64f..57f384e 100644
--- a/tests/CarDeveloperOptions/res/values-fr/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-fr/strings.xml
@@ -1225,7 +1225,7 @@
<string name="night_display_summary_on" msgid="6580571388791426596">"Activé - <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="night_display_summary_on_auto_mode_never" msgid="5461580863060506687">"Ne jamais désactiver automatiquement"</string>
<string name="night_display_summary_on_auto_mode_custom" msgid="2200631112239399233">"Désactiver automatiquement à <xliff:g id="ID_1">%1$s</xliff:g>"</string>
- <string name="night_display_summary_on_auto_mode_twilight" msgid="8386769601369289561">"Désactiver automatiquement au lever du soleil"</string>
+ <string name="night_display_summary_on_auto_mode_twilight" msgid="8386769601369289561">"Se désactivera automatiquement au lever du soleil"</string>
<string name="night_display_activation_on_manual" msgid="8379477527072027346">"Activer maintenant"</string>
<string name="night_display_activation_off_manual" msgid="7776082151269794201">"Désactiver"</string>
<string name="night_display_activation_on_twilight" msgid="5610294051700287249">"Activer jusqu\'au lever du soleil"</string>
diff --git a/tests/CarDeveloperOptions/res/values-gu/strings.xml b/tests/CarDeveloperOptions/res/values-gu/strings.xml
index acf4b4b..fdd8b9a 100644
--- a/tests/CarDeveloperOptions/res/values-gu/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-gu/strings.xml
@@ -823,7 +823,7 @@
<string name="art_verifier_for_debuggable_summary" msgid="2204242476996701111">"ડીબગ કરવા યોગ્ય ઍપ માટે બાઇટકોડને ચકાસવા ARTને મંજૂરી આપો"</string>
<string name="nfc_quick_toggle_title" msgid="4990697912813795002">"NFC"</string>
<string name="nfc_quick_toggle_summary" product="tablet" msgid="983451155092850657">"જ્યારે ટેબ્લેટ બીજા ઉપકરણને ટચ કરે ત્યારે ડેટા વિનિમયની મંજૂરી આપો"</string>
- <string name="nfc_quick_toggle_summary" product="default" msgid="7141056939052895142">"જ્યારે ફોન બીજા ઉપકરણને ટચ કરે ત્યારે ડેટા વિનિમયની મંજૂરી આપો"</string>
+ <string name="nfc_quick_toggle_summary" product="default" msgid="7141056939052895142">"જ્યારે ફોન બીજા ડિવાઇસને ટચ કરે ત્યારે ડેટા વિનિમયની મંજૂરી આપો"</string>
<string name="nfc_disclaimer_title" msgid="4860231267351602970">"NFC ચાલુ કરો"</string>
<string name="nfc_disclaimer_content" msgid="3066113577854565782">"NFC આ ઉપકરણ અને અન્ય નજીકના ઉપકરણો અથવા લક્ષ્યો વચ્ચે ડેટાની આપ-લે કરે છે, જેમ કે ચુકવણી ટર્મિનલ્સ, અૅક્સેસ રીડર્સ અને ક્રિયા-પ્રતિક્રિયાત્મક જાહેરાતો અથવા ટૅગ્સ."</string>
<string name="nfc_secure_settings_title" msgid="5153751163174916581">"NFCને સુરક્ષિત કરો"</string>
@@ -1168,7 +1168,7 @@
<string name="accessibility_personal_account_title" msgid="7251761883688839354">"વ્યક્તિગત એકાઉન્ટ - <xliff:g id="MANAGED_BY">%s</xliff:g>"</string>
<string name="search_settings" msgid="5809250790214921377">"શોધો"</string>
<string name="display_settings" msgid="1045535829232307190">"ડિસ્પ્લે"</string>
- <string name="accelerometer_title" msgid="2427487734964971453">"સ્ક્રીનને આપમેળે ફેરવો"</string>
+ <string name="accelerometer_title" msgid="2427487734964971453">"ઑટો રોટેટ સ્ક્રીન"</string>
<string name="color_mode_title" msgid="8164858320869449142">"રંગો"</string>
<string name="color_mode_option_natural" msgid="1292837781836645320">"કુદરતી"</string>
<string name="color_mode_option_boosted" msgid="453557938434778933">"બુસ્ટ કરેલ"</string>
@@ -1219,7 +1219,7 @@
<string name="night_display_status_title" msgid="1727020934735770319">"સ્થિતિ"</string>
<string name="night_display_temperature_title" msgid="8375126629902616296">"તીવ્રતા"</string>
<string name="night_display_summary_off" msgid="8850539785332228069">"બંધ / <xliff:g id="ID_1">%1$s</xliff:g>"</string>
- <string name="night_display_summary_off_auto_mode_never" msgid="8618824386434992487">"આપમેળે ક્યારેય ચાલુ નહીં થાય"</string>
+ <string name="night_display_summary_off_auto_mode_never" msgid="8618824386434992487">"ક્યારેય ઑટોમૅટિક રીતે ચાલુ નહીં થાય"</string>
<string name="night_display_summary_off_auto_mode_custom" msgid="596847003171394411">"<xliff:g id="ID_1">%1$s</xliff:g> વાગ્યે આપમેળે ચાલુ થઈ જશે"</string>
<string name="night_display_summary_off_auto_mode_twilight" msgid="4071750976585359952">"સૂર્યાસ્ત સમયે આપમેળે ચાલુ થઈ જશે"</string>
<string name="night_display_summary_on" msgid="6580571388791426596">"ચાલુ / <xliff:g id="ID_1">%1$s</xliff:g>"</string>
@@ -2382,7 +2382,7 @@
<string name="usage_type_data_wifi_send" msgid="4457097885099163617">"વાઇ-ફાઇ પૅકેટ્સ મોકલ્યાં"</string>
<string name="usage_type_data_wifi_recv" msgid="6629526425662663926">"વાઇ-ફાઇ પૅકેટ્સ પ્રાપ્ત થયાં"</string>
<string name="usage_type_audio" msgid="510459400845396879">"ઑડિઓ"</string>
- <string name="usage_type_video" msgid="8161701367674306793">"વીડિઓ"</string>
+ <string name="usage_type_video" msgid="8161701367674306793">"વીડિયો"</string>
<string name="usage_type_camera" msgid="2276450385733155264">"કૅમેરો"</string>
<string name="usage_type_flashlight" msgid="954750302897154167">"ફ્લેશલાઇટ"</string>
<string name="usage_type_on_time" msgid="4622180623970638221">"સમય ચાલુ"</string>
@@ -2973,7 +2973,7 @@
<string name="restriction_nfc_enable_title" msgid="5146674482590550598">"NFC"</string>
<string name="restriction_nfc_enable_summary_config" msgid="405349698260328073">"જ્યારે આ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> બીજા NFC ઉપકરણને ટચ કરે ત્યારે ડેટા ફેરબદલીની મંજૂરી આપો"</string>
<string name="restriction_nfc_enable_summary" product="tablet" msgid="3292205836938064931">"જ્યારે ટેબ્લેટ બીજા ઉપકરણને ટચ કરે ત્યારે ડેટા વિનિમયની મંજૂરી આપો"</string>
- <string name="restriction_nfc_enable_summary" product="default" msgid="226439584043333608">"જ્યારે ફોન બીજા ઉપકરણને ટચ કરે ત્યારે ડેટા વિનિમયની મંજૂરી આપો"</string>
+ <string name="restriction_nfc_enable_summary" product="default" msgid="226439584043333608">"જ્યારે ફોન બીજા ડિવાઇસને ટચ કરે ત્યારે ડેટા વિનિમયની મંજૂરી આપો"</string>
<string name="restriction_location_enable_title" msgid="358506740636434856">"સ્થાન"</string>
<string name="restriction_location_enable_summary" msgid="4159500201124004463">"એપ્લિકેશન્સને તમારી સ્થાન માહિતીનો ઉપયોગ કરવા દો"</string>
<string name="wizard_back" msgid="223654213898117594">"પાછળ"</string>
diff --git a/tests/CarDeveloperOptions/res/values-hi/strings.xml b/tests/CarDeveloperOptions/res/values-hi/strings.xml
index 59684f8..d8f5db5 100644
--- a/tests/CarDeveloperOptions/res/values-hi/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-hi/strings.xml
@@ -128,7 +128,7 @@
<string name="bluetooth_notif_title" msgid="5090288898529286011">"दूसरे डिवाइस से जोड़ने का अनुरोध किया गया है"</string>
<string name="bluetooth_notif_message" msgid="6612367890895077938">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> से युग्मित करने के लिए टैप करें."</string>
<string name="bluetooth_show_received_files" msgid="5060846395852236652">"मिलने वाली फ़ाइलें"</string>
- <string name="bluetooth_show_files_received_via_bluetooth" msgid="1699095577431389560">"ब्लूटूथ के ज़रिए मिली फ़ाइलें"</string>
+ <string name="bluetooth_show_files_received_via_bluetooth" msgid="1699095577431389560">"ब्लूटूथ से मिली फ़ाइलें"</string>
<string name="device_picker" msgid="8345264486071697705">"ब्लूटूथ डिवाइस चुनें"</string>
<string name="bluetooth_ask_enablement" msgid="8716802066127746062">"<xliff:g id="APP_NAME">%1$s</xliff:g> ब्लूटूथ को चालू करना चाहता है"</string>
<string name="bluetooth_ask_disablement" msgid="7125319551097350783">"<xliff:g id="APP_NAME">%1$s</xliff:g> ब्लूटूथ को बंद करना चाहता है"</string>
@@ -823,7 +823,7 @@
<string name="art_verifier_for_debuggable_summary" msgid="2204242476996701111">"डीबग किए जा सकने वाले ऐप्लिकेशन के लिए, ART को बाइटकोड की पुष्टि करने की मंज़ूरी दें"</string>
<string name="nfc_quick_toggle_title" msgid="4990697912813795002">"आस-पास के डिवाइस से संपर्क (एनएफसी)"</string>
<string name="nfc_quick_toggle_summary" product="tablet" msgid="983451155092850657">"जब टैबलेट अन्य डिवाइस को स्पर्श करे तो डेटा ट्रांसफर करने दें"</string>
- <string name="nfc_quick_toggle_summary" product="default" msgid="7141056939052895142">"जब फ़ोन दूसरे डिवाइस को टच करे तो डेटा ट्रांसफर करने दें"</string>
+ <string name="nfc_quick_toggle_summary" product="default" msgid="7141056939052895142">"जब फ़ोन दूसरे डिवाइस को टच करे, तो डेटा ट्रांसफर करने दें"</string>
<string name="nfc_disclaimer_title" msgid="4860231267351602970">"NFC चालू करें"</string>
<string name="nfc_disclaimer_content" msgid="3066113577854565782">"NFC इस डिवाइस और आस-पास के अन्य डिवाइस या लक्ष्यों के बीच डेटा का लेन-देन करता है, जैसे कि भुगतान टर्मिनल, ऐक्सेस रीडर और सहभागी विज्ञापन या टैग."</string>
<string name="nfc_secure_settings_title" msgid="5153751163174916581">"NFC सुरक्षित करें"</string>
diff --git a/tests/CarDeveloperOptions/res/values-hy/strings.xml b/tests/CarDeveloperOptions/res/values-hy/strings.xml
index 68f6947..9f370ae 100644
--- a/tests/CarDeveloperOptions/res/values-hy/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-hy/strings.xml
@@ -56,7 +56,7 @@
<string name="radio_info_ims_reg_status" msgid="4771711884059371514">"IMS-ի գրանցում՝ <xliff:g id="STATUS">%1$s</xliff:g>\nVoice over LTE՝ <xliff:g id="AVAILABILITY_0">%2$s</xliff:g>\nVoice over WiFi՝ <xliff:g id="AVAILABILITY_1">%3$s</xliff:g>\nՏեսազանգ՝ <xliff:g id="AVAILABILITY_2">%4$s</xliff:g>\nUT միջերես՝ <xliff:g id="AVAILABILITY_3">%5$s</xliff:g>"</string>
<string name="radioInfo_service_in" msgid="1297020186765943857">"Շահագործման մեջ է"</string>
<string name="radioInfo_service_out" msgid="8460363463722476510">"Չի շահագործվում"</string>
- <string name="radioInfo_service_emergency" msgid="7674989004735662599">"Միայն արտակարգ իրավիճակների զանգեր"</string>
+ <string name="radioInfo_service_emergency" msgid="7674989004735662599">"Միայն շտապ կանչեր"</string>
<string name="radioInfo_service_off" msgid="1873939869994136791">"Ռադիոն անջատված է"</string>
<string name="radioInfo_roaming_in" msgid="7059350234710947417">"Ռոումինգ"</string>
<string name="radioInfo_roaming_not" msgid="7733269160603599835">"Ռոումինգում չէ"</string>
diff --git a/tests/CarDeveloperOptions/res/values-it/arrays.xml b/tests/CarDeveloperOptions/res/values-it/arrays.xml
index 11d6291..22a26a0 100644
--- a/tests/CarDeveloperOptions/res/values-it/arrays.xml
+++ b/tests/CarDeveloperOptions/res/values-it/arrays.xml
@@ -479,7 +479,7 @@
<item msgid="5079453644557603349">"Chiaro"</item>
</string-array>
<string-array name="autofill_logging_level_entries">
- <item msgid="6882729786516723474">"Off"</item>
+ <item msgid="6882729786516723474">"OFF"</item>
<item msgid="4072198137051566919">"Debug"</item>
<item msgid="2473005316958868509">"Dettagliata"</item>
</string-array>
diff --git a/tests/CarDeveloperOptions/res/values-it/strings.xml b/tests/CarDeveloperOptions/res/values-it/strings.xml
index 30b4ef7..d5855cc 100644
--- a/tests/CarDeveloperOptions/res/values-it/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-it/strings.xml
@@ -370,7 +370,7 @@
<string name="Accounts_settings_title" msgid="7901374987121953746">"Account"</string>
<string name="location_settings_title" msgid="2707201457572301030">"Geolocalizzazione"</string>
<string name="location_settings_master_switch_title" msgid="3108016866082816733">"Usa geolocalizzazione"</string>
- <string name="location_settings_summary_location_off" msgid="5563530256978372978">"Off"</string>
+ <string name="location_settings_summary_location_off" msgid="5563530256978372978">"OFF"</string>
<plurals name="location_settings_summary_location_on" formatted="false" msgid="7893342914540884818">
<item quantity="other">On - <xliff:g id="COUNT_1">%1$d</xliff:g> app possono accedere alla posizione</item>
<item quantity="one">On - <xliff:g id="COUNT_0">%1$d</xliff:g> app può accedere alla posizione</item>
@@ -830,7 +830,7 @@
<string name="nfc_secure_toggle_summary" product="default" msgid="7631183023440112192">"Consenti il pagamento NFC e l\'utilizzo di biglietti per il trasporto pubblico solo quando lo schermo è sbloccato"</string>
<string name="android_beam_settings_title" msgid="3083436415873738389">"Android Beam"</string>
<string name="android_beam_on_summary" msgid="8068287225180474199">"Pronto a trasmettere i contenuti dell\'app tramite NFC"</string>
- <string name="android_beam_off_summary" msgid="7365818039159364600">"Off"</string>
+ <string name="android_beam_off_summary" msgid="7365818039159364600">"OFF"</string>
<string name="nfc_disabled_summary" msgid="2181777971122724361">"Non disponibile perché la tecnologia NFC non è attiva"</string>
<string name="android_beam_label" msgid="5340299879556025708">"Android Beam"</string>
<string name="android_beam_explained" msgid="4501176353247859329">"Quando questa funzione è attiva, puoi trasmettere contenuti di app a un altro dispositivo che supporta la tecnologia NFC tenendo vicini i dispositivi. Ad esempio, puoi trasmettere pagine web, video di YouTube, contatti e altro ancora.\n\nÈ sufficiente avvicinare i dispositivi (generalmente mettendo a contatto le parti posteriori), quindi toccare lo schermo. L\'app stabilisce quali dati trasferire."</string>
@@ -1185,13 +1185,13 @@
<string name="brightness_summary" msgid="8687101964451818730">"Regola la luminosità dello schermo"</string>
<string name="auto_brightness_title" msgid="908511534369820426">"Luminosità adattiva"</string>
<string name="auto_brightness_summary_on" msgid="121488862610275737">"Attiva"</string>
- <string name="auto_brightness_summary_off" msgid="8569141123211510256">"Off"</string>
+ <string name="auto_brightness_summary_off" msgid="8569141123211510256">"OFF"</string>
<string name="auto_brightness_summary_very_low" msgid="7625647285740629347">"Luminosità preferita molto bassa"</string>
<string name="auto_brightness_summary_low" msgid="1829314781781906712">"Luminosità preferita bassa"</string>
<string name="auto_brightness_summary_default" msgid="4095465958108128891">"Luminosità preferita predefinita"</string>
<string name="auto_brightness_summary_high" msgid="8980041483278767898">"Luminosità preferita alta"</string>
<string name="auto_brightness_summary_very_high" msgid="8891768063638513875">"Luminosità preferita molto alta"</string>
- <string name="auto_brightness_off_title" msgid="6410562081118281572">"Off"</string>
+ <string name="auto_brightness_off_title" msgid="6410562081118281572">"OFF"</string>
<string name="auto_brightness_very_low_title" msgid="8716493755125824074">"Molto bassa"</string>
<string name="auto_brightness_low_title" msgid="5005479920075366970">"Bassa"</string>
<string name="auto_brightness_default_title" msgid="5446692891470912829">"Predefinita"</string>
@@ -1205,7 +1205,7 @@
<string name="display_white_balance_title" msgid="5747260735311935143">"Bilanciamento bianco display"</string>
<string name="adaptive_sleep_title" msgid="3237620948260957018">"Screen aware"</string>
<string name="adaptive_sleep_summary_on" msgid="6670369739228487082">"On/Lo schermo non si spegne se lo stai guardando"</string>
- <string name="adaptive_sleep_summary_off" msgid="2891586225954973431">"Off"</string>
+ <string name="adaptive_sleep_summary_off" msgid="2891586225954973431">"OFF"</string>
<string name="adaptive_sleep_description" msgid="812673735459170009">"Consente di impedire lo spegnimento dello schermo se lo stai guardando."</string>
<string name="adaptive_sleep_privacy" msgid="5706802215479902623">"Screen aware usa la fotocamera anteriore per controllare se qualcuno sta guardando lo schermo. Funziona sul dispositivo e le immagini non vengono mai memorizzate o inviate a Google."</string>
<string name="night_display_title" msgid="1305002424893349814">"Luminosità notturna"</string>
@@ -1218,7 +1218,7 @@
<string name="night_display_end_time_title" msgid="2760793157124245911">"Ora fine"</string>
<string name="night_display_status_title" msgid="1727020934735770319">"Stato"</string>
<string name="night_display_temperature_title" msgid="8375126629902616296">"Intensità"</string>
- <string name="night_display_summary_off" msgid="8850539785332228069">"Off/<xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="night_display_summary_off" msgid="8850539785332228069">"OFF/<xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="night_display_summary_off_auto_mode_never" msgid="8618824386434992487">"Non verrà mai attivata automaticamente"</string>
<string name="night_display_summary_off_auto_mode_custom" msgid="596847003171394411">"Verrà attivata automaticamente alle ore <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="night_display_summary_off_auto_mode_twilight" msgid="4071750976585359952">"Verrà attivata automaticamente al tramonto"</string>
@@ -1249,7 +1249,7 @@
<string name="screensaver_settings_summary_sleep" msgid="6097363596749362692">"Durante la ricarica"</string>
<string name="screensaver_settings_summary_dock" msgid="6297808146601570196">"Quando inserito nel dock"</string>
<string name="screensaver_settings_summary_never" msgid="3995259444981620707">"Mai"</string>
- <string name="screensaver_settings_summary_off" msgid="6119947316484763131">"Off"</string>
+ <string name="screensaver_settings_summary_off" msgid="6119947316484763131">"OFF"</string>
<string name="screensaver_settings_disabled_prompt" msgid="1897518064782596947">"Attiva il salvaschermo per controllare ciò che accade quando il telefono è inserito nel dock e/o in standby."</string>
<string name="screensaver_settings_when_to_dream" msgid="3763052013516826348">"Quando avviare"</string>
<string name="screensaver_settings_current" msgid="4017556173596361672">"Salvaschermo attuale"</string>
@@ -2108,7 +2108,7 @@
<item quantity="one"><xliff:g id="NUMBER_DEVICE_COUNT_0">%1$d</xliff:g> apparecchio acustico salvato</item>
</plurals>
<string name="accessibility_summary_state_enabled" msgid="7357731696603247963">"On"</string>
- <string name="accessibility_summary_state_disabled" msgid="9197369047683087620">"Off"</string>
+ <string name="accessibility_summary_state_disabled" msgid="9197369047683087620">"OFF"</string>
<string name="accessibility_summary_state_stopped" msgid="3170264683616172746">"Non funziona. Tocca per avere informazioni."</string>
<string name="accessibility_description_state_stopped" msgid="7666178628053039493">"Questo servizio non funziona correttamente."</string>
<string name="enable_quick_setting" msgid="1580451877998661255">"Mostra in Impostazioni rapide"</string>
@@ -2144,7 +2144,7 @@
<string name="accessibility_vibration_intensity_high" msgid="7850793704772123134">"Vibrazione alta"</string>
<string name="accessibility_menu_item_settings" msgid="6809813639403725032">"Impostazioni"</string>
<string name="accessibility_feature_state_on" msgid="8649102771420898911">"On"</string>
- <string name="accessibility_feature_state_off" msgid="7536392255214437050">"Off"</string>
+ <string name="accessibility_feature_state_off" msgid="7536392255214437050">"OFF"</string>
<string name="captioning_preview_title" msgid="6072706647310074854">"Anteprima"</string>
<string name="captioning_standard_options_title" msgid="4124898413348084226">"Opzioni standard"</string>
<string name="captioning_locale" msgid="4734464353806207943">"Lingua"</string>
@@ -2191,7 +2191,7 @@
<string name="accessibility_service_default_description" msgid="857921874644864502">"Nessuna descrizione fornita."</string>
<string name="settings_button" msgid="8557747862035866953">"Impostazioni"</string>
<string name="print_settings" msgid="7886184656544483072">"Stampa"</string>
- <string name="print_settings_summary_no_service" msgid="634173687975841526">"Off"</string>
+ <string name="print_settings_summary_no_service" msgid="634173687975841526">"OFF"</string>
<plurals name="print_settings_summary" formatted="false" msgid="7580293760281445137">
<item quantity="other"><xliff:g id="COUNT">%1$d</xliff:g> servizi di stampa attivi</item>
<item quantity="one">1 servizio di stampa attivo</item>
@@ -2206,7 +2206,7 @@
<string name="print_menu_item_settings" msgid="2654804159012579508">"Impostazioni"</string>
<string name="print_menu_item_add_printers" msgid="8198201275621756510">"Aggiungi stampanti"</string>
<string name="print_feature_state_on" msgid="1838010230650403367">"On"</string>
- <string name="print_feature_state_off" msgid="208580346723223688">"Off"</string>
+ <string name="print_feature_state_off" msgid="208580346723223688">"OFF"</string>
<string name="print_menu_item_add_service" msgid="6803000110578493782">"Aggiungi servizio"</string>
<string name="print_menu_item_add_printer" msgid="8529196211179574921">"Aggiungi stampante"</string>
<string name="print_menu_item_search" msgid="1165316329772287360">"Cerca"</string>
@@ -2334,7 +2334,7 @@
<string name="battery_auto_restriction_title" msgid="488905332794794076">"Usa Battery Manager"</string>
<string name="battery_auto_restriction_summary" msgid="1638072655581821837">"Rileva quando le app scaricano la batteria"</string>
<string name="battery_manager_on" msgid="5626982529932239656">"Opzione attiva/Rileva quando le app scaricano la batteria"</string>
- <string name="battery_manager_off" msgid="9114027524232450371">"Off"</string>
+ <string name="battery_manager_off" msgid="9114027524232450371">"OFF"</string>
<plurals name="battery_manager_app_restricted" formatted="false" msgid="6721813588142691216">
<item quantity="other">%1$d app con restrizioni</item>
<item quantity="one">%1$d app con restrizioni</item>
@@ -2546,7 +2546,7 @@
<string name="emergency_tone_summary" msgid="8035940153401622240">"Imposta il comportamento in caso di chiamata di emergenza"</string>
<string name="privacy_settings_title" msgid="3573891462732375772">"Backup"</string>
<string name="backup_summary_state_on" msgid="1725597360282574647">"On"</string>
- <string name="backup_summary_state_off" msgid="7138020503288730492">"Off"</string>
+ <string name="backup_summary_state_off" msgid="7138020503288730492">"OFF"</string>
<string name="backup_section_title" msgid="8177209731777904656">"Backup e ripristino"</string>
<string name="personal_data_section_title" msgid="9161854418510071558">"Dati personali"</string>
<string name="backup_data_title" msgid="4461508563849583624">"Backup dei miei dati"</string>
@@ -3239,8 +3239,8 @@
<string name="zen_interruption_level_priority" msgid="9178419297408319234">"Solo con priorità"</string>
<string name="zen_mode_and_condition" msgid="4123722186007123567">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="zen_mode_sound_summary_on_with_info" msgid="2539952366467518398">"On/<xliff:g id="ID_1">%1$s</xliff:g>"</string>
- <string name="zen_mode_sound_summary_off_with_info" msgid="3910718455243440265">"Off/<xliff:g id="ID_1">%1$s</xliff:g>"</string>
- <string name="zen_mode_sound_summary_off" msgid="2800265178411749309">"Off"</string>
+ <string name="zen_mode_sound_summary_off_with_info" msgid="3910718455243440265">"OFF/<xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="zen_mode_sound_summary_off" msgid="2800265178411749309">"OFF"</string>
<string name="zen_mode_sound_summary_on" msgid="6964666541479146310">"On"</string>
<string name="zen_mode_duration_summary_always_prompt" msgid="7642321938427056823">"Chiedi ogni volta (a meno che l\'opzione non sia stata attivata automaticamente)"</string>
<string name="zen_mode_duration_summary_forever" msgid="4563938129424903030">"Fino alla disattivazione (a meno che l\'opzione non sia stata attivata automaticamente)"</string>
@@ -3551,7 +3551,7 @@
<string name="device_feedback" msgid="4042352891448769818">"Invia feedback sul dispositivo"</string>
<string name="restr_pin_enter_admin_pin" msgid="8577847751493521230">"Inserisci PIN amministratore"</string>
<string name="switch_on_text" msgid="7100491749799298324">"On"</string>
- <string name="switch_off_text" msgid="3539551289454353555">"Off"</string>
+ <string name="switch_off_text" msgid="3539551289454353555">"OFF"</string>
<string name="screen_pinning_title" msgid="578020318289781102">"Blocco su schermo"</string>
<string name="screen_pinning_description" msgid="3814537379086412278">"Quando l\'impostazione è attiva, puoi usare il blocco su schermo per lasciare visibile la schermata corrente finché non la sblocchi.\n\nPer usare la funzione:\n\n1. Assicurati che il blocco su schermo sia attivo\n\n2. Apri Panoramica\n\n3. Tocca l\'icona dell\'app in alto nella schermata, quindi tocca Blocca"</string>
<string name="screen_pinning_unlock_pattern" msgid="1060334707088339444">"Richiedi sequenza di sblocco prima di sbloccare"</string>
@@ -3602,7 +3602,7 @@
<string name="notifications_label" msgid="2792398288062643318">"Notifiche"</string>
<string name="notifications_enabled" msgid="439339392141736137">"On"</string>
<string name="notifications_enabled_with_info" msgid="7706460489443809452">"<xliff:g id="NOTIFICATIONS_SENT">%1$s</xliff:g>/<xliff:g id="NOTIFICATIONS_CATEGORIES_OFF">%2$s</xliff:g>"</string>
- <string name="notifications_disabled" msgid="316658185757688983">"Off"</string>
+ <string name="notifications_disabled" msgid="316658185757688983">"OFF"</string>
<string name="notifications_partly_blocked" msgid="6330451240669068819">"<xliff:g id="COUNT_0">%1$d</xliff:g> di <xliff:g id="COUNT_1">%2$d</xliff:g> categorie disattivate"</string>
<string name="notifications_silenced" msgid="538923056987616372">"Senza audio"</string>
<string name="notifications_redacted" msgid="308836040236690014">"Nessun contenuto riservato nella schermata di blocco"</string>
@@ -3987,7 +3987,7 @@
<string name="unrestricted_data_saver" msgid="9139401849550738720">"Dati senza limitazioni"</string>
<string name="restrict_background_blacklisted" msgid="7158991683849067124">"I dati in background sono disattivati"</string>
<string name="data_saver_on" msgid="7281809065420480881">"On"</string>
- <string name="data_saver_off" msgid="7439439787358504018">"Off"</string>
+ <string name="data_saver_off" msgid="7439439787358504018">"OFF"</string>
<string name="data_saver_switch_title" msgid="8244008132112735207">"Usa Risparmio dati"</string>
<string name="unrestricted_app_title" msgid="4390661122069905122">"Uso dati senza limitazioni"</string>
<string name="unrestricted_app_summary" msgid="2829141815077800483">"Consenti accesso senza limitazioni con Risparmio dati attivo"</string>
@@ -4140,7 +4140,7 @@
<string name="fingerprint_swipe_for_notifications_summary" product="device" msgid="7950264130913070035">"Per controllare le notifiche, scorri verso il basso sul sensore di impronte digitali sul retro del dispositivo."</string>
<string name="fingerprint_swipe_for_notifications_suggestion_title" msgid="948946491233738823">"Visualizza rapidamente le notifiche"</string>
<string name="gesture_setting_on" msgid="7573680730101327866">"On"</string>
- <string name="gesture_setting_off" msgid="2540159841716890511">"Off"</string>
+ <string name="gesture_setting_off" msgid="2540159841716890511">"OFF"</string>
<string name="oem_unlock_enable_disabled_summary_bootloader_unlocked" msgid="7233244080078311793">"Il bootloader è già sbloccato"</string>
<string name="oem_unlock_enable_disabled_summary_connectivity" msgid="262986780389836168">"Devi prima connetterti a Internet"</string>
<string name="oem_unlock_enable_disabled_summary_connectivity_or_locked" msgid="3331374502670483142">"Connettiti a Internet o contatta il tuo operatore"</string>
@@ -4263,7 +4263,7 @@
<string name="show_operator_name_title" msgid="5056163028128447308">"Nome della rete"</string>
<string name="show_operator_name_summary" msgid="6352180285743777497">"Nome della Rete Display nella bara di stato"</string>
<string name="storage_manager_indicator" msgid="4255140732848476875">"Gestione memoria: <xliff:g id="STATUS">^1</xliff:g>"</string>
- <string name="storage_manager_indicator_off" msgid="6404056007102580777">"Off"</string>
+ <string name="storage_manager_indicator_off" msgid="6404056007102580777">"OFF"</string>
<string name="storage_manager_indicator_on" msgid="5295306384982062320">"Attiva"</string>
<string name="install_type_instant" msgid="6248487669862821874">"App istantanea"</string>
<string name="automatic_storage_manager_deactivation_warning" msgid="7867793739491286374">"Disattivare la gestione della memoria?"</string>
@@ -4408,7 +4408,7 @@
<string name="mobile_network_sim_name" msgid="8228870017368926761">"Nome SIM"</string>
<string name="mobile_network_sim_name_rename" msgid="4810736493612513152">"Rinomina"</string>
<string name="mobile_network_use_sim_on" msgid="1944823242539751387">"Utilizza SIM"</string>
- <string name="mobile_network_use_sim_off" msgid="2077820358051946635">"Off"</string>
+ <string name="mobile_network_use_sim_off" msgid="2077820358051946635">"OFF"</string>
<string name="mobile_network_esim_swap_confirm_title" msgid="6077154427380613615">"Passare a <xliff:g id="CARRIER">%1$s</xliff:g>?"</string>
<string name="mobile_network_esim_swap_confirm_body" msgid="1192274915146275063">"È possibile attivare una sola SIM scaricata alla volta.\n\nIl passaggio a <xliff:g id="CARRIER1">%1$s</xliff:g> non annullerà il servizio di <xliff:g id="CARRIER2">%2$s</xliff:g>."</string>
<string name="mobile_network_esim_swap_confirm_ok" msgid="4253442720111626242">"Passa a <xliff:g id="CARRIER">%1$s</xliff:g>"</string>
diff --git a/tests/CarDeveloperOptions/res/values-ka/strings.xml b/tests/CarDeveloperOptions/res/values-ka/strings.xml
index 1a0838f..a167d28 100644
--- a/tests/CarDeveloperOptions/res/values-ka/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-ka/strings.xml
@@ -1219,7 +1219,7 @@
<string name="night_display_status_title" msgid="1727020934735770319">"სტატუსი"</string>
<string name="night_display_temperature_title" msgid="8375126629902616296">"ინტენსივობა"</string>
<string name="night_display_summary_off" msgid="8850539785332228069">"გამორთულია / <xliff:g id="ID_1">%1$s</xliff:g>"</string>
- <string name="night_display_summary_off_auto_mode_never" msgid="8618824386434992487">"არასოდეს ჩაირთოს ავტომატურად"</string>
+ <string name="night_display_summary_off_auto_mode_never" msgid="8618824386434992487">"არასოდეს ჩაირთვება ავტომატურად"</string>
<string name="night_display_summary_off_auto_mode_custom" msgid="596847003171394411">"ავტომატურად ჩაირთვება <xliff:g id="ID_1">%1$s</xliff:g>-ზე"</string>
<string name="night_display_summary_off_auto_mode_twilight" msgid="4071750976585359952">"ავტომატურად ჩაირთვება მზის ჩასვლისას"</string>
<string name="night_display_summary_on" msgid="6580571388791426596">"ჩართულია / <xliff:g id="ID_1">%1$s</xliff:g>"</string>
diff --git a/tests/CarDeveloperOptions/res/values-kk/strings.xml b/tests/CarDeveloperOptions/res/values-kk/strings.xml
index 18bf1f1..2f33cb7 100644
--- a/tests/CarDeveloperOptions/res/values-kk/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-kk/strings.xml
@@ -1173,7 +1173,7 @@
<string name="color_mode_option_natural" msgid="1292837781836645320">"Табиғи"</string>
<string name="color_mode_option_boosted" msgid="453557938434778933">"Жарқын"</string>
<string name="color_mode_option_saturated" msgid="7758384943407859851">"Қаныққан"</string>
- <string name="color_mode_option_automatic" msgid="6572718611315165117">"Адаптивті"</string>
+ <string name="color_mode_option_automatic" msgid="6572718611315165117">"Бейімделгіш"</string>
<string name="color_mode_summary_natural" msgid="1247153893843263340">"Тек анық түстерді пайдаланыңыз"</string>
<string name="color_mode_summary_automatic" msgid="6066740785261330514">"Түстердің ашықтығы мен анықтығын реттеңіз"</string>
<string name="accelerometer_summary_on" product="tablet" msgid="5750977897791656412">"Планшетті айналдырғанда бағытын автоматты түрде ауыстыру"</string>
diff --git a/tests/CarDeveloperOptions/res/values-km/strings.xml b/tests/CarDeveloperOptions/res/values-km/strings.xml
index 01f5390..7027289 100644
--- a/tests/CarDeveloperOptions/res/values-km/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-km/strings.xml
@@ -128,7 +128,7 @@
<string name="bluetooth_notif_title" msgid="5090288898529286011">"សំណើផ្គូផ្គង"</string>
<string name="bluetooth_notif_message" msgid="6612367890895077938">"ប៉ះដើម្បីផ្គូផ្គងជាមួយ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ។"</string>
<string name="bluetooth_show_received_files" msgid="5060846395852236652">"ឯកសារដែលបានទទួល"</string>
- <string name="bluetooth_show_files_received_via_bluetooth" msgid="1699095577431389560">"បានទទួលឯកសារតាមរយៈប៊្លូធូស"</string>
+ <string name="bluetooth_show_files_received_via_bluetooth" msgid="1699095577431389560">"ឯកសារដែលបានទទួលតាមរយៈប៊្លូធូស"</string>
<string name="device_picker" msgid="8345264486071697705">"ជ្រើសឧបករណ៍ប៊្លូធូស"</string>
<string name="bluetooth_ask_enablement" msgid="8716802066127746062">"<xliff:g id="APP_NAME">%1$s</xliff:g> ចង់បើកប៊្លូធូស"</string>
<string name="bluetooth_ask_disablement" msgid="7125319551097350783">"<xliff:g id="APP_NAME">%1$s</xliff:g> ចង់បិទប៊្លូធូស"</string>
diff --git a/tests/CarDeveloperOptions/res/values-ky/strings.xml b/tests/CarDeveloperOptions/res/values-ky/strings.xml
index 5768b44..c775813d 100644
--- a/tests/CarDeveloperOptions/res/values-ky/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-ky/strings.xml
@@ -56,7 +56,7 @@
<string name="radio_info_ims_reg_status" msgid="4771711884059371514">"IMS каттоосу: <xliff:g id="STATUS">%1$s</xliff:g>\nLTE аркылуу аудио чалуу: <xliff:g id="AVAILABILITY_0">%2$s</xliff:g>\nWiFi аркылуу аудио чалуу: <xliff:g id="AVAILABILITY_1">%3$s</xliff:g>\nВидео чалуу: <xliff:g id="AVAILABILITY_2">%4$s</xliff:g>\nUT интерфейс: <xliff:g id="AVAILABILITY_3">%5$s</xliff:g>"</string>
<string name="radioInfo_service_in" msgid="1297020186765943857">"Тейлөө аймагында"</string>
<string name="radioInfo_service_out" msgid="8460363463722476510">"Тейлөө аймагынын сыртында"</string>
- <string name="radioInfo_service_emergency" msgid="7674989004735662599">"Өзгөчө кырдаалда гана чалганга болот"</string>
+ <string name="radioInfo_service_emergency" msgid="7674989004735662599">"Кырсыктаганда гана чалууга болот"</string>
<string name="radioInfo_service_off" msgid="1873939869994136791">"Радио өчүк"</string>
<string name="radioInfo_roaming_in" msgid="7059350234710947417">"Роуминг"</string>
<string name="radioInfo_roaming_not" msgid="7733269160603599835">"Роумингде эмес"</string>
@@ -4515,5 +4515,5 @@
<string name="automatic_system_heap_dump_summary" msgid="4962129546638974661">"Android тутуму өтө көп эстутумун колдоногондо, автоматтык түрдө анын үймө дампын тартып алуу"</string>
<string name="wifi_disconnect_button_text" msgid="787688024070426706">"Ажыратуу"</string>
<string name="wfc_disclaimer_emergency_limitation_title_text" msgid="26884532087670844">"Шашылыш чалуулар"</string>
- <string name="wfc_disclaimer_emergency_limitation_desc_text" msgid="8726152486964822599">"Операторуңуз Wi‑Fi аркылуу шашылыш чалууларды колдоого албайт.\nТүзмөгүңүз шашылыш чалууну аткаруу үчүн автоматтык түрдө мобилдик тармакка которулат.\nШашылык чалууларды мобилдик тармак иштеген аймактарда гана аткарууга болот."</string>
+ <string name="wfc_disclaimer_emergency_limitation_desc_text" msgid="8726152486964822599">"Операторуңузда кырсыктаганда Wi‑Fi аркылуу чалуу мүмкүнчүлүгү каралган эмес.\nКырсыктаганда жардамга келчү кызматтарга чалганыңызда, түзмөгүңүз автоматтык түрдө мобилдик тармакка которулат.\nМындай кырдаалдарда мобилдик тармак кармаган аймактарда гана чала аласыз."</string>
</resources>
diff --git a/tests/CarDeveloperOptions/res/values-mcc262-mnc02-ky/strings.xml b/tests/CarDeveloperOptions/res/values-mcc262-mnc02-ky/strings.xml
index 825e8ba..a7fc2a3 100644
--- a/tests/CarDeveloperOptions/res/values-mcc262-mnc02-ky/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-mcc262-mnc02-ky/strings.xml
@@ -16,5 +16,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="wifi_calling_off_explanation_2" msgid="4142074253083399456">\n\n" Өзгөчө кырдаалда Wi-Fi аркылуу чала албайсыз. Өзгөчө кырдаалда чалууга аракет кылганыңызда түзмөгүңүз автоматтык түрдө мобилдик тармакты пайдаланат. Өзгөчө кырдаалда мобилдик тармак кармаган аймактарда гана чала аласыз."</string>
+ <string name="wifi_calling_off_explanation_2" msgid="4142074253083399456">\n\n" Кырсыктаганда Wi-Fi аркылуу чала албайсыз. Мындай кырдаалдарда чалууга аракет кылганыңызда, түзмөгүңүз автоматтык түрдө мобилдик тармакты пайдаланып, мобилдик тармак кармаган аймактарда гана чала аласыз."</string>
</resources>
diff --git a/tests/CarDeveloperOptions/res/values-mk/strings.xml b/tests/CarDeveloperOptions/res/values-mk/strings.xml
index 1e8fa66..6b7df69 100644
--- a/tests/CarDeveloperOptions/res/values-mk/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-mk/strings.xml
@@ -3319,7 +3319,7 @@
<string name="notification_pulse_title" msgid="4861418327614907116">"Трепкај со сијаличката"</string>
<string name="lock_screen_notifications_title" msgid="6889072265118747835">"На заклучен екран"</string>
<string name="locked_work_profile_notification_title" msgid="8307025804986190658">"При заклучен работен профил"</string>
- <string name="lock_screen_notifications_summary_show" msgid="5788874994455257378">"Прикажи ја целата содржина од известувањето"</string>
+ <string name="lock_screen_notifications_summary_show" msgid="5788874994455257378">"Прикажи ја целата содржина од известувањата"</string>
<string name="lock_screen_notifications_summary_hide" msgid="3668806866535260143">"Сокриј чувствителни содржини"</string>
<string name="lock_screen_notifications_summary_disable" msgid="3259929507369817672">"Воопшто не прикажувај известувања"</string>
<string name="lock_screen_notifications_interstitial_message" msgid="4230189215124387818">"Кога уредот е заклучен, како сакате да се прикажуваат известувањата?"</string>
diff --git a/tests/CarDeveloperOptions/res/values-ml/strings.xml b/tests/CarDeveloperOptions/res/values-ml/strings.xml
index 73bbd68..1d98219 100644
--- a/tests/CarDeveloperOptions/res/values-ml/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-ml/strings.xml
@@ -128,7 +128,7 @@
<string name="bluetooth_notif_title" msgid="5090288898529286011">"ജോടിയാക്കൽ അഭ്യർത്ഥന"</string>
<string name="bluetooth_notif_message" msgid="6612367890895077938">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> എന്ന ഉപകരണവുമായി ജോടിയാക്കാൻ ടാപ്പുചെയ്യുക."</string>
<string name="bluetooth_show_received_files" msgid="5060846395852236652">"സ്വീകരിച്ച ഫയലുകള്"</string>
- <string name="bluetooth_show_files_received_via_bluetooth" msgid="1699095577431389560">"Bluetooth വഴി ഫയലുകൾ സ്വീകരിച്ചു"</string>
+ <string name="bluetooth_show_files_received_via_bluetooth" msgid="1699095577431389560">"Bluetooth വഴി സ്വീകരിച്ച ഫയലുകൾ"</string>
<string name="device_picker" msgid="8345264486071697705">"ബ്ലൂടൂത്തുപകരണം തിരഞ്ഞെടുക്കൂ"</string>
<string name="bluetooth_ask_enablement" msgid="8716802066127746062">"Bluetooth ഓണാക്കാൻ <xliff:g id="APP_NAME">%1$s</xliff:g> താൽപ്പര്യപ്പെടുന്നു"</string>
<string name="bluetooth_ask_disablement" msgid="7125319551097350783">"Bluetooth ഓഫാക്കാൻ <xliff:g id="APP_NAME">%1$s</xliff:g> താൽപ്പര്യപ്പെടുന്നു"</string>
@@ -1225,7 +1225,7 @@
<string name="night_display_summary_on" msgid="6580571388791426596">"ഓൺ / <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="night_display_summary_on_auto_mode_never" msgid="5461580863060506687">"ഒരിക്കലും സ്വമേധയാ ഓഫാകില്ല"</string>
<string name="night_display_summary_on_auto_mode_custom" msgid="2200631112239399233">"<xliff:g id="ID_1">%1$s</xliff:g>-ന് സ്വമേധയാ ഓഫാകും"</string>
- <string name="night_display_summary_on_auto_mode_twilight" msgid="8386769601369289561">"സൂര്യോദയ സമയത്ത് സ്വമേധയാ ഓഫാകും"</string>
+ <string name="night_display_summary_on_auto_mode_twilight" msgid="8386769601369289561">"സൂര്യോദയ സമയത്ത് സ്വയമേവ ഓഫാകും"</string>
<string name="night_display_activation_on_manual" msgid="8379477527072027346">"ഇപ്പോൾ ഓണാക്കുക"</string>
<string name="night_display_activation_off_manual" msgid="7776082151269794201">"ഇപ്പോൾ ഓഫാക്കുക"</string>
<string name="night_display_activation_on_twilight" msgid="5610294051700287249">"സൂര്യോദയം വരെ ഓണാക്കുക"</string>
diff --git a/tests/CarDeveloperOptions/res/values-mr/strings.xml b/tests/CarDeveloperOptions/res/values-mr/strings.xml
index f942c1f..de4c570 100644
--- a/tests/CarDeveloperOptions/res/values-mr/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-mr/strings.xml
@@ -1183,7 +1183,7 @@
<string name="brightness" msgid="7309120144111305275">"चकाकी स्तर"</string>
<string name="brightness_title" msgid="5660190946911149690">"चकाकी"</string>
<string name="brightness_summary" msgid="8687101964451818730">"स्क्रीनची चकाकी समायोजित करा"</string>
- <string name="auto_brightness_title" msgid="908511534369820426">"अॅडाप्टिव्ह ब्राइटनेस"</string>
+ <string name="auto_brightness_title" msgid="908511534369820426">"अॅडॅप्टिव्ह ब्राइटनेस"</string>
<string name="auto_brightness_summary_on" msgid="121488862610275737">"सुरू"</string>
<string name="auto_brightness_summary_off" msgid="8569141123211510256">"बंद"</string>
<string name="auto_brightness_summary_very_low" msgid="7625647285740629347">"प्राधान्य दिलेली उज्ज्वलता खूप कमी आहे"</string>
@@ -3034,7 +3034,7 @@
<string name="network_dashboard_summary_mobile" msgid="5560545061217580626">"मोबाइल"</string>
<string name="network_dashboard_summary_data_usage" msgid="4695629715072542102">"डेटा वापर"</string>
<string name="network_dashboard_summary_hotspot" msgid="3928610802321995214">"हॉटस्पॉट"</string>
- <string name="connected_devices_dashboard_title" msgid="7795222675849060444">"कनेक्ट केलेले डिव्हाइस"</string>
+ <string name="connected_devices_dashboard_title" msgid="7795222675849060444">"कनेक्ट केलेली डिव्हाइस"</string>
<string name="connected_devices_dashboard_summary" msgid="1072664369515033179">"ब्लूटूथ, ड्रायव्हिंग मोड, NFC"</string>
<string name="connected_devices_dashboard_no_nfc_summary" msgid="2610085597733526722">"ब्लूटूथ, ड्रायव्हिंग मोड"</string>
<string name="connected_devices_dashboard_no_driving_mode_summary" msgid="3524409078596318803">"ब्लूटूथ, NFC"</string>
diff --git a/tests/CarDeveloperOptions/res/values-pl/strings.xml b/tests/CarDeveloperOptions/res/values-pl/strings.xml
index 8c29317..cf10b3b 100644
--- a/tests/CarDeveloperOptions/res/values-pl/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-pl/strings.xml
@@ -3382,7 +3382,7 @@
<string name="other_sound_category_preference_title" msgid="2045757472469840859">"Inne dźwięki i wibracje"</string>
<string name="configure_notification_settings" msgid="291914315140851270">"Powiadomienia"</string>
<string name="recent_notifications" msgid="8125865995065032049">"Ostatnio wysłane"</string>
- <string name="recent_notifications_see_all_title" msgid="4089007770442871469">"Zobacz wszystkie z ostatnich siedmiu dni"</string>
+ <string name="recent_notifications_see_all_title" msgid="4089007770442871469">"Zobacz wszystkie z ostatnich 7 dni"</string>
<string name="advanced_section_header" msgid="984680389373090015">"Zaawansowane"</string>
<string name="profile_section_header" msgid="5471479005472037417">"Powiadomienia związane z pracą"</string>
<string name="asst_capability_prioritizer_title" msgid="3488284760645922160">"Automatyczne nadawanie priorytetów powiadomieniom"</string>
@@ -4066,11 +4066,11 @@
<string name="cell_data_template" msgid="5473177306229738078">"<xliff:g id="AMOUNT">^1</xliff:g> danych mobilnych"</string>
<string name="wifi_data_template" msgid="3146090439147042068">"Dane Wi-Fi: <xliff:g id="AMOUNT">^1</xliff:g>"</string>
<string name="ethernet_data_template" msgid="6414118030827090119">"Dane ethernet: <xliff:g id="AMOUNT">^1</xliff:g>"</string>
- <string name="billing_cycle" msgid="5740717948341713190">"Dane i limit"</string>
+ <string name="billing_cycle" msgid="5740717948341713190">"Ostrzeżenie dotyczące danych i limit"</string>
<string name="app_usage_cycle" msgid="213483325132959663">"Cykl użycia danych w aplikacjach"</string>
- <string name="cell_data_warning" msgid="8902740337286652689">"Próg ostrzegawczy: <xliff:g id="ID_1">^1</xliff:g>"</string>
+ <string name="cell_data_warning" msgid="8902740337286652689">"Ostrzeżenie dotyczące danych: <xliff:g id="ID_1">^1</xliff:g>"</string>
<string name="cell_data_limit" msgid="3175933829235314233">"Limit danych: <xliff:g id="ID_1">^1</xliff:g>"</string>
- <string name="cell_data_warning_and_limit" msgid="3846150001253927594">"Próg ostrzegawczy: <xliff:g id="ID_1">^1</xliff:g> / limit danych: <xliff:g id="ID_2">^2</xliff:g>"</string>
+ <string name="cell_data_warning_and_limit" msgid="3846150001253927594">"Ostrzeżenie dotyczące danych: <xliff:g id="ID_1">^1</xliff:g> / limit danych: <xliff:g id="ID_2">^2</xliff:g>"</string>
<string name="billing_cycle_fragment_summary" msgid="4926047002107855543">"<xliff:g id="ID_1">%1$s</xliff:g>. każdego miesiąca"</string>
<string name="network_restrictions" msgid="196294262243618198">"Ograniczenia sieci"</string>
<plurals name="network_restrictions_summary" formatted="false" msgid="1664494781594839837">
@@ -4081,8 +4081,8 @@
</plurals>
<string name="operator_warning" msgid="4676042739221117031">"Operator komórkowy może obliczać ilość przesłanych danych inaczej niż urządzenie"</string>
<string name="data_used_template" msgid="761605393453849477">"Wykorzystano <xliff:g id="ID_1">%1$s</xliff:g>"</string>
- <string name="set_data_warning" msgid="8115980184415563941">"Ustaw próg ostrzegawczy"</string>
- <string name="data_warning" msgid="2699207195535036240">"Próg ostrzegawczy"</string>
+ <string name="set_data_warning" msgid="8115980184415563941">"Ustaw ostrzeżenie dotyczące danych"</string>
+ <string name="data_warning" msgid="2699207195535036240">"Ostrzeżenie dotyczące danych"</string>
<string name="data_warning_footnote" msgid="965724845580257305">"Ostrzeżenie dotyczące użycia danych i limit danych są oparte na pomiarach wykonywanych przez Twoje urządzenie. Dane operatora mogą być inne."</string>
<string name="set_data_limit" msgid="5043770023229990674">"Ustaw limit transmisji danych"</string>
<string name="data_limit" msgid="5793521160051596228">"Limit danych"</string>
diff --git a/tests/CarDeveloperOptions/res/values-sq/strings.xml b/tests/CarDeveloperOptions/res/values-sq/strings.xml
index d7f31e1..d5b1709 100644
--- a/tests/CarDeveloperOptions/res/values-sq/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-sq/strings.xml
@@ -2664,7 +2664,7 @@
<string name="data_usage_menu_show_ethernet" msgid="2130574690318410238">"Shfaq përdorimin e Eternetit"</string>
<string name="data_usage_menu_hide_ethernet" msgid="1191233197312414533">"Fshih përdorimin e eternetit"</string>
<string name="data_usage_menu_metered" msgid="3087525150259956831">"Kufizimet e rrjetit"</string>
- <string name="data_usage_menu_auto_sync" msgid="3350154877737572146">"Të dhënat e autosinkronizimit"</string>
+ <string name="data_usage_menu_auto_sync" msgid="3350154877737572146">"Të dhënat e sinkronizimit automatik"</string>
<string name="data_usage_menu_sim_cards" msgid="8508154611676507088">"Kartat SIM"</string>
<string name="data_usage_cellular_data_summary" msgid="9162777397135709280">"U ndërpre në kufi"</string>
<string name="account_settings_menu_auto_sync" msgid="2673669556006027506">"Auto-sinkronizo të dhënat"</string>
diff --git a/tests/CarDeveloperOptions/res/values-uk/strings.xml b/tests/CarDeveloperOptions/res/values-uk/strings.xml
index 9940077..ca11eb5 100644
--- a/tests/CarDeveloperOptions/res/values-uk/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-uk/strings.xml
@@ -2579,7 +2579,7 @@
<string name="voice_interactor_preference_summary" msgid="7321365727286121067">"Підтримка команд швидкого запуску та взаємодії"</string>
<string name="voice_recognizer_preference_summary" msgid="3681161319745912594">"Просте перетворення мовлення на текст"</string>
<string name="voice_interaction_security_warning" msgid="4986261746316889768">"Ця служба голосового вводу зможе постійно відстежувати голос і контролювати додатки, у яких увімкнено голосовий ввід, від вашого імені. Вона походить із додатка <xliff:g id="VOICE_INPUT_SERVICE_APP_NAME">%s</xliff:g>. Увімкнути цю службу?"</string>
- <string name="tts_engine_preference_title" msgid="1183116842356275061">"Бажана система"</string>
+ <string name="tts_engine_preference_title" msgid="1183116842356275061">"Система за умовчанням"</string>
<string name="tts_engine_settings_title" msgid="4079757915136562358">"Налаштування системи"</string>
<string name="tts_sliders_title" msgid="1927481069989092278">"Темп і тон мовлення"</string>
<string name="tts_engine_section_title" msgid="7796486438271227076">"Система"</string>
diff --git a/tests/CarDeveloperOptions/res/values-zh-rHK/strings.xml b/tests/CarDeveloperOptions/res/values-zh-rHK/strings.xml
index 64cf41a..2c94d17 100644
--- a/tests/CarDeveloperOptions/res/values-zh-rHK/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-zh-rHK/strings.xml
@@ -1208,7 +1208,7 @@
<string name="adaptive_sleep_summary_off" msgid="2891586225954973431">"關閉"</string>
<string name="adaptive_sleep_description" msgid="812673735459170009">"防止在您望向螢幕時螢幕關閉。"</string>
<string name="adaptive_sleep_privacy" msgid="5706802215479902623">"螢幕意識利用前置鏡頭偵測使用者是否正望向螢幕。此功能只在裝置上使用,同時圖片不會被儲存或傳送至 Google。"</string>
- <string name="night_display_title" msgid="1305002424893349814">"夜燈模式"</string>
+ <string name="night_display_title" msgid="1305002424893349814">"夜間模式"</string>
<string name="night_display_text" msgid="5330502493684652527">"「夜燈模式」會將螢幕調校至橙黃色,在光線昏暗的環境下看螢幕或閱讀時就更舒適,並讓您更易入睡。"</string>
<string name="night_display_auto_mode_title" msgid="8493573087102481588">"設定時間"</string>
<string name="night_display_auto_mode_never" msgid="2897444637217807088">"無"</string>
@@ -2029,7 +2029,7 @@
<string name="allow_bind_app_widget_activity_always_allow_bind" msgid="1185486443615658430">"永遠允許「<xliff:g id="WIDGET_HOST_NAME">%1$s</xliff:g>」建立小工具並存取其資料"</string>
<string name="usage_stats_label" msgid="3128999956478977035">"用量統計資料"</string>
<string name="testing_usage_stats" msgid="704965692323956976">"用量統計資料"</string>
- <string name="display_order_text" msgid="2973620313510295873">"排序依據:"</string>
+ <string name="display_order_text" msgid="2973620313510295873">"排序方式:"</string>
<string name="app_name_label" msgid="2258469951312794816">"應用程式"</string>
<string name="last_time_used_label" msgid="1119322667349666930">"上次使用時間"</string>
<string name="usage_time_label" msgid="5615725415876461039">"使用時間"</string>
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/dashboard/DashboardFeatureProviderImpl.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/dashboard/DashboardFeatureProviderImpl.java
index 87f52e3..de184cf 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/dashboard/DashboardFeatureProviderImpl.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/dashboard/DashboardFeatureProviderImpl.java
@@ -243,16 +243,15 @@
ProfileSelectDialog.updateUserHandlesIfNeeded(mContext, tile);
if (tile.userHandle == null || tile.isPrimaryProfileOnly()) {
- mMetricsFeatureProvider.logDashboardStartIntent(mContext, intent, sourceMetricCategory);
+ mMetricsFeatureProvider.logStartedIntent(intent, sourceMetricCategory);
activity.startActivityForResult(intent, 0);
} else if (tile.userHandle.size() == 1) {
- mMetricsFeatureProvider.logDashboardStartIntent(mContext, intent, sourceMetricCategory);
+ mMetricsFeatureProvider.logStartedIntent(intent, sourceMetricCategory);
activity.startActivityForResultAsUser(intent, 0, tile.userHandle.get(0));
} else {
final UserHandle userHandle = intent.getParcelableExtra(EXTRA_USER);
if (userHandle != null && tile.userHandle.contains(userHandle)) {
- mMetricsFeatureProvider.logDashboardStartIntent(
- mContext, intent, sourceMetricCategory);
+ mMetricsFeatureProvider.logStartedIntent(intent, sourceMetricCategory);
activity.startActivityForResultAsUser(intent, 0, userHandle);
} else {
ProfileSelectDialog.show(activity.getSupportFragmentManager(), tile);
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/dashboard/DashboardFragment.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/dashboard/DashboardFragment.java
index e021e6b..a08ad0f 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/dashboard/DashboardFragment.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/dashboard/DashboardFragment.java
@@ -197,8 +197,7 @@
Collection<List<AbstractPreferenceController>> controllers =
mPreferenceControllers.values();
// If preference contains intent, log it before handling.
- mMetricsFeatureProvider.logDashboardStartIntent(
- getContext(), preference.getIntent(), getMetricsCategory());
+ mMetricsFeatureProvider.logStartedIntent(preference.getIntent(), getMetricsCategory());
// Give all controllers a chance to handle click.
for (List<AbstractPreferenceController> controllerList : controllers) {
for (AbstractPreferenceController controller : controllerList) {
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/WifiConfigController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/WifiConfigController.java
index 02b5278..61abd4c 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/WifiConfigController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/WifiConfigController.java
@@ -329,17 +329,10 @@
showProxyFields();
final CheckBox advancedTogglebox =
(CheckBox) mView.findViewById(R.id.wifi_advanced_togglebox);
- mView.findViewById(R.id.wifi_advanced_toggle).setVisibility(
- mAccessPoint.isCarrierAp() ? View.GONE : View.VISIBLE);
advancedTogglebox.setOnCheckedChangeListener(this);
advancedTogglebox.setChecked(showAdvancedFields);
mView.findViewById(R.id.wifi_advanced_fields)
.setVisibility(showAdvancedFields ? View.VISIBLE : View.GONE);
- if (mAccessPoint.isCarrierAp()) {
- addRow(group, R.string.wifi_carrier_connect,
- String.format(mContext.getString(R.string.wifi_carrier_content),
- mAccessPoint.getCarrierName()));
- }
}
if (mMode == WifiConfigUiBase.MODE_MODIFY) {
@@ -976,10 +969,6 @@
mEapIdentityView = (TextView) mView.findViewById(R.id.identity);
mEapAnonymousView = (TextView) mView.findViewById(R.id.anonymous);
- if (mAccessPoint != null && mAccessPoint.isCarrierAp()) {
- mEapMethodSpinner.setSelection(mAccessPoint.getCarrierApEapType());
- }
-
loadCertificates(
mEapCaCertSpinner,
Credentials.CA_CERTIFICATE,
@@ -1147,9 +1136,6 @@
setUserCertInvisible();
setPasswordInvisible();
setIdentityInvisible();
- if (mAccessPoint != null && mAccessPoint.isCarrierAp()) {
- setEapMethodInvisible();
- }
break;
}
diff --git a/tests/EmbeddedKitchenSinkApp/AndroidManifest.xml b/tests/EmbeddedKitchenSinkApp/AndroidManifest.xml
index a30b9b4..b069ef4 100644
--- a/tests/EmbeddedKitchenSinkApp/AndroidManifest.xml
+++ b/tests/EmbeddedKitchenSinkApp/AndroidManifest.xml
@@ -146,13 +146,6 @@
<activity android:name=".activityview.ActivityViewTestFragment"/>
- <!-- temporary solution until b/68882625 is fixed. -->
- <receiver android:name=".touchsound.DisableTouchSoundOnBoot" android:exported="true">
- <intent-filter>
- <action android:name="android.intent.action.BOOT_COMPLETED"/>
- </intent-filter>
- </receiver>
-
<service android:name=".vendorservice.LogLifecycleService"
android:exported="false" android:directBootAware="true">
</service>
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/touchsound/DisableTouchSoundOnBoot.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/touchsound/DisableTouchSoundOnBoot.java
deleted file mode 100644
index 2c81bda..0000000
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/touchsound/DisableTouchSoundOnBoot.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-package com.google.android.car.kitchensink.touchsound;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.provider.Settings;
-import android.util.Log;
-
-/**
- * Temp solution until b/68882625 is fixed
- */
-public class DisableTouchSoundOnBoot extends BroadcastReceiver {
-
- private static final String KEY_TOUCH_SOUNDS = "sound_effects_enabled";
-
- @Override
- public void onReceive(Context context, Intent intent) {
- Log.w("DisableTouchSoundOnBoot", "disabling touch sound");
- Settings.System.putInt(context.getContentResolver(), KEY_TOUCH_SOUNDS, 0);
- }
-}
diff --git a/tests/carservice_test/src/com/android/car/CarPropertyManagerTest.java b/tests/carservice_test/src/com/android/car/CarPropertyManagerTest.java
index eef9638..56540dd 100644
--- a/tests/carservice_test/src/com/android/car/CarPropertyManagerTest.java
+++ b/tests/carservice_test/src/com/android/car/CarPropertyManagerTest.java
@@ -17,10 +17,12 @@
package com.android.car;
import android.car.Car;
+import android.car.VehicleAreaType;
import android.car.hardware.CarPropertyConfig;
import android.car.hardware.CarPropertyValue;
import android.car.hardware.property.CarPropertyManager;
import android.hardware.automotive.vehicle.V2_0.VehicleArea;
+import android.hardware.automotive.vehicle.V2_0.VehicleAreaSeat;
import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
import android.hardware.automotive.vehicle.V2_0.VehiclePropertyGroup;
import android.hardware.automotive.vehicle.V2_0.VehiclePropertyType;
@@ -67,9 +69,17 @@
private static final Object[] EXPECTED_VALUE_2 = {"android", true, 3, 1.1f, 2f};
private static final int CUSTOM_GLOBAL_MIXED_PROP_ID_1 =
- 0x1101 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.MIXED | VehicleArea.GLOBAL;
+ 0x1101 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.MIXED | VehicleArea.SEAT;
private static final int CUSTOM_GLOBAL_MIXED_PROP_ID_2 =
0x1102 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.MIXED | VehicleArea.GLOBAL;
+ // Use FAKE_PROPERTY_ID to test api return null or throw exception.
+ private static final int FAKE_PROPERTY_ID = 0x111;
+
+ private static final int DRIVER_SIDE_AREA_ID = VehicleAreaSeat.ROW_1_LEFT
+ | VehicleAreaSeat.ROW_2_LEFT;
+ private static final int PASSENGER_SIDE_AREA_ID = VehicleAreaSeat.ROW_1_RIGHT
+ | VehicleAreaSeat.ROW_2_CENTER
+ | VehicleAreaSeat.ROW_2_RIGHT;
private CarPropertyManager mManager;
@@ -116,14 +126,49 @@
Assert.assertArrayEquals(EXPECTED_VALUE_2, result.getValue());
}
+ @Test
+ public void testGetPropertyConfig() {
+ CarPropertyConfig config = mManager.getCarPropertyConfig(CUSTOM_GLOBAL_MIXED_PROP_ID_1);
+ Assert.assertEquals(CUSTOM_GLOBAL_MIXED_PROP_ID_1, config.getPropertyId());
+ // return null if can not find the propertyConfig for the property.
+ Assert.assertNull(mManager.getCarPropertyConfig(FAKE_PROPERTY_ID));
+ }
+
+ @Test
+ public void testGetAreaId() {
+ int result = mManager.getAreaId(CUSTOM_GLOBAL_MIXED_PROP_ID_1, VehicleAreaSeat.ROW_1_LEFT);
+ Assert.assertEquals(DRIVER_SIDE_AREA_ID, result);
+
+ //test for the GLOBAL property
+ int globalAreaId =
+ mManager.getAreaId(CUSTOM_GLOBAL_MIXED_PROP_ID_2, VehicleAreaSeat.ROW_1_LEFT);
+ Assert.assertEquals(VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, globalAreaId);
+
+ //test exception
+ try {
+ int areaId = mManager.getAreaId(CUSTOM_GLOBAL_MIXED_PROP_ID_1,
+ VehicleAreaSeat.ROW_3_CENTER);
+ Assert.fail("Unexpected areaId: " + areaId);
+ } catch (IllegalArgumentException e) {
+ Log.v(TAG, e.getMessage());
+ }
+
+ try {
+ // test exception
+ int areaIdForFakeProp = mManager.getAreaId(FAKE_PROPERTY_ID,
+ VehicleAreaSeat.ROW_1_LEFT);
+ Assert.fail("Unexpected areaId for fake property: " + areaIdForFakeProp);
+ } catch (IllegalArgumentException e) {
+ Log.v(TAG, e.getMessage());
+ }
+ }
@Override
protected synchronized void configureMockedHal() {
PropertyHandler handler = new PropertyHandler();
- addProperty(CUSTOM_GLOBAL_MIXED_PROP_ID_1, handler).setConfigArray(CONFIG_ARRAY_1);
+ addProperty(CUSTOM_GLOBAL_MIXED_PROP_ID_1, handler).setConfigArray(CONFIG_ARRAY_1)
+ .addAreaConfig(DRIVER_SIDE_AREA_ID).addAreaConfig(PASSENGER_SIDE_AREA_ID);
addProperty(CUSTOM_GLOBAL_MIXED_PROP_ID_2, handler).setConfigArray(CONFIG_ARRAY_2);
-
-
}
private class PropertyHandler implements VehicleHalPropertyHandler {
diff --git a/tests/carservice_unit_test/src/com/android/car/CarPowerManagementServiceTest.java b/tests/carservice_unit_test/src/com/android/car/CarPowerManagementServiceTest.java
index c0369a2..6c06b56 100644
--- a/tests/carservice_unit_test/src/com/android/car/CarPowerManagementServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/CarPowerManagementServiceTest.java
@@ -18,22 +18,33 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
-import static org.mockito.Mockito.mock;
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.fail;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.car.hardware.power.CarPowerManager.CarPowerStateListener;
import android.car.hardware.power.ICarPowerStateListener;
import android.car.userlib.CarUserManagerHelper;
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.content.res.Resources;
import android.hardware.automotive.vehicle.V2_0.VehicleApPowerStateReq;
import android.hardware.automotive.vehicle.V2_0.VehicleApPowerStateShutdownParam;
import android.os.RemoteException;
-import android.test.AndroidTestCase;
+import android.os.UserManager;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.Log;
+import androidx.test.platform.app.InstrumentationRegistry;
+
import com.android.car.hal.PowerHalService;
import com.android.car.hal.PowerHalService.PowerState;
import com.android.car.systeminterface.DisplayInterface;
@@ -43,55 +54,95 @@
import com.android.car.systeminterface.WakeLockInterface;
import com.android.car.test.utils.TemporaryDirectory;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+import org.junit.rules.TestWatcher;
+import org.junit.runner.Description;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
import org.mockito.MockitoSession;
+import org.mockito.junit.MockitoJUnitRunner;
import org.mockito.quality.Strictness;
import java.io.File;
import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import java.lang.reflect.Method;
import java.time.Duration;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
@SmallTest
-public class CarPowerManagementServiceTest extends AndroidTestCase {
+@RunWith(MockitoJUnitRunner.class)
+public class CarPowerManagementServiceTest {
private static final String TAG = CarPowerManagementServiceTest.class.getSimpleName();
private static final long WAIT_TIMEOUT_MS = 2000;
private static final long WAIT_TIMEOUT_LONG_MS = 5000;
+ private static final int NO_USER_INFO_FLAGS = 0;
private final MockDisplayInterface mDisplayInterface = new MockDisplayInterface();
private final MockSystemStateInterface mSystemStateInterface = new MockSystemStateInterface();
private final MockWakeLockInterface mWakeLockInterface = new MockWakeLockInterface();
private final MockIOInterface mIOInterface = new MockIOInterface();
private final PowerSignalListener mPowerSignalListener = new PowerSignalListener();
+ private final Context mContext = InstrumentationRegistry.getInstrumentation().getContext();
private MockitoSession mSession;
- private CarUserManagerHelper mCarUserManagerHelper;
+
private MockedPowerHalService mPowerHal;
private SystemInterface mSystemInterface;
private CarPowerManagementService mService;
private CompletableFuture<Void> mFuture;
- @Override
- protected void setUp() throws Exception {
- super.setUp();
+ @Mock
+ private CarUserManagerHelper mCarUserManagerHelper;
+ @Mock
+ private UserManager mUserManager;
+ @Mock
+ private Resources mResources;
+
+ // Wakeup time for the test; it's automatically set based on @WakeupTime annotation
+ private int mWakeupTime;
+
+ @Rule
+ public final TestRule setWakeupTimeRule = new TestWatcher() {
+ protected void starting(Description description) {
+ final String testName = description.getMethodName();
+ try {
+ Method testMethod = CarPowerManagementServiceTest.class.getMethod(testName);
+ WakeupTime wakeupAnnotation = testMethod.getAnnotation(WakeupTime.class);
+ if (wakeupAnnotation != null) {
+ mWakeupTime = wakeupAnnotation.value();
+ Log.d(TAG, "Using annotated wakeup time: " + mWakeupTime);
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Could not infer wakeupTime for " + testName, e);
+ }
+ }
+ };
+
+ @Before
+ public void setUp() throws Exception {
mSession = mockitoSession()
.strictness(Strictness.LENIENT)
.spyStatic(ActivityManager.class)
.startMocking();
mPowerHal = new MockedPowerHalService(true /*isPowerStateSupported*/,
true /*isDeepSleepAllowed*/, true /*isTimedWakeupAllowed*/);
- mSystemInterface = SystemInterface.Builder.defaultSystemInterface(getContext())
+ mSystemInterface = SystemInterface.Builder.defaultSystemInterface(mContext)
.withDisplayInterface(mDisplayInterface)
.withSystemStateInterface(mSystemStateInterface)
.withWakeLockInterface(mWakeLockInterface)
.withIOInterface(mIOInterface).build();
- mCarUserManagerHelper = mock(CarUserManagerHelper.class);
}
- @Override
- protected void tearDown() throws Exception {
- super.tearDown();
+ @After
+ public void tearDown() throws Exception {
if (mService != null) {
mService.release();
}
@@ -102,41 +153,54 @@
/**
* Helper method to create mService and initialize a test case
*/
- private void initTest(int wakeupTime) throws Exception {
- mService = new CarPowerManagementService(getContext(), mPowerHal, mSystemInterface,
- mCarUserManagerHelper);
+ private void initTest() throws Exception {
+ when(mResources.getInteger(R.integer.maxGarageModeRunningDurationInSecs))
+ .thenReturn(900);
+ when(mResources.getBoolean(R.bool.config_disableUserSwitchDuringResume))
+ .thenReturn(false);
+
+ Log.i(TAG, "initTest(): overridden overlay properties: "
+ + "config_disableUserSwitchDuringResume="
+ + mResources.getBoolean(R.bool.config_disableUserSwitchDuringResume)
+ + ", maxGarageModeRunningDurationInSecs="
+ + mResources.getInteger(R.integer.maxGarageModeRunningDurationInSecs));
+ mService = new CarPowerManagementService(mContext, mResources, mPowerHal,
+ mSystemInterface, mCarUserManagerHelper);
mService.init();
CarPowerManagementService.setShutdownPrepareTimeout(0);
mPowerHal.setSignalListener(mPowerSignalListener);
- if (wakeupTime > 0) {
+ if (mWakeupTime > 0) {
registerListenerToService();
- mService.scheduleNextWakeupTime(wakeupTime);
+ mService.scheduleNextWakeupTime(mWakeupTime);
}
assertStateReceived(MockedPowerHalService.SET_WAIT_FOR_VHAL, 0);
}
+ @Test
public void testBootComplete() throws Exception {
- initTest(0);
+ initTest();
}
+ @Test
public void testDisplayOn() throws Exception {
// start with display off
mSystemInterface.setDisplayState(false);
mDisplayInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS);
- initTest(0);
+ initTest();
// Transition to ON state
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, 0));
// display should be turned on as it started with off state.
- assertTrue(mDisplayInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS));
+ assertThat(mDisplayInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS)).isTrue();
}
+ @Test
public void testShutdown() throws Exception {
- initTest(0);
+ initTest();
// Transition to ON state
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, 0));
- assertTrue(mDisplayInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS));
+ assertThat(mDisplayInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS)).isTrue();
mPowerHal.setCurrentPowerState(
new PowerState(
@@ -145,17 +209,18 @@
// Since modules have to manually schedule next wakeup, we should not schedule next wakeup
// To test module behavior, we need to actually implement mock listener module.
assertStateReceived(PowerHalService.SET_SHUTDOWN_START, 0);
- assertFalse(mDisplayInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS));
+ assertThat(mDisplayInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS)).isFalse();
mPowerSignalListener.waitForShutdown(WAIT_TIMEOUT_MS);
mSystemStateInterface.waitForShutdown(WAIT_TIMEOUT_MS);
}
+ @Test
public void testSleepImmediately() throws Exception {
- initTest(0);
+ initTest();
// Transition to ON state
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, 0));
- assertTrue(mDisplayInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS));
+ assertThat(mDisplayInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS)).isTrue();
mPowerHal.setCurrentPowerState(
new PowerState(
@@ -164,30 +229,32 @@
// Since modules have to manually schedule next wakeup, we should not schedule next wakeup
// To test module behavior, we need to actually implement mock listener module.
assertStateReceived(PowerHalService.SET_SHUTDOWN_START, 0);
- assertFalse(mDisplayInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS));
+ assertThat(mDisplayInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS)).isFalse();
mPowerSignalListener.waitForShutdown(WAIT_TIMEOUT_MS);
mSystemStateInterface.waitForShutdown(WAIT_TIMEOUT_MS);
}
+ @Test
+ @WakeupTime(100)
public void testShutdownWithProcessing() throws Exception {
- final int wakeupTime = 100;
- initTest(wakeupTime);
+ initTest();
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.SHUTDOWN_PREPARE, 0));
assertStateReceivedForShutdownOrSleepWithPostpone(
- PowerHalService.SET_SHUTDOWN_START, WAIT_TIMEOUT_LONG_MS, wakeupTime);
+ PowerHalService.SET_SHUTDOWN_START, WAIT_TIMEOUT_LONG_MS, mWakeupTime);
mPowerSignalListener.waitForShutdown(WAIT_TIMEOUT_MS);
// Send the finished signal
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.FINISHED, 0));
mSystemStateInterface.waitForShutdown(WAIT_TIMEOUT_MS);
}
+ @Test
+ @WakeupTime(100)
public void testSleepEntryAndWakeup() throws Exception {
- final int wakeupTime = 100;
- initTest(wakeupTime);
+ initTest();
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.SHUTDOWN_PREPARE,
VehicleApPowerStateShutdownParam.CAN_SLEEP));
assertStateReceivedForShutdownOrSleepWithPostpone(
- PowerHalService.SET_DEEP_SLEEP_ENTRY, WAIT_TIMEOUT_LONG_MS, wakeupTime);
+ PowerHalService.SET_DEEP_SLEEP_ENTRY, WAIT_TIMEOUT_LONG_MS, mWakeupTime);
mPowerSignalListener.waitForSleepEntry(WAIT_TIMEOUT_MS);
// Send the finished signal from HAL to CPMS
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.FINISHED, 0));
@@ -196,51 +263,57 @@
mPowerSignalListener.waitForSleepExit(WAIT_TIMEOUT_MS);
}
+ @Test
public void testSleepEntryAndWakeUpForProcessing() throws Exception {
- final int wakeupTime = 100;
- initTest(wakeupTime);
+ initTest();
+ setUserInfo(10, NO_USER_INFO_FLAGS);
+ setUserInfo(11, NO_USER_INFO_FLAGS);
+ setCurrentUser(10);
+ setInitialUser(11);
- // set up for user switching after display on
- final int currentUserId = 10;
- final int newUserId = 11;
- when(mCarUserManagerHelper.getInitialUser()).thenReturn(newUserId);
- when(ActivityManager.getCurrentUser()).thenReturn(currentUserId);
+ suspendAndResumeForUserSwitchingTests();
- mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, 0));
- assertTrue(mDisplayInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS));
+ verifyUserSwitched(11);
+ }
+
+ private void suspendAndResumeForUserSwitchingTests() throws Exception {
+ Log.d(TAG, "suspend()");
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.SHUTDOWN_PREPARE,
VehicleApPowerStateShutdownParam.CAN_SLEEP));
- assertFalse(mDisplayInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS));
+ assertThat(mDisplayInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS)).isFalse();
assertStateReceivedForShutdownOrSleepWithPostpone(
- PowerHalService.SET_DEEP_SLEEP_ENTRY, WAIT_TIMEOUT_LONG_MS, wakeupTime);
+ PowerHalService.SET_DEEP_SLEEP_ENTRY, WAIT_TIMEOUT_LONG_MS, mWakeupTime);
mPowerSignalListener.waitForSleepEntry(WAIT_TIMEOUT_MS);
+
// Send the finished signal
+ Log.d(TAG, "resume()");
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.FINISHED, 0));
mSystemStateInterface.setWakeupCausedByTimer(true);
mSystemStateInterface.waitForSleepEntryAndWakeup(WAIT_TIMEOUT_MS);
assertStateReceived(PowerHalService.SET_DEEP_SLEEP_EXIT, 0);
mPowerSignalListener.waitForSleepExit(WAIT_TIMEOUT_MS);
- mService.scheduleNextWakeupTime(wakeupTime);
+ mService.scheduleNextWakeupTime(mWakeupTime);
// second processing after wakeup
- assertFalse(mDisplayInterface.getDisplayState());
- // do not skip user switching part.
- mService.clearIsBootingOrResuming();
+ assertThat(mDisplayInterface.getDisplayState()).isFalse();
+
+ mService.setStateForTesting(/* isBooting= */ false, /* isResuming= */ true);
+
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, 0));
- assertTrue(mDisplayInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS));
- // user switching should have been requested.
- verify(mCarUserManagerHelper, times(1)).switchToUserId(newUserId);
+ assertThat(mDisplayInterface.waitForDisplayStateChange(WAIT_TIMEOUT_MS)).isTrue();
+ // Should wait until Handler has finished ON processing.
+ CarServiceUtils.runOnLooperSync(mService.getHandlerThread().getLooper(), () -> { });
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.SHUTDOWN_PREPARE,
VehicleApPowerStateShutdownParam.CAN_SLEEP));
assertStateReceivedForShutdownOrSleepWithPostpone(
- PowerHalService.SET_DEEP_SLEEP_ENTRY, WAIT_TIMEOUT_LONG_MS, wakeupTime);
+ PowerHalService.SET_DEEP_SLEEP_ENTRY, WAIT_TIMEOUT_LONG_MS, mWakeupTime);
mPowerSignalListener.waitForSleepEntry(WAIT_TIMEOUT_MS);
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.FINISHED, 0));
- // PM will shutdown system as it was not woken-up due to timer and it is not power on.
+ // PM will shutdown system as it was not woken-up due timer and it is not power on.
mSystemStateInterface.setWakeupCausedByTimer(false);
mSystemStateInterface.waitForSleepEntryAndWakeup(WAIT_TIMEOUT_MS);
// Since we just woke up from shutdown, wake up time will be 0
assertStateReceived(PowerHalService.SET_DEEP_SLEEP_EXIT, 0);
- assertFalse(mDisplayInterface.getDisplayState());
+ assertThat(mDisplayInterface.getDisplayState()).isFalse();
}
private void registerListenerToService() {
@@ -265,8 +338,8 @@
private void assertStateReceived(int expectedState, int expectedParam) throws Exception {
int[] state = mPowerHal.waitForSend(WAIT_TIMEOUT_MS);
- assertEquals(expectedState, state[0]);
- assertEquals(expectedParam, state[1]);
+ assertThat(state[0]).isEqualTo(expectedState);
+ assertThat(state[1]).isEqualTo(expectedParam);
}
private void assertStateReceivedForShutdownOrSleepWithPostpone(
@@ -280,7 +353,7 @@
continue;
}
if (state[0] == lastState) {
- assertEquals(expectedParamForShutdownOrSuspend, state[1]);
+ assertThat(state[1]).isEqualTo(expectedParamForShutdownOrSuspend);
return;
}
}
@@ -293,6 +366,30 @@
}
}
+ private void setInitialUser(int userId) {
+ when(mCarUserManagerHelper.getInitialUser()).thenReturn(userId);
+ }
+
+ private void setCurrentUser(int userId) {
+ when(ActivityManager.getCurrentUser()).thenReturn(userId);
+ }
+
+ private void setUserInfo(int userId, int flags) {
+ setUserInfo(userId, /* name= */ null, flags);
+ }
+
+ private void setUserInfo(int userId, @Nullable String name, int flags) {
+ final UserInfo userInfo = new UserInfo();
+ userInfo.id = userId;
+ userInfo.name = name;
+ userInfo.flags = flags;
+ when(mUserManager.getUserInfo(userId)).thenReturn(userInfo);
+ }
+
+ private void verifyUserSwitched(int userId) {
+ verify(mCarUserManagerHelper, times(1)).switchToUserId(userId);
+ }
+
private static final class MockDisplayInterface implements DisplayInterface {
private boolean mDisplayOn = true;
private final Semaphore mDisplayStateWait = new Semaphore(0);
@@ -446,4 +543,10 @@
}
}
}
+
+ @Retention(RUNTIME)
+ @Target({METHOD})
+ public static @interface WakeupTime {
+ int value();
+ }
}
diff --git a/tools/emulator/VehicleHalProto_pb2.py b/tools/emulator/VehicleHalProto_pb2.py
index 3278ed7..6e964f6 100644
--- a/tools/emulator/VehicleHalProto_pb2.py
+++ b/tools/emulator/VehicleHalProto_pb2.py
@@ -1,153 +1,164 @@
+# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: VehicleHalProto.proto
+import sys
+_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
from google.protobuf.internal import enum_type_wrapper
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from google.protobuf import reflection as _reflection
-from google.protobuf import descriptor_pb2
+from google.protobuf import symbol_database as _symbol_database
# @@protoc_insertion_point(imports)
+_sym_db = _symbol_database.Default()
+
DESCRIPTOR = _descriptor.FileDescriptor(
name='VehicleHalProto.proto',
- package='emulator',
- serialized_pb='\n\x15VehicleHalProto.proto\x12\x08\x65mulator\"\xba\x01\n\x11VehicleAreaConfig\x12\x0f\n\x07\x61rea_id\x18\x01 \x02(\x05\x12\x17\n\x0fmin_int32_value\x18\x02 \x01(\x11\x12\x17\n\x0fmax_int32_value\x18\x03 \x01(\x11\x12\x17\n\x0fmin_int64_value\x18\x04 \x01(\x12\x12\x17\n\x0fmax_int64_value\x18\x05 \x01(\x12\x12\x17\n\x0fmin_float_value\x18\x06 \x01(\x02\x12\x17\n\x0fmax_float_value\x18\x07 \x01(\x02\"\x9b\x02\n\x11VehiclePropConfig\x12\x0c\n\x04prop\x18\x01 \x02(\x05\x12\x0e\n\x06\x61\x63\x63\x65ss\x18\x02 \x01(\x05\x12\x13\n\x0b\x63hange_mode\x18\x03 \x01(\x05\x12\x12\n\nvalue_type\x18\x04 \x01(\x05\x12\x17\n\x0fsupported_areas\x18\x05 \x01(\x05\x12\x31\n\x0c\x61rea_configs\x18\x06 \x03(\x0b\x32\x1b.emulator.VehicleAreaConfig\x12\x14\n\x0c\x63onfig_flags\x18\x07 \x01(\x05\x12\x14\n\x0c\x63onfig_array\x18\x08 \x03(\x05\x12\x15\n\rconfig_string\x18\t \x01(\t\x12\x17\n\x0fmin_sample_rate\x18\n \x01(\x02\x12\x17\n\x0fmax_sample_rate\x18\x0b \x01(\x02\"\xf2\x01\n\x10VehiclePropValue\x12\x0c\n\x04prop\x18\x01 \x02(\x05\x12\x12\n\nvalue_type\x18\x02 \x01(\x05\x12\x11\n\ttimestamp\x18\x03 \x01(\x03\x12+\n\x06status\x18\n \x01(\x0e\x32\x1b.emulator.VehiclePropStatus\x12\x0f\n\x07\x61rea_id\x18\x04 \x01(\x05\x12\x14\n\x0cint32_values\x18\x05 \x03(\x11\x12\x14\n\x0cint64_values\x18\x06 \x03(\x12\x12\x14\n\x0c\x66loat_values\x18\x07 \x03(\x02\x12\x14\n\x0cstring_value\x18\x08 \x01(\t\x12\x13\n\x0b\x62ytes_value\x18\t \x01(\x0c\"/\n\x0eVehiclePropGet\x12\x0c\n\x04prop\x18\x01 \x02(\x05\x12\x0f\n\x07\x61rea_id\x18\x02 \x01(\x05\"\xd8\x01\n\x0f\x45mulatorMessage\x12#\n\x08msg_type\x18\x01 \x02(\x0e\x32\x11.emulator.MsgType\x12 \n\x06status\x18\x02 \x01(\x0e\x32\x10.emulator.Status\x12&\n\x04prop\x18\x03 \x03(\x0b\x32\x18.emulator.VehiclePropGet\x12+\n\x06\x63onfig\x18\x04 \x03(\x0b\x32\x1b.emulator.VehiclePropConfig\x12)\n\x05value\x18\x05 \x03(\x0b\x32\x1a.emulator.VehiclePropValue*\x8a\x02\n\x07MsgType\x12\x12\n\x0eGET_CONFIG_CMD\x10\x00\x12\x13\n\x0fGET_CONFIG_RESP\x10\x01\x12\x16\n\x12GET_CONFIG_ALL_CMD\x10\x02\x12\x17\n\x13GET_CONFIG_ALL_RESP\x10\x03\x12\x14\n\x10GET_PROPERTY_CMD\x10\x04\x12\x15\n\x11GET_PROPERTY_RESP\x10\x05\x12\x18\n\x14GET_PROPERTY_ALL_CMD\x10\x06\x12\x19\n\x15GET_PROPERTY_ALL_RESP\x10\x07\x12\x14\n\x10SET_PROPERTY_CMD\x10\x08\x12\x15\n\x11SET_PROPERTY_RESP\x10\t\x12\x16\n\x12SET_PROPERTY_ASYNC\x10\n*\xfb\x01\n\x06Status\x12\r\n\tRESULT_OK\x10\x00\x12\x11\n\rERROR_UNKNOWN\x10\x01\x12\x1b\n\x17\x45RROR_UNIMPLEMENTED_CMD\x10\x02\x12\x1a\n\x16\x45RROR_INVALID_PROPERTY\x10\x03\x12\x19\n\x15\x45RROR_INVALID_AREA_ID\x10\x04\x12 \n\x1c\x45RROR_PROPERTY_UNINITIALIZED\x10\x05\x12\x1d\n\x19\x45RROR_WRITE_ONLY_PROPERTY\x10\x06\x12\x1d\n\x19\x45RROR_MEMORY_ALLOC_FAILED\x10\x07\x12\x1b\n\x17\x45RROR_INVALID_OPERATION\x10\x08*>\n\x11VehiclePropStatus\x12\r\n\tAVAILABLE\x10\x00\x12\x0f\n\x0bUNAVAILABLE\x10\x01\x12\t\n\x05\x45RROR\x10\x02\x42\x02H\x03')
+ package='vhal_proto',
+ syntax='proto2',
+ serialized_options=None,
+ serialized_pb=_b('\n\x15VehicleHalProto.proto\x12\nvhal_proto\"\xba\x01\n\x11VehicleAreaConfig\x12\x0f\n\x07\x61rea_id\x18\x01 \x02(\x05\x12\x17\n\x0fmin_int32_value\x18\x02 \x01(\x11\x12\x17\n\x0fmax_int32_value\x18\x03 \x01(\x11\x12\x17\n\x0fmin_int64_value\x18\x04 \x01(\x12\x12\x17\n\x0fmax_int64_value\x18\x05 \x01(\x12\x12\x17\n\x0fmin_float_value\x18\x06 \x01(\x02\x12\x17\n\x0fmax_float_value\x18\x07 \x01(\x02\"\x9d\x02\n\x11VehiclePropConfig\x12\x0c\n\x04prop\x18\x01 \x02(\x05\x12\x0e\n\x06\x61\x63\x63\x65ss\x18\x02 \x01(\x05\x12\x13\n\x0b\x63hange_mode\x18\x03 \x01(\x05\x12\x12\n\nvalue_type\x18\x04 \x01(\x05\x12\x17\n\x0fsupported_areas\x18\x05 \x01(\x05\x12\x33\n\x0c\x61rea_configs\x18\x06 \x03(\x0b\x32\x1d.vhal_proto.VehicleAreaConfig\x12\x14\n\x0c\x63onfig_flags\x18\x07 \x01(\x05\x12\x14\n\x0c\x63onfig_array\x18\x08 \x03(\x05\x12\x15\n\rconfig_string\x18\t \x01(\t\x12\x17\n\x0fmin_sample_rate\x18\n \x01(\x02\x12\x17\n\x0fmax_sample_rate\x18\x0b \x01(\x02\"\xf4\x01\n\x10VehiclePropValue\x12\x0c\n\x04prop\x18\x01 \x02(\x05\x12\x12\n\nvalue_type\x18\x02 \x01(\x05\x12\x11\n\ttimestamp\x18\x03 \x01(\x03\x12-\n\x06status\x18\n \x01(\x0e\x32\x1d.vhal_proto.VehiclePropStatus\x12\x0f\n\x07\x61rea_id\x18\x04 \x01(\x05\x12\x14\n\x0cint32_values\x18\x05 \x03(\x11\x12\x14\n\x0cint64_values\x18\x06 \x03(\x12\x12\x14\n\x0c\x66loat_values\x18\x07 \x03(\x02\x12\x14\n\x0cstring_value\x18\x08 \x01(\t\x12\x13\n\x0b\x62ytes_value\x18\t \x01(\x0c\"/\n\x0eVehiclePropGet\x12\x0c\n\x04prop\x18\x01 \x02(\x05\x12\x0f\n\x07\x61rea_id\x18\x02 \x01(\x05\"\xe2\x01\n\x0f\x45mulatorMessage\x12%\n\x08msg_type\x18\x01 \x02(\x0e\x32\x13.vhal_proto.MsgType\x12\"\n\x06status\x18\x02 \x01(\x0e\x32\x12.vhal_proto.Status\x12(\n\x04prop\x18\x03 \x03(\x0b\x32\x1a.vhal_proto.VehiclePropGet\x12-\n\x06\x63onfig\x18\x04 \x03(\x0b\x32\x1d.vhal_proto.VehiclePropConfig\x12+\n\x05value\x18\x05 \x03(\x0b\x32\x1c.vhal_proto.VehiclePropValue*\x8a\x02\n\x07MsgType\x12\x12\n\x0eGET_CONFIG_CMD\x10\x00\x12\x13\n\x0fGET_CONFIG_RESP\x10\x01\x12\x16\n\x12GET_CONFIG_ALL_CMD\x10\x02\x12\x17\n\x13GET_CONFIG_ALL_RESP\x10\x03\x12\x14\n\x10GET_PROPERTY_CMD\x10\x04\x12\x15\n\x11GET_PROPERTY_RESP\x10\x05\x12\x18\n\x14GET_PROPERTY_ALL_CMD\x10\x06\x12\x19\n\x15GET_PROPERTY_ALL_RESP\x10\x07\x12\x14\n\x10SET_PROPERTY_CMD\x10\x08\x12\x15\n\x11SET_PROPERTY_RESP\x10\t\x12\x16\n\x12SET_PROPERTY_ASYNC\x10\n*\xfb\x01\n\x06Status\x12\r\n\tRESULT_OK\x10\x00\x12\x11\n\rERROR_UNKNOWN\x10\x01\x12\x1b\n\x17\x45RROR_UNIMPLEMENTED_CMD\x10\x02\x12\x1a\n\x16\x45RROR_INVALID_PROPERTY\x10\x03\x12\x19\n\x15\x45RROR_INVALID_AREA_ID\x10\x04\x12 \n\x1c\x45RROR_PROPERTY_UNINITIALIZED\x10\x05\x12\x1d\n\x19\x45RROR_WRITE_ONLY_PROPERTY\x10\x06\x12\x1d\n\x19\x45RROR_MEMORY_ALLOC_FAILED\x10\x07\x12\x1b\n\x17\x45RROR_INVALID_OPERATION\x10\x08*>\n\x11VehiclePropStatus\x12\r\n\tAVAILABLE\x10\x00\x12\x0f\n\x0bUNAVAILABLE\x10\x01\x12\t\n\x05\x45RROR\x10\x02')
+)
_MSGTYPE = _descriptor.EnumDescriptor(
name='MsgType',
- full_name='emulator.MsgType',
+ full_name='vhal_proto.MsgType',
filename=None,
file=DESCRIPTOR,
values=[
_descriptor.EnumValueDescriptor(
name='GET_CONFIG_CMD', index=0, number=0,
- options=None,
+ serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='GET_CONFIG_RESP', index=1, number=1,
- options=None,
+ serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='GET_CONFIG_ALL_CMD', index=2, number=2,
- options=None,
+ serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='GET_CONFIG_ALL_RESP', index=3, number=3,
- options=None,
+ serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='GET_PROPERTY_CMD', index=4, number=4,
- options=None,
+ serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='GET_PROPERTY_RESP', index=5, number=5,
- options=None,
+ serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='GET_PROPERTY_ALL_CMD', index=6, number=6,
- options=None,
+ serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='GET_PROPERTY_ALL_RESP', index=7, number=7,
- options=None,
+ serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='SET_PROPERTY_CMD', index=8, number=8,
- options=None,
+ serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='SET_PROPERTY_RESP', index=9, number=9,
- options=None,
+ serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='SET_PROPERTY_ASYNC', index=10, number=10,
- options=None,
+ serialized_options=None,
type=None),
],
containing_type=None,
- options=None,
- serialized_start=1024,
- serialized_end=1290,
+ serialized_options=None,
+ serialized_start=1040,
+ serialized_end=1306,
)
+_sym_db.RegisterEnumDescriptor(_MSGTYPE)
MsgType = enum_type_wrapper.EnumTypeWrapper(_MSGTYPE)
_STATUS = _descriptor.EnumDescriptor(
name='Status',
- full_name='emulator.Status',
+ full_name='vhal_proto.Status',
filename=None,
file=DESCRIPTOR,
values=[
_descriptor.EnumValueDescriptor(
name='RESULT_OK', index=0, number=0,
- options=None,
+ serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='ERROR_UNKNOWN', index=1, number=1,
- options=None,
+ serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='ERROR_UNIMPLEMENTED_CMD', index=2, number=2,
- options=None,
+ serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='ERROR_INVALID_PROPERTY', index=3, number=3,
- options=None,
+ serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='ERROR_INVALID_AREA_ID', index=4, number=4,
- options=None,
+ serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='ERROR_PROPERTY_UNINITIALIZED', index=5, number=5,
- options=None,
+ serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='ERROR_WRITE_ONLY_PROPERTY', index=6, number=6,
- options=None,
+ serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='ERROR_MEMORY_ALLOC_FAILED', index=7, number=7,
- options=None,
+ serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='ERROR_INVALID_OPERATION', index=8, number=8,
- options=None,
+ serialized_options=None,
type=None),
],
containing_type=None,
- options=None,
- serialized_start=1293,
- serialized_end=1544,
+ serialized_options=None,
+ serialized_start=1309,
+ serialized_end=1560,
)
+_sym_db.RegisterEnumDescriptor(_STATUS)
Status = enum_type_wrapper.EnumTypeWrapper(_STATUS)
_VEHICLEPROPSTATUS = _descriptor.EnumDescriptor(
name='VehiclePropStatus',
- full_name='emulator.VehiclePropStatus',
+ full_name='vhal_proto.VehiclePropStatus',
filename=None,
file=DESCRIPTOR,
values=[
_descriptor.EnumValueDescriptor(
name='AVAILABLE', index=0, number=0,
- options=None,
+ serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='UNAVAILABLE', index=1, number=1,
- options=None,
+ serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='ERROR', index=2, number=2,
- options=None,
+ serialized_options=None,
type=None),
],
containing_type=None,
- options=None,
- serialized_start=1546,
- serialized_end=1608,
+ serialized_options=None,
+ serialized_start=1562,
+ serialized_end=1624,
)
+_sym_db.RegisterEnumDescriptor(_VEHICLEPROPSTATUS)
VehiclePropStatus = enum_type_wrapper.EnumTypeWrapper(_VEHICLEPROPSTATUS)
GET_CONFIG_CMD = 0
@@ -178,351 +189,366 @@
_VEHICLEAREACONFIG = _descriptor.Descriptor(
name='VehicleAreaConfig',
- full_name='emulator.VehicleAreaConfig',
+ full_name='vhal_proto.VehicleAreaConfig',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
- name='area_id', full_name='emulator.VehicleAreaConfig.area_id', index=0,
+ name='area_id', full_name='vhal_proto.VehicleAreaConfig.area_id', index=0,
number=1, type=5, cpp_type=1, label=2,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
- name='min_int32_value', full_name='emulator.VehicleAreaConfig.min_int32_value', index=1,
+ name='min_int32_value', full_name='vhal_proto.VehicleAreaConfig.min_int32_value', index=1,
number=2, type=17, cpp_type=1, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
- name='max_int32_value', full_name='emulator.VehicleAreaConfig.max_int32_value', index=2,
+ name='max_int32_value', full_name='vhal_proto.VehicleAreaConfig.max_int32_value', index=2,
number=3, type=17, cpp_type=1, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
- name='min_int64_value', full_name='emulator.VehicleAreaConfig.min_int64_value', index=3,
+ name='min_int64_value', full_name='vhal_proto.VehicleAreaConfig.min_int64_value', index=3,
number=4, type=18, cpp_type=2, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
- name='max_int64_value', full_name='emulator.VehicleAreaConfig.max_int64_value', index=4,
+ name='max_int64_value', full_name='vhal_proto.VehicleAreaConfig.max_int64_value', index=4,
number=5, type=18, cpp_type=2, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
- name='min_float_value', full_name='emulator.VehicleAreaConfig.min_float_value', index=5,
+ name='min_float_value', full_name='vhal_proto.VehicleAreaConfig.min_float_value', index=5,
number=6, type=2, cpp_type=6, label=1,
- has_default_value=False, default_value=0,
+ has_default_value=False, default_value=float(0),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
- name='max_float_value', full_name='emulator.VehicleAreaConfig.max_float_value', index=6,
+ name='max_float_value', full_name='vhal_proto.VehicleAreaConfig.max_float_value', index=6,
number=7, type=2, cpp_type=6, label=1,
- has_default_value=False, default_value=0,
+ has_default_value=False, default_value=float(0),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
- options=None,
+ serialized_options=None,
is_extendable=False,
+ syntax='proto2',
extension_ranges=[],
- serialized_start=36,
- serialized_end=222,
+ oneofs=[
+ ],
+ serialized_start=38,
+ serialized_end=224,
)
_VEHICLEPROPCONFIG = _descriptor.Descriptor(
name='VehiclePropConfig',
- full_name='emulator.VehiclePropConfig',
+ full_name='vhal_proto.VehiclePropConfig',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
- name='prop', full_name='emulator.VehiclePropConfig.prop', index=0,
+ name='prop', full_name='vhal_proto.VehiclePropConfig.prop', index=0,
number=1, type=5, cpp_type=1, label=2,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
- name='access', full_name='emulator.VehiclePropConfig.access', index=1,
+ name='access', full_name='vhal_proto.VehiclePropConfig.access', index=1,
number=2, type=5, cpp_type=1, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
- name='change_mode', full_name='emulator.VehiclePropConfig.change_mode', index=2,
+ name='change_mode', full_name='vhal_proto.VehiclePropConfig.change_mode', index=2,
number=3, type=5, cpp_type=1, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
- name='value_type', full_name='emulator.VehiclePropConfig.value_type', index=3,
+ name='value_type', full_name='vhal_proto.VehiclePropConfig.value_type', index=3,
number=4, type=5, cpp_type=1, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
- name='supported_areas', full_name='emulator.VehiclePropConfig.supported_areas', index=4,
+ name='supported_areas', full_name='vhal_proto.VehiclePropConfig.supported_areas', index=4,
number=5, type=5, cpp_type=1, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
- name='area_configs', full_name='emulator.VehiclePropConfig.area_configs', index=5,
+ name='area_configs', full_name='vhal_proto.VehiclePropConfig.area_configs', index=5,
number=6, type=11, cpp_type=10, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
- name='config_flags', full_name='emulator.VehiclePropConfig.config_flags', index=6,
+ name='config_flags', full_name='vhal_proto.VehiclePropConfig.config_flags', index=6,
number=7, type=5, cpp_type=1, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
- name='config_array', full_name='emulator.VehiclePropConfig.config_array', index=7,
+ name='config_array', full_name='vhal_proto.VehiclePropConfig.config_array', index=7,
number=8, type=5, cpp_type=1, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
- name='config_string', full_name='emulator.VehiclePropConfig.config_string', index=8,
+ name='config_string', full_name='vhal_proto.VehiclePropConfig.config_string', index=8,
number=9, type=9, cpp_type=9, label=1,
- has_default_value=False, default_value=unicode("", "utf-8"),
+ has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
- name='min_sample_rate', full_name='emulator.VehiclePropConfig.min_sample_rate', index=9,
+ name='min_sample_rate', full_name='vhal_proto.VehiclePropConfig.min_sample_rate', index=9,
number=10, type=2, cpp_type=6, label=1,
- has_default_value=False, default_value=0,
+ has_default_value=False, default_value=float(0),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
- name='max_sample_rate', full_name='emulator.VehiclePropConfig.max_sample_rate', index=10,
+ name='max_sample_rate', full_name='vhal_proto.VehiclePropConfig.max_sample_rate', index=10,
number=11, type=2, cpp_type=6, label=1,
- has_default_value=False, default_value=0,
+ has_default_value=False, default_value=float(0),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
- options=None,
+ serialized_options=None,
is_extendable=False,
+ syntax='proto2',
extension_ranges=[],
- serialized_start=225,
- serialized_end=508,
+ oneofs=[
+ ],
+ serialized_start=227,
+ serialized_end=512,
)
_VEHICLEPROPVALUE = _descriptor.Descriptor(
name='VehiclePropValue',
- full_name='emulator.VehiclePropValue',
+ full_name='vhal_proto.VehiclePropValue',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
- name='prop', full_name='emulator.VehiclePropValue.prop', index=0,
+ name='prop', full_name='vhal_proto.VehiclePropValue.prop', index=0,
number=1, type=5, cpp_type=1, label=2,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
- name='value_type', full_name='emulator.VehiclePropValue.value_type', index=1,
+ name='value_type', full_name='vhal_proto.VehiclePropValue.value_type', index=1,
number=2, type=5, cpp_type=1, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
- name='timestamp', full_name='emulator.VehiclePropValue.timestamp', index=2,
+ name='timestamp', full_name='vhal_proto.VehiclePropValue.timestamp', index=2,
number=3, type=3, cpp_type=2, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
- name='status', full_name='emulator.VehiclePropValue.status', index=3,
+ name='status', full_name='vhal_proto.VehiclePropValue.status', index=3,
number=10, type=14, cpp_type=8, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
- name='area_id', full_name='emulator.VehiclePropValue.area_id', index=4,
+ name='area_id', full_name='vhal_proto.VehiclePropValue.area_id', index=4,
number=4, type=5, cpp_type=1, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
- name='int32_values', full_name='emulator.VehiclePropValue.int32_values', index=5,
+ name='int32_values', full_name='vhal_proto.VehiclePropValue.int32_values', index=5,
number=5, type=17, cpp_type=1, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
- name='int64_values', full_name='emulator.VehiclePropValue.int64_values', index=6,
+ name='int64_values', full_name='vhal_proto.VehiclePropValue.int64_values', index=6,
number=6, type=18, cpp_type=2, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
- name='float_values', full_name='emulator.VehiclePropValue.float_values', index=7,
+ name='float_values', full_name='vhal_proto.VehiclePropValue.float_values', index=7,
number=7, type=2, cpp_type=6, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
- name='string_value', full_name='emulator.VehiclePropValue.string_value', index=8,
+ name='string_value', full_name='vhal_proto.VehiclePropValue.string_value', index=8,
number=8, type=9, cpp_type=9, label=1,
- has_default_value=False, default_value=unicode("", "utf-8"),
+ has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
- name='bytes_value', full_name='emulator.VehiclePropValue.bytes_value', index=9,
+ name='bytes_value', full_name='vhal_proto.VehiclePropValue.bytes_value', index=9,
number=9, type=12, cpp_type=9, label=1,
- has_default_value=False, default_value="",
+ has_default_value=False, default_value=_b(""),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
- options=None,
+ serialized_options=None,
is_extendable=False,
+ syntax='proto2',
extension_ranges=[],
- serialized_start=511,
- serialized_end=753,
+ oneofs=[
+ ],
+ serialized_start=515,
+ serialized_end=759,
)
_VEHICLEPROPGET = _descriptor.Descriptor(
name='VehiclePropGet',
- full_name='emulator.VehiclePropGet',
+ full_name='vhal_proto.VehiclePropGet',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
- name='prop', full_name='emulator.VehiclePropGet.prop', index=0,
+ name='prop', full_name='vhal_proto.VehiclePropGet.prop', index=0,
number=1, type=5, cpp_type=1, label=2,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
- name='area_id', full_name='emulator.VehiclePropGet.area_id', index=1,
+ name='area_id', full_name='vhal_proto.VehiclePropGet.area_id', index=1,
number=2, type=5, cpp_type=1, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
- options=None,
+ serialized_options=None,
is_extendable=False,
+ syntax='proto2',
extension_ranges=[],
- serialized_start=755,
- serialized_end=802,
+ oneofs=[
+ ],
+ serialized_start=761,
+ serialized_end=808,
)
_EMULATORMESSAGE = _descriptor.Descriptor(
name='EmulatorMessage',
- full_name='emulator.EmulatorMessage',
+ full_name='vhal_proto.EmulatorMessage',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
- name='msg_type', full_name='emulator.EmulatorMessage.msg_type', index=0,
+ name='msg_type', full_name='vhal_proto.EmulatorMessage.msg_type', index=0,
number=1, type=14, cpp_type=8, label=2,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
- name='status', full_name='emulator.EmulatorMessage.status', index=1,
+ name='status', full_name='vhal_proto.EmulatorMessage.status', index=1,
number=2, type=14, cpp_type=8, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
- name='prop', full_name='emulator.EmulatorMessage.prop', index=2,
+ name='prop', full_name='vhal_proto.EmulatorMessage.prop', index=2,
number=3, type=11, cpp_type=10, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
- name='config', full_name='emulator.EmulatorMessage.config', index=3,
+ name='config', full_name='vhal_proto.EmulatorMessage.config', index=3,
number=4, type=11, cpp_type=10, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
- name='value', full_name='emulator.EmulatorMessage.value', index=4,
+ name='value', full_name='vhal_proto.EmulatorMessage.value', index=4,
number=5, type=11, cpp_type=10, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
- options=None,
+ serialized_options=None,
is_extendable=False,
+ syntax='proto2',
extension_ranges=[],
- serialized_start=805,
- serialized_end=1021,
+ oneofs=[
+ ],
+ serialized_start=811,
+ serialized_end=1037,
)
_VEHICLEPROPCONFIG.fields_by_name['area_configs'].message_type = _VEHICLEAREACONFIG
@@ -537,38 +563,45 @@
DESCRIPTOR.message_types_by_name['VehiclePropValue'] = _VEHICLEPROPVALUE
DESCRIPTOR.message_types_by_name['VehiclePropGet'] = _VEHICLEPROPGET
DESCRIPTOR.message_types_by_name['EmulatorMessage'] = _EMULATORMESSAGE
+DESCRIPTOR.enum_types_by_name['MsgType'] = _MSGTYPE
+DESCRIPTOR.enum_types_by_name['Status'] = _STATUS
+DESCRIPTOR.enum_types_by_name['VehiclePropStatus'] = _VEHICLEPROPSTATUS
+_sym_db.RegisterFileDescriptor(DESCRIPTOR)
-class VehicleAreaConfig(_message.Message):
- __metaclass__ = _reflection.GeneratedProtocolMessageType
- DESCRIPTOR = _VEHICLEAREACONFIG
+VehicleAreaConfig = _reflection.GeneratedProtocolMessageType('VehicleAreaConfig', (_message.Message,), {
+ 'DESCRIPTOR' : _VEHICLEAREACONFIG,
+ '__module__' : 'VehicleHalProto_pb2'
+ # @@protoc_insertion_point(class_scope:vhal_proto.VehicleAreaConfig)
+ })
+_sym_db.RegisterMessage(VehicleAreaConfig)
- # @@protoc_insertion_point(class_scope:emulator.VehicleAreaConfig)
+VehiclePropConfig = _reflection.GeneratedProtocolMessageType('VehiclePropConfig', (_message.Message,), {
+ 'DESCRIPTOR' : _VEHICLEPROPCONFIG,
+ '__module__' : 'VehicleHalProto_pb2'
+ # @@protoc_insertion_point(class_scope:vhal_proto.VehiclePropConfig)
+ })
+_sym_db.RegisterMessage(VehiclePropConfig)
-class VehiclePropConfig(_message.Message):
- __metaclass__ = _reflection.GeneratedProtocolMessageType
- DESCRIPTOR = _VEHICLEPROPCONFIG
+VehiclePropValue = _reflection.GeneratedProtocolMessageType('VehiclePropValue', (_message.Message,), {
+ 'DESCRIPTOR' : _VEHICLEPROPVALUE,
+ '__module__' : 'VehicleHalProto_pb2'
+ # @@protoc_insertion_point(class_scope:vhal_proto.VehiclePropValue)
+ })
+_sym_db.RegisterMessage(VehiclePropValue)
- # @@protoc_insertion_point(class_scope:emulator.VehiclePropConfig)
+VehiclePropGet = _reflection.GeneratedProtocolMessageType('VehiclePropGet', (_message.Message,), {
+ 'DESCRIPTOR' : _VEHICLEPROPGET,
+ '__module__' : 'VehicleHalProto_pb2'
+ # @@protoc_insertion_point(class_scope:vhal_proto.VehiclePropGet)
+ })
+_sym_db.RegisterMessage(VehiclePropGet)
-class VehiclePropValue(_message.Message):
- __metaclass__ = _reflection.GeneratedProtocolMessageType
- DESCRIPTOR = _VEHICLEPROPVALUE
-
- # @@protoc_insertion_point(class_scope:emulator.VehiclePropValue)
-
-class VehiclePropGet(_message.Message):
- __metaclass__ = _reflection.GeneratedProtocolMessageType
- DESCRIPTOR = _VEHICLEPROPGET
-
- # @@protoc_insertion_point(class_scope:emulator.VehiclePropGet)
-
-class EmulatorMessage(_message.Message):
- __metaclass__ = _reflection.GeneratedProtocolMessageType
- DESCRIPTOR = _EMULATORMESSAGE
-
- # @@protoc_insertion_point(class_scope:emulator.EmulatorMessage)
+EmulatorMessage = _reflection.GeneratedProtocolMessageType('EmulatorMessage', (_message.Message,), {
+ 'DESCRIPTOR' : _EMULATORMESSAGE,
+ '__module__' : 'VehicleHalProto_pb2'
+ # @@protoc_insertion_point(class_scope:vhal_proto.EmulatorMessage)
+ })
+_sym_db.RegisterMessage(EmulatorMessage)
-DESCRIPTOR.has_options = True
-DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), 'H\003')
# @@protoc_insertion_point(module_scope)